Refactoring

This commit is contained in:
Ali 2022-05-20 06:53:13 +03:00
parent 54788f60de
commit 85a0b3b4d0
31 changed files with 548 additions and 265 deletions

View File

@ -2,6 +2,7 @@ import Foundation
import UIKit import UIKit
import Postbox import Postbox
import Display import Display
import TelegramCore
public protocol ChatListController: ViewController { public protocol ChatListController: ViewController {
var context: AccountContext { get } var context: AccountContext { get }
@ -11,5 +12,5 @@ public protocol ChatListController: ViewController {
func activateSearch(filter: ChatListSearchFilter, query: String?) func activateSearch(filter: ChatListSearchFilter, query: String?)
func deactivateSearch(animated: Bool) func deactivateSearch(animated: Bool)
func activateCompose() func activateCompose()
func maybeAskForPeerChatRemoval(peer: RenderedPeer, joined: Bool, deleteGloballyIfPossible: Bool, completion: @escaping (Bool) -> Void, removed: @escaping () -> Void) func maybeAskForPeerChatRemoval(peer: EngineRenderedPeer, joined: Bool, deleteGloballyIfPossible: Bool, completion: @escaping (Bool) -> Void, removed: @escaping () -> Void)
} }

View File

@ -1428,7 +1428,7 @@ public final class CalendarMessageScreen: ViewController {
struct ClearInfo { struct ClearInfo {
var canClearForMyself: ClearType? var canClearForMyself: ClearType?
var canClearForEveryone: ClearType? var canClearForEveryone: ClearType?
var mainPeer: Peer var mainPeer: EnginePeer
} }
let peerId = self.peerId let peerId = self.peerId
@ -1436,8 +1436,10 @@ public final class CalendarMessageScreen: ViewController {
} else { } else {
return return
} }
let _ = (self.context.account.postbox.transaction { transaction -> ClearInfo? in
guard let chatPeer = transaction.getPeer(peerId) else { let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|> map { chatPeer -> ClearInfo? in
guard let chatPeer = chatPeer else {
return nil return nil
} }
@ -1447,10 +1449,10 @@ public final class CalendarMessageScreen: ViewController {
if peerId == self.context.account.peerId { if peerId == self.context.account.peerId {
canClearForMyself = .savedMessages canClearForMyself = .savedMessages
canClearForEveryone = nil canClearForEveryone = nil
} else if chatPeer is TelegramSecretChat { } else if case .secretChat = chatPeer {
canClearForMyself = .secretChat canClearForMyself = .secretChat
canClearForEveryone = nil canClearForEveryone = nil
} else if let group = chatPeer as? TelegramGroup { } else if case let .legacyGroup(group) = chatPeer {
switch group.role { switch group.role {
case .creator: case .creator:
canClearForMyself = .group canClearForMyself = .group
@ -1459,7 +1461,7 @@ public final class CalendarMessageScreen: ViewController {
canClearForMyself = .group canClearForMyself = .group
canClearForEveryone = nil canClearForEveryone = nil
} }
} else if let channel = chatPeer as? TelegramChannel { } else if case let .channel(channel) = chatPeer {
if channel.hasPermission(.deleteAllMessages) { if channel.hasPermission(.deleteAllMessages) {
if case .group = channel.info { if case .group = channel.info {
canClearForEveryone = .group canClearForEveryone = .group
@ -1473,7 +1475,7 @@ public final class CalendarMessageScreen: ViewController {
} else { } else {
canClearForMyself = .user canClearForMyself = .user
if let user = chatPeer as? TelegramUser, user.botInfo != nil { if case let .user(user) = chatPeer, user.botInfo != nil {
canClearForEveryone = nil canClearForEveryone = nil
} else { } else {
canClearForEveryone = .user canClearForEveryone = .user
@ -1511,7 +1513,7 @@ public final class CalendarMessageScreen: ViewController {
let confirmationText: String let confirmationText: String
switch canClearForEveryone { switch canClearForEveryone {
case .user: case .user:
text = strongSelf.presentationData.strings.ChatList_DeleteForEveryone(EnginePeer(info.mainPeer).compactDisplayTitle).string text = strongSelf.presentationData.strings.ChatList_DeleteForEveryone(info.mainPeer.compactDisplayTitle).string
confirmationText = strongSelf.presentationData.strings.ChatList_DeleteForEveryoneConfirmationText confirmationText = strongSelf.presentationData.strings.ChatList_DeleteForEveryoneConfirmationText
default: default:
text = strongSelf.presentationData.strings.Conversation_DeleteMessagesForEveryone text = strongSelf.presentationData.strings.Conversation_DeleteMessagesForEveryone

View File

@ -973,7 +973,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
self.chatListDisplayNode.requestOpenMessageFromSearch = { [weak self] peer, messageId, deactivateOnAction in self.chatListDisplayNode.requestOpenMessageFromSearch = { [weak self] peer, messageId, deactivateOnAction in
if let strongSelf = self { if let strongSelf = self {
strongSelf.openMessageFromSearchDisposable.set((storedMessageFromSearchPeer(account: strongSelf.context.account, peer: peer._asPeer()) strongSelf.openMessageFromSearchDisposable.set((strongSelf.context.engine.peers.ensurePeerIsLocallyAvailable(peer: peer)
|> deliverOnMainQueue).start(next: { [weak strongSelf] actualPeerId in |> deliverOnMainQueue).start(next: { [weak strongSelf] actualPeerId in
if let strongSelf = strongSelf { if let strongSelf = strongSelf {
if let navigationController = strongSelf.navigationController as? NavigationController { if let navigationController = strongSelf.navigationController as? NavigationController {
@ -995,13 +995,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
self.chatListDisplayNode.requestOpenPeerFromSearch = { [weak self] peer, dismissSearch in self.chatListDisplayNode.requestOpenPeerFromSearch = { [weak self] peer, dismissSearch in
if let strongSelf = self { if let strongSelf = self {
let storedPeer = strongSelf.context.account.postbox.transaction { transaction -> Void in let storedPeer = strongSelf.context.engine.peers.ensurePeerIsLocallyAvailable(peer: peer) |> map { _ -> Void in return Void() }
if transaction.getPeer(peer.id) == nil {
updatePeers(transaction: transaction, peers: [peer._asPeer()], update: { previousPeer, updatedPeer in
return updatedPeer
})
}
}
strongSelf.openMessageFromSearchDisposable.set((storedPeer |> deliverOnMainQueue).start(completed: { [weak strongSelf] in strongSelf.openMessageFromSearchDisposable.set((storedPeer |> deliverOnMainQueue).start(completed: { [weak strongSelf] in
if let strongSelf = strongSelf { if let strongSelf = strongSelf {
if dismissSearch { if dismissSearch {
@ -1528,27 +1522,27 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
self.didSuggestLocalization = true self.didSuggestLocalization = true
let context = self.context let context = self.context
let signal = combineLatest(self.context.sharedContext.accountManager.transaction { transaction -> String in
let languageCode: String let suggestedLocalization = self.context.engine.data.get(TelegramEngine.EngineData.Item.Configuration.SuggestedLocalization())
if let current = transaction.getSharedData(SharedDataKeys.localizationSettings)?.get(LocalizationSettings.self) {
let code = current.primaryComponent.languageCode let signal = combineLatest(
let rawSuffix = "-raw" self.context.sharedContext.accountManager.transaction { transaction -> String in
if code.hasSuffix(rawSuffix) { let languageCode: String
languageCode = String(code.dropLast(rawSuffix.count)) if let current = transaction.getSharedData(SharedDataKeys.localizationSettings)?.get(LocalizationSettings.self) {
let code = current.primaryComponent.languageCode
let rawSuffix = "-raw"
if code.hasSuffix(rawSuffix) {
languageCode = String(code.dropLast(rawSuffix.count))
} else {
languageCode = code
}
} else { } else {
languageCode = code languageCode = "en"
} }
} else { return languageCode
languageCode = "en" },
} suggestedLocalization
return languageCode )
}, self.context.account.postbox.transaction { transaction -> SuggestedLocalizationEntry? in
var suggestedLocalization: SuggestedLocalizationEntry?
if let localization = transaction.getPreferencesEntry(key: PreferencesKeys.suggestedLocalization)?.get(SuggestedLocalizationEntry.self) {
suggestedLocalization = localization
}
return suggestedLocalization
})
|> mapToSignal({ value -> Signal<(String, SuggestedLocalizationInfo)?, NoError> in |> mapToSignal({ value -> Signal<(String, SuggestedLocalizationInfo)?, NoError> in
guard let suggestedLocalization = value.1, !suggestedLocalization.isSeen && suggestedLocalization.languageCode != "en" && suggestedLocalization.languageCode != value.0 else { guard let suggestedLocalization = value.1, !suggestedLocalization.isSeen && suggestedLocalization.languageCode != "en" && suggestedLocalization.languageCode != value.0 else {
return .single(nil) return .single(nil)
@ -1604,14 +1598,13 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
})) }))
Queue.mainQueue().after(1.0, { Queue.mainQueue().after(1.0, {
let _ = (self.context.account.postbox.transaction { transaction -> Int32? in let _ = (
if let value = transaction.getNoticeEntry(key: ApplicationSpecificNotice.forcedPasswordSetupKey())?.get(ApplicationSpecificCounterNotice.self) { self.context.engine.data.get(TelegramEngine.EngineData.Item.Notices.Notice(key: ApplicationSpecificNotice.forcedPasswordSetupKey()))
return value.value |> map { entry -> Int32? in
} else { return entry?.get(ApplicationSpecificCounterNotice.self)?.value
return nil
} }
} |> deliverOnMainQueue
|> deliverOnMainQueue).start(next: { [weak self] value in ).start(next: { [weak self] value in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
@ -2534,20 +2527,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
} }
func deletePeerChat(peerId: PeerId, joined: Bool) { func deletePeerChat(peerId: PeerId, joined: Bool) {
let _ = (self.context.account.postbox.transaction { transaction -> RenderedPeer? in let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.RenderedPeer(id: peerId))
guard let peer = transaction.getPeer(peerId) else {
return nil
}
if let associatedPeerId = peer.associatedPeerId {
if let associatedPeer = transaction.getPeer(associatedPeerId) {
return RenderedPeer(peerId: peerId, peers: SimpleDictionary([peer.id: peer, associatedPeer.id: associatedPeer]))
} else {
return nil
}
} else {
return RenderedPeer(peer: peer)
}
}
|> deliverOnMainQueue).start(next: { [weak self] peer in |> deliverOnMainQueue).start(next: { [weak self] peer in
guard let strongSelf = self, let peer = peer, let chatPeer = peer.peers[peer.peerId], let mainPeer = peer.chatMainPeer else { guard let strongSelf = self, let peer = peer, let chatPeer = peer.peers[peer.peerId], let mainPeer = peer.chatMainPeer else {
return return
@ -2564,7 +2544,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
canRemoveGlobally = true canRemoveGlobally = true
} }
if let user = chatPeer as? TelegramUser, user.botInfo == nil, canRemoveGlobally { if case let .user(user) = chatPeer, user.botInfo == nil, canRemoveGlobally {
strongSelf.maybeAskForPeerChatRemoval(peer: peer, joined: joined, completion: { _ in }, removed: {}) strongSelf.maybeAskForPeerChatRemoval(peer: peer, joined: joined, completion: { _ in }, removed: {})
} else { } else {
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData) let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
@ -2574,7 +2554,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
var canRemoveGlobally = false var canRemoveGlobally = false
var deleteTitle = strongSelf.presentationData.strings.Common_Delete var deleteTitle = strongSelf.presentationData.strings.Common_Delete
if let channel = chatPeer as? TelegramChannel { if case let .channel(channel) = chatPeer {
if case .broadcast = channel.info { if case .broadcast = channel.info {
canClear = false canClear = false
deleteTitle = strongSelf.presentationData.strings.Channel_LeaveChannel deleteTitle = strongSelf.presentationData.strings.Channel_LeaveChannel
@ -2590,30 +2570,38 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
if let addressName = channel.addressName, !addressName.isEmpty { if let addressName = channel.addressName, !addressName.isEmpty {
canClear = false canClear = false
} }
} else if let group = chatPeer as? TelegramGroup { } else if case let .legacyGroup(group) = chatPeer {
if case .creator = group.role { if case .creator = group.role {
canRemoveGlobally = true canRemoveGlobally = true
} }
} else if let user = chatPeer as? TelegramUser, user.botInfo != nil { } else if case let .user(user) = chatPeer, user.botInfo != nil {
canStop = !user.flags.contains(.isSupport) canStop = !user.flags.contains(.isSupport)
canClear = user.botInfo == nil canClear = user.botInfo == nil
deleteTitle = strongSelf.presentationData.strings.ChatList_DeleteChat deleteTitle = strongSelf.presentationData.strings.ChatList_DeleteChat
} else if let _ = chatPeer as? TelegramSecretChat { } else if case .secretChat = chatPeer {
canClear = true canClear = true
deleteTitle = strongSelf.presentationData.strings.ChatList_DeleteChat deleteTitle = strongSelf.presentationData.strings.ChatList_DeleteChat
} }
let limitsConfiguration = strongSelf.context.currentLimitsConfiguration.with { $0 } let limitsConfiguration = strongSelf.context.currentLimitsConfiguration.with { $0 }
if chatPeer is TelegramUser && chatPeer.id != strongSelf.context.account.peerId { if case .user = chatPeer, chatPeer.id != strongSelf.context.account.peerId {
if limitsConfiguration.maxMessageRevokeIntervalInPrivateChats == LimitsConfiguration.timeIntervalForever { if limitsConfiguration.maxMessageRevokeIntervalInPrivateChats == LimitsConfiguration.timeIntervalForever {
canRemoveGlobally = true canRemoveGlobally = true
} }
} else if chatPeer is TelegramSecretChat { } else if case .secretChat = chatPeer {
canRemoveGlobally = true canRemoveGlobally = true
} }
if canRemoveGlobally, (mainPeer is TelegramGroup || mainPeer is TelegramChannel) { var isGroupOrChannel = false
items.append(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: EnginePeer(mainPeer), chatPeer: EnginePeer(chatPeer), action: .deleteAndLeave, strings: strongSelf.presentationData.strings, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder)) switch mainPeer {
case .legacyGroup, .channel:
isGroupOrChannel = true
default:
break
}
if canRemoveGlobally && isGroupOrChannel {
items.append(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: mainPeer, chatPeer: chatPeer, action: .deleteAndLeave, strings: strongSelf.presentationData.strings, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder))
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForCurrentUser, color: .destructive, action: { [weak actionSheet] in items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForCurrentUser, color: .destructive, action: { [weak actionSheet] in
actionSheet?.dismissAnimated() actionSheet?.dismissAnimated()
@ -2622,7 +2610,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
})) }))
let deleteForAllText: String let deleteForAllText: String
if let channel = mainPeer as? TelegramChannel, case .broadcast = channel.info { if case let .channel(channel) = mainPeer, case .broadcast = channel.info {
deleteForAllText = strongSelf.presentationData.strings.ChatList_DeleteForAllSubscribers deleteForAllText = strongSelf.presentationData.strings.ChatList_DeleteForAllSubscribers
} else { } else {
deleteForAllText = strongSelf.presentationData.strings.ChatList_DeleteForAllMembers deleteForAllText = strongSelf.presentationData.strings.ChatList_DeleteForAllMembers
@ -2635,7 +2623,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
} }
let deleteForAllConfirmation: String let deleteForAllConfirmation: String
if let channel = mainPeer as? TelegramChannel, case .broadcast = channel.info { if case let .channel(channel) = mainPeer, case .broadcast = channel.info {
deleteForAllConfirmation = strongSelf.presentationData.strings.ChannelInfo_DeleteChannelConfirmation deleteForAllConfirmation = strongSelf.presentationData.strings.ChannelInfo_DeleteChannelConfirmation
} else { } else {
deleteForAllConfirmation = strongSelf.presentationData.strings.ChannelInfo_DeleteGroupConfirmation deleteForAllConfirmation = strongSelf.presentationData.strings.ChannelInfo_DeleteGroupConfirmation
@ -2651,7 +2639,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
], parseMarkdown: true), in: .window(.root)) ], parseMarkdown: true), in: .window(.root))
})) }))
} else { } else {
items.append(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: EnginePeer(mainPeer), chatPeer: EnginePeer(chatPeer), action: .delete, strings: strongSelf.presentationData.strings, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder)) items.append(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: mainPeer, chatPeer: chatPeer, action: .delete, strings: strongSelf.presentationData.strings, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder))
if canClear { if canClear {
let beginClear: (InteractiveHistoryClearingType) -> Void = { type in let beginClear: (InteractiveHistoryClearingType) -> Void = { type in
@ -2705,14 +2693,14 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
return return
} }
if chatPeer is TelegramSecretChat { if case .secretChat = chatPeer {
beginClear(.forEveryone) beginClear(.forEveryone)
} else { } else {
if canRemoveGlobally { if canRemoveGlobally {
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData) let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
var items: [ActionSheetItem] = [] var items: [ActionSheetItem] = []
items.append(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: EnginePeer(mainPeer), chatPeer: EnginePeer(chatPeer), action: .clearHistory(canClearCache: false), strings: strongSelf.presentationData.strings, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder)) items.append(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: mainPeer, chatPeer: chatPeer, action: .clearHistory(canClearCache: false), strings: strongSelf.presentationData.strings, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder))
if joined || mainPeer.isDeleted { if joined || mainPeer.isDeleted {
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Delete, color: .destructive, action: { [weak actionSheet] in items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Delete, color: .destructive, action: { [weak actionSheet] in
@ -2724,7 +2712,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
beginClear(.forLocalPeer) beginClear(.forLocalPeer)
actionSheet?.dismissAnimated() actionSheet?.dismissAnimated()
})) }))
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForEveryone(EnginePeer(mainPeer).compactDisplayTitle).string, color: .destructive, action: { [weak actionSheet] in items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForEveryone(mainPeer.compactDisplayTitle).string, color: .destructive, action: { [weak actionSheet] in
beginClear(.forEveryone) beginClear(.forEveryone)
actionSheet?.dismissAnimated() actionSheet?.dismissAnimated()
})) }))
@ -2752,8 +2740,8 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
})) }))
} }
if chatPeer is TelegramSecretChat { if case .secretChat = chatPeer {
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForEveryone(EnginePeer(mainPeer).compactDisplayTitle).string, color: .destructive, action: { [weak actionSheet] in items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForEveryone(mainPeer.compactDisplayTitle).string, color: .destructive, action: { [weak actionSheet] in
actionSheet?.dismissAnimated() actionSheet?.dismissAnimated()
guard let strongSelf = self else { guard let strongSelf = self else {
return return
@ -2768,11 +2756,19 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
return return
} }
if canRemoveGlobally, (mainPeer is TelegramGroup || mainPeer is TelegramChannel) { var isGroupOrChannel = false
switch mainPeer {
case .legacyGroup, .channel:
isGroupOrChannel = true
default:
break
}
if canRemoveGlobally && isGroupOrChannel {
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData) let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
var items: [ActionSheetItem] = [] var items: [ActionSheetItem] = []
items.append(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: EnginePeer(mainPeer), chatPeer: EnginePeer(chatPeer), action: .deleteAndLeave, strings: strongSelf.presentationData.strings, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder)) items.append(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: mainPeer, chatPeer: chatPeer, action: .deleteAndLeave, strings: strongSelf.presentationData.strings, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder))
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForCurrentUser, color: .destructive, action: { [weak actionSheet] in items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForCurrentUser, color: .destructive, action: { [weak actionSheet] in
actionSheet?.dismissAnimated() actionSheet?.dismissAnimated()
@ -2781,7 +2777,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
})) }))
let deleteForAllText: String let deleteForAllText: String
if let channel = mainPeer as? TelegramChannel, case .broadcast = channel.info { if case let .channel(channel) = mainPeer, case .broadcast = channel.info {
deleteForAllText = strongSelf.presentationData.strings.ChatList_DeleteForAllSubscribers deleteForAllText = strongSelf.presentationData.strings.ChatList_DeleteForAllSubscribers
} else { } else {
deleteForAllText = strongSelf.presentationData.strings.ChatList_DeleteForAllMembers deleteForAllText = strongSelf.presentationData.strings.ChatList_DeleteForAllMembers
@ -2794,7 +2790,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
} }
let deleteForAllConfirmation: String let deleteForAllConfirmation: String
if let channel = mainPeer as? TelegramChannel, case .broadcast = channel.info { if case let .channel(channel) = mainPeer, case .broadcast = channel.info {
deleteForAllConfirmation = strongSelf.presentationData.strings.ChatList_DeleteForAllSubscribersConfirmationText deleteForAllConfirmation = strongSelf.presentationData.strings.ChatList_DeleteForAllSubscribersConfirmationText
} else { } else {
deleteForAllConfirmation = strongSelf.presentationData.strings.ChatList_DeleteForAllMembersConfirmationText deleteForAllConfirmation = strongSelf.presentationData.strings.ChatList_DeleteForAllMembersConfirmationText
@ -2854,7 +2850,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
}) })
} }
public func maybeAskForPeerChatRemoval(peer: RenderedPeer, joined: Bool = false, deleteGloballyIfPossible: Bool = false, completion: @escaping (Bool) -> Void, removed: @escaping () -> Void) { public func maybeAskForPeerChatRemoval(peer: EngineRenderedPeer, joined: Bool = false, deleteGloballyIfPossible: Bool = false, completion: @escaping (Bool) -> Void, removed: @escaping () -> Void) {
guard let chatPeer = peer.peers[peer.peerId], let mainPeer = peer.chatMainPeer else { guard let chatPeer = peer.peers[peer.peerId], let mainPeer = peer.chatMainPeer else {
completion(false) completion(false)
return return
@ -2866,10 +2862,10 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
canRemoveGlobally = true canRemoveGlobally = true
} }
} }
if let user = chatPeer as? TelegramUser, user.botInfo != nil { if case let .user(user) = chatPeer, user.botInfo != nil {
canRemoveGlobally = false canRemoveGlobally = false
} }
if let _ = chatPeer as? TelegramSecretChat { if case .secretChat = chatPeer {
canRemoveGlobally = true canRemoveGlobally = true
} }
@ -2877,7 +2873,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
let actionSheet = ActionSheetController(presentationData: self.presentationData) let actionSheet = ActionSheetController(presentationData: self.presentationData)
var items: [ActionSheetItem] = [] var items: [ActionSheetItem] = []
items.append(DeleteChatPeerActionSheetItem(context: self.context, peer: EnginePeer(mainPeer), chatPeer: EnginePeer(chatPeer), action: .delete, strings: self.presentationData.strings, nameDisplayOrder: self.presentationData.nameDisplayOrder)) items.append(DeleteChatPeerActionSheetItem(context: self.context, peer: mainPeer, chatPeer: chatPeer, action: .delete, strings: self.presentationData.strings, nameDisplayOrder: self.presentationData.nameDisplayOrder))
if joined || mainPeer.isDeleted { if joined || mainPeer.isDeleted {
items.append(ActionSheetButtonItem(title: self.presentationData.strings.Common_Delete, color: .destructive, action: { [weak self, weak actionSheet] in items.append(ActionSheetButtonItem(title: self.presentationData.strings.Common_Delete, color: .destructive, action: { [weak self, weak actionSheet] in
@ -2895,7 +2891,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
}) })
completion(true) completion(true)
})) }))
items.append(ActionSheetButtonItem(title: self.presentationData.strings.ChatList_DeleteForEveryone(EnginePeer(mainPeer).compactDisplayTitle).string, color: .destructive, action: { [weak self, weak actionSheet] in items.append(ActionSheetButtonItem(title: self.presentationData.strings.ChatList_DeleteForEveryone(mainPeer.compactDisplayTitle).string, color: .destructive, action: { [weak self, weak actionSheet] in
actionSheet?.dismissAnimated() actionSheet?.dismissAnimated()
guard let strongSelf = self else { guard let strongSelf = self else {
return return
@ -3016,7 +3012,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
}) })
} }
private func schedulePeerChatRemoval(peer: RenderedPeer, type: InteractiveMessagesDeletionType, deleteGloballyIfPossible: Bool, completion: @escaping () -> Void) { private func schedulePeerChatRemoval(peer: EngineRenderedPeer, type: InteractiveMessagesDeletionType, deleteGloballyIfPossible: Bool, completion: @escaping () -> Void) {
guard let chatPeer = peer.peers[peer.peerId] else { guard let chatPeer = peer.peers[peer.peerId] else {
return return
} }
@ -3035,7 +3031,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
}) })
self.chatListDisplayNode.containerNode.currentItemNode.setCurrentRemovingPeerId(nil) self.chatListDisplayNode.containerNode.currentItemNode.setCurrentRemovingPeerId(nil)
let statusText: String let statusText: String
if let channel = chatPeer as? TelegramChannel { if case let .channel(channel) = chatPeer {
if deleteGloballyIfPossible { if deleteGloballyIfPossible {
if case .broadcast = channel.info { if case .broadcast = channel.info {
statusText = self.presentationData.strings.Undo_DeletedChannel statusText = self.presentationData.strings.Undo_DeletedChannel
@ -3049,13 +3045,13 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
statusText = self.presentationData.strings.Undo_LeftGroup statusText = self.presentationData.strings.Undo_LeftGroup
} }
} }
} else if let _ = chatPeer as? TelegramGroup { } else if case .legacyGroup = chatPeer {
if deleteGloballyIfPossible { if deleteGloballyIfPossible {
statusText = self.presentationData.strings.Undo_DeletedGroup statusText = self.presentationData.strings.Undo_DeletedGroup
} else { } else {
statusText = self.presentationData.strings.Undo_LeftGroup statusText = self.presentationData.strings.Undo_LeftGroup
} }
} else if let _ = chatPeer as? TelegramSecretChat { } else if case .secretChat = chatPeer {
statusText = self.presentationData.strings.Undo_SecretChatDeleted statusText = self.presentationData.strings.Undo_SecretChatDeleted
} else { } else {
if case .forEveryone = type { if case .forEveryone = type {
@ -3078,7 +3074,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
} }
if value == .commit { if value == .commit {
strongSelf.chatListDisplayNode.containerNode.currentItemNode.setCurrentRemovingPeerId(peerId) strongSelf.chatListDisplayNode.containerNode.currentItemNode.setCurrentRemovingPeerId(peerId)
if let channel = chatPeer as? TelegramChannel { if case let .channel(channel) = chatPeer {
strongSelf.context.peerChannelMemberCategoriesContextsManager.externallyRemoved(peerId: channel.id, memberId: strongSelf.context.account.peerId) strongSelf.context.peerChannelMemberCategoriesContextsManager.externallyRemoved(peerId: channel.id, memberId: strongSelf.context.account.peerId)
} }
let _ = strongSelf.context.engine.peers.removePeerChat(peerId: peerId, reportChatSpam: false, deleteGloballyIfPossible: deleteGloballyIfPossible).start(completed: { let _ = strongSelf.context.engine.peers.removePeerChat(peerId: peerId, reportChatSpam: false, deleteGloballyIfPossible: deleteGloballyIfPossible).start(completed: {

View File

@ -225,12 +225,12 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
case includePeersHeader(String) case includePeersHeader(String)
case addIncludePeer(title: String) case addIncludePeer(title: String)
case includeCategory(index: Int, category: ChatListFilterIncludeCategory, title: String, isRevealed: Bool) case includeCategory(index: Int, category: ChatListFilterIncludeCategory, title: String, isRevealed: Bool)
case includePeer(index: Int, peer: RenderedPeer, isRevealed: Bool) case includePeer(index: Int, peer: EngineRenderedPeer, isRevealed: Bool)
case includePeerInfo(String) case includePeerInfo(String)
case excludePeersHeader(String) case excludePeersHeader(String)
case addExcludePeer(title: String) case addExcludePeer(title: String)
case excludeCategory(index: Int, category: ChatListFilterExcludeCategory, title: String, isRevealed: Bool) case excludeCategory(index: Int, category: ChatListFilterExcludeCategory, title: String, isRevealed: Bool)
case excludePeer(index: Int, peer: RenderedPeer, isRevealed: Bool) case excludePeer(index: Int, peer: EngineRenderedPeer, isRevealed: Bool)
case excludePeerInfo(String) case excludePeerInfo(String)
case includeExpand(String) case includeExpand(String)
case excludeExpand(String) case excludeExpand(String)
@ -389,7 +389,7 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
} }
) )
case let .includePeer(_, peer, isRevealed): case let .includePeer(_, peer, isRevealed):
return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(), nameDisplayOrder: .firstLast, context: arguments.context, peer: EnginePeer(peer.chatMainPeer!), height: .peerList, aliasHandling: .threatSelfAsSaved, presence: nil, text: .none, label: .none, editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: isRevealed), revealOptions: ItemListPeerItemRevealOptions(options: [ItemListPeerItemRevealOption(type: .destructive, title: presentationData.strings.Common_Delete, action: { return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(), nameDisplayOrder: .firstLast, context: arguments.context, peer: peer.chatMainPeer!, height: .peerList, aliasHandling: .threatSelfAsSaved, presence: nil, text: .none, label: .none, editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: isRevealed), revealOptions: ItemListPeerItemRevealOptions(options: [ItemListPeerItemRevealOption(type: .destructive, title: presentationData.strings.Common_Delete, action: {
arguments.deleteIncludePeer(peer.peerId) arguments.deleteIncludePeer(peer.peerId)
})]), switchValue: nil, enabled: true, selectable: false, sectionId: self.section, action: nil, setPeerIdWithRevealedOptions: { lhs, rhs in })]), switchValue: nil, enabled: true, selectable: false, sectionId: self.section, action: nil, setPeerIdWithRevealedOptions: { lhs, rhs in
arguments.setItemIdWithRevealedOptions(lhs.flatMap { .peer($0) }, rhs.flatMap { .peer($0) }) arguments.setItemIdWithRevealedOptions(lhs.flatMap { .peer($0) }, rhs.flatMap { .peer($0) })
@ -397,7 +397,7 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
arguments.deleteIncludePeer(id) arguments.deleteIncludePeer(id)
}) })
case let .excludePeer(_, peer, isRevealed): case let .excludePeer(_, peer, isRevealed):
return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(), nameDisplayOrder: .firstLast, context: arguments.context, peer: EnginePeer(peer.chatMainPeer!), height: .peerList, aliasHandling: .threatSelfAsSaved, presence: nil, text: .none, label: .none, editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: isRevealed), revealOptions: ItemListPeerItemRevealOptions(options: [ItemListPeerItemRevealOption(type: .destructive, title: presentationData.strings.Common_Delete, action: { return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(), nameDisplayOrder: .firstLast, context: arguments.context, peer: peer.chatMainPeer!, height: .peerList, aliasHandling: .threatSelfAsSaved, presence: nil, text: .none, label: .none, editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: isRevealed), revealOptions: ItemListPeerItemRevealOptions(options: [ItemListPeerItemRevealOption(type: .destructive, title: presentationData.strings.Common_Delete, action: {
arguments.deleteExcludePeer(peer.peerId) arguments.deleteExcludePeer(peer.peerId)
})]), switchValue: nil, enabled: true, selectable: false, sectionId: self.section, action: nil, setPeerIdWithRevealedOptions: { lhs, rhs in })]), switchValue: nil, enabled: true, selectable: false, sectionId: self.section, action: nil, setPeerIdWithRevealedOptions: { lhs, rhs in
arguments.setItemIdWithRevealedOptions(lhs.flatMap { .peer($0) }, rhs.flatMap { .peer($0) }) arguments.setItemIdWithRevealedOptions(lhs.flatMap { .peer($0) }, rhs.flatMap { .peer($0) })
@ -454,7 +454,7 @@ private struct ChatListFilterPresetControllerState: Equatable {
} }
} }
private func chatListFilterPresetControllerEntries(presentationData: PresentationData, isNewFilter: Bool, state: ChatListFilterPresetControllerState, includePeers: [RenderedPeer], excludePeers: [RenderedPeer]) -> [ChatListFilterPresetEntry] { private func chatListFilterPresetControllerEntries(presentationData: PresentationData, isNewFilter: Bool, state: ChatListFilterPresetControllerState, includePeers: [EngineRenderedPeer], excludePeers: [EngineRenderedPeer]) -> [ChatListFilterPresetEntry] {
var entries: [ChatListFilterPresetEntry] = [] var entries: [ChatListFilterPresetEntry] = []
if isNewFilter { if isNewFilter {
@ -933,12 +933,12 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
} }
) )
let currentPeers = Atomic<[PeerId: RenderedPeer]>(value: [:]) let currentPeers = Atomic<[PeerId: EngineRenderedPeer]>(value: [:])
let stateWithPeers = statePromise.get() let stateWithPeers = statePromise.get()
|> mapToSignal { state -> Signal<(ChatListFilterPresetControllerState, [RenderedPeer], [RenderedPeer]), NoError> in |> mapToSignal { state -> Signal<(ChatListFilterPresetControllerState, [EngineRenderedPeer], [EngineRenderedPeer]), NoError> in
let currentPeersValue = currentPeers.with { $0 } let currentPeersValue = currentPeers.with { $0 }
var included: [RenderedPeer] = [] var included: [EngineRenderedPeer] = []
var excluded: [RenderedPeer] = [] var excluded: [EngineRenderedPeer] = []
var missingPeers = false var missingPeers = false
for peerId in state.additionallyIncludePeers { for peerId in state.additionallyIncludePeers {
if let peer = currentPeersValue[peerId] { if let peer = currentPeersValue[peerId] {
@ -955,20 +955,30 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
} }
} }
if missingPeers { if missingPeers {
return context.account.postbox.transaction { transaction -> (ChatListFilterPresetControllerState, [RenderedPeer], [RenderedPeer]) in return context.engine.data.get(
var included: [RenderedPeer] = [] EngineDataMap(
var excluded: [RenderedPeer] = [] state.additionallyIncludePeers.map { peerId -> TelegramEngine.EngineData.Item.Peer.RenderedPeer in
var allPeers: [PeerId: RenderedPeer] = [:] return TelegramEngine.EngineData.Item.Peer.RenderedPeer(id: peerId)
}
),
EngineDataMap(
state.additionallyExcludePeers.map { peerId -> TelegramEngine.EngineData.Item.Peer.RenderedPeer in
return TelegramEngine.EngineData.Item.Peer.RenderedPeer(id: peerId)
}
)
)
|> map { additionallyIncludePeers, additionallyExcludePeers -> (ChatListFilterPresetControllerState, [EngineRenderedPeer], [EngineRenderedPeer]) in
var included: [EngineRenderedPeer] = []
var excluded: [EngineRenderedPeer] = []
var allPeers: [EnginePeer.Id: EngineRenderedPeer] = [:]
for peerId in state.additionallyIncludePeers { for peerId in state.additionallyIncludePeers {
if let peer = transaction.getPeer(peerId) { if let renderedPeerValue = additionallyIncludePeers[peerId], let renderedPeer = renderedPeerValue {
let renderedPeer = RenderedPeer(peer: peer)
included.append(renderedPeer) included.append(renderedPeer)
allPeers[renderedPeer.peerId] = renderedPeer allPeers[renderedPeer.peerId] = renderedPeer
} }
} }
for peerId in state.additionallyExcludePeers { for peerId in state.additionallyExcludePeers {
if let peer = transaction.getPeer(peerId) { if let renderedPeerValue = additionallyExcludePeers[peerId], let renderedPeer = renderedPeerValue {
let renderedPeer = RenderedPeer(peer: peer)
excluded.append(renderedPeer) excluded.append(renderedPeer)
allPeers[renderedPeer.peerId] = renderedPeer allPeers[renderedPeer.peerId] = renderedPeer
} }

View File

@ -614,11 +614,16 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
guard let strongSelf = self, let messageIds = strongSelf.stateValue.selectedMessageIds, !messageIds.isEmpty else { guard let strongSelf = self, let messageIds = strongSelf.stateValue.selectedMessageIds, !messageIds.isEmpty else {
return return
} }
let _ = (strongSelf.context.account.postbox.transaction { transaction -> [EngineMessage] in let _ = (strongSelf.context.engine.data.get(EngineDataMap(
messageIds.map { id -> TelegramEngine.EngineData.Item.Messages.Message in
return TelegramEngine.EngineData.Item.Messages.Message(id: id)
}
))
|> map { messageMap -> [EngineMessage] in
var messages: [EngineMessage] = [] var messages: [EngineMessage] = []
for id in messageIds { for id in messageIds {
if let message = transaction.getMessage(id) { if let messageValue = messageMap[id], let message = messageValue {
messages.append(EngineMessage(message)) messages.append(message)
} }
} }
return messages return messages
@ -641,11 +646,16 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
guard let strongSelf = self, let messageIds = strongSelf.stateValue.selectedMessageIds, !messageIds.isEmpty else { guard let strongSelf = self, let messageIds = strongSelf.stateValue.selectedMessageIds, !messageIds.isEmpty else {
return return
} }
let _ = (strongSelf.context.account.postbox.transaction { transaction -> [EngineMessage] in let _ = (strongSelf.context.engine.data.get(EngineDataMap(
messageIds.map { id -> TelegramEngine.EngineData.Item.Messages.Message in
return TelegramEngine.EngineData.Item.Messages.Message(id: id)
}
))
|> map { messageMap -> [EngineMessage] in
var messages: [EngineMessage] = [] var messages: [EngineMessage] = []
for id in messageIds { for id in messageIds {
if let message = transaction.getMessage(id) { if let messageValue = messageMap[id], let message = messageValue {
messages.append(EngineMessage(message)) messages.append(message)
} }
} }
return messages return messages
@ -898,43 +908,6 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
}))) })))
} }
/*if !actions.options.intersection([.deleteLocally, .deleteGlobally]).isEmpty {
if !items.isEmpty {
items.append(.separator)
}
if actions.options.contains(.deleteLocally) {
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_DeleteMessagesForMe, textColor: .destructive, icon: { _ in
return nil
}, action: { controller, f in
guard let strongSelf = self else {
return
}
let _ = strongSelf.context.engine.messages.deleteMessagesInteractively(messageIds: [message.id], type: .forLocalPeer).start()
f(.dismissWithoutContent)
})))
}
if actions.options.contains(.deleteGlobally) {
let text: String
if let mainPeer = message.peers[message.id.peerId] {
if mainPeer is TelegramUser {
text = strongSelf.presentationData.strings.ChatList_DeleteForEveryone(EnginePeer(mainPeer).compactDisplayTitle).string
} else {
text = strongSelf.presentationData.strings.Conversation_DeleteMessagesForEveryone
}
} else {
text = strongSelf.presentationData.strings.Conversation_DeleteMessagesForEveryone
}
items.append(.action(ContextMenuActionItem(text: text, textColor: .destructive, icon: { _ in
return nil
}, action: { controller, f in
let _ = strongSelf.context.engine.messages.deleteMessagesInteractively(messageIds: [message.id], type: .forEveryone).start()
f(.dismissWithoutContent)
})))
}
}*/
return items return items
} }
@ -944,7 +917,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
return return
} }
let _ = storedMessageFromSearch(account: self.context.account, message: message._asMessage()).start() self.context.engine.messages.ensureMessagesAreLocallyAvailable(messages: [message])
var linkForCopying: String? var linkForCopying: String?
var currentSupernode: ASDisplayNode? = node var currentSupernode: ASDisplayNode? = node
@ -1093,8 +1066,19 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
if let messageIds = messageIds ?? self.stateValue.selectedMessageIds, !messageIds.isEmpty { if let messageIds = messageIds ?? self.stateValue.selectedMessageIds, !messageIds.isEmpty {
if isDownloads { if isDownloads {
let _ = (self.context.account.postbox.transaction { transaction -> [Message] in let _ = (self.context.engine.data.get(EngineDataMap(
return messageIds.compactMap(transaction.getMessage) messageIds.map { id -> TelegramEngine.EngineData.Item.Messages.Message in
return TelegramEngine.EngineData.Item.Messages.Message(id: id)
}
))
|> map { messageMap -> [EngineMessage] in
var messages: [EngineMessage] = []
for id in messageIds {
if let messageValue = messageMap[id], let message = messageValue {
messages.append(message)
}
}
return messages
} }
|> deliverOnMainQueue).start(next: { [weak self] messages in |> deliverOnMainQueue).start(next: { [weak self] messages in
guard let strongSelf = self else { guard let strongSelf = self else {
@ -1142,13 +1126,8 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
}) })
} else { } else {
let (peers, messages) = self.currentMessages let (peers, messages) = self.currentMessages
let _ = (self.context.account.postbox.transaction { transaction -> Void in
for id in messageIds { self.context.engine.messages.ensureMessagesAreLocallyAvailable(messages: messages.values.filter { messageIds.contains($0.id) })
if transaction.getMessage(id) == nil, let message = messages[id] {
storeMessageFromSearch(transaction: transaction, message: message._asMessage())
}
}
}).start()
self.activeActionDisposable.set((self.context.sharedContext.chatAvailableMessageActions(postbox: self.context.account.postbox, accountPeerId: self.context.account.peerId, messageIds: messageIds, messages: messages, peers: peers) self.activeActionDisposable.set((self.context.sharedContext.chatAvailableMessageActions(postbox: self.context.account.postbox, accountPeerId: self.context.account.peerId, messageIds: messageIds, messages: messages, peers: peers)
|> deliverOnMainQueue).start(next: { [weak self] actions in |> deliverOnMainQueue).start(next: { [weak self] actions in
@ -1211,13 +1190,8 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
let messageIds = messageIds ?? self.stateValue.selectedMessageIds let messageIds = messageIds ?? self.stateValue.selectedMessageIds
if let messageIds = messageIds, !messageIds.isEmpty { if let messageIds = messageIds, !messageIds.isEmpty {
let messages = self.paneContainerNode.allCurrentMessages() let messages = self.paneContainerNode.allCurrentMessages()
let _ = (self.context.account.postbox.transaction { transaction -> Void in
for id in messageIds { self.context.engine.messages.ensureMessagesAreLocallyAvailable(messages: messages.values.filter { messageIds.contains($0.id) })
if transaction.getMessage(id) == nil, let message = messages[id] {
storeMessageFromSearch(transaction: transaction, message: message._asMessage())
}
}
}).start()
let peerSelectionController = self.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: self.context, filter: [.onlyWriteable, .excludeDisabled], multipleSelection: true)) let peerSelectionController = self.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: self.context, filter: [.onlyWriteable, .excludeDisabled], multipleSelection: true))
peerSelectionController.multiplePeersSelected = { [weak self, weak peerSelectionController] peers, peerMap, messageText, mode, forwardOptions in peerSelectionController.multiplePeersSelected = { [weak self, weak peerSelectionController] peers, peerMap, messageText, mode, forwardOptions in

View File

@ -799,7 +799,7 @@ public struct ChatListSearchOptions {
private struct DownloadItem: Equatable { private struct DownloadItem: Equatable {
let resourceId: MediaResourceId let resourceId: MediaResourceId
let message: Message let message: EngineMessage
let priority: FetchManagerPriorityKey let priority: FetchManagerPriorityKey
let isPaused: Bool let isPaused: Bool
@ -1053,8 +1053,9 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
for entry in entries { for entry in entries {
switch entry.id.locationKey { switch entry.id.locationKey {
case let .messageId(id): case let .messageId(id):
itemSignals.append(context.account.postbox.transaction { transaction -> DownloadItem? in itemSignals.append(context.engine.data.get(TelegramEngine.EngineData.Item.Messages.Message(id: id))
if let message = transaction.getMessage(id) { |> map { message -> DownloadItem? in
if let message = message {
return DownloadItem(resourceId: entry.resourceReference.resource.id, message: message, priority: entry.priority, isPaused: entry.isPaused) return DownloadItem(resourceId: entry.resourceReference.resource.id, message: message, priority: entry.priority, isPaused: entry.isPaused)
} }
return nil return nil
@ -1134,7 +1135,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
} }
existingMessageIds.insert(item.message.id) existingMessageIds.insert(item.message.id)
let message = EngineMessage(item.message) let message = item.message
if !queryTokens.isEmpty { if !queryTokens.isEmpty {
if !messageMatchesTokens(message: message, tokens: queryTokens) { if !messageMatchesTokens(message: message, tokens: queryTokens) {

View File

@ -55,7 +55,7 @@ public final class HashtagSearchController: TelegramBaseController {
}, additionalCategorySelected: { _ in }, additionalCategorySelected: { _ in
}, messageSelected: { [weak self] peer, message, _ in }, messageSelected: { [weak self] peer, message, _ in
if let strongSelf = self { if let strongSelf = self {
strongSelf.openMessageFromSearchDisposable.set((storedMessageFromSearchPeer(account: strongSelf.context.account, peer: peer._asPeer()) |> deliverOnMainQueue).start(next: { actualPeerId in strongSelf.openMessageFromSearchDisposable.set((strongSelf.context.engine.peers.ensurePeerIsLocallyAvailable(peer: peer) |> deliverOnMainQueue).start(next: { actualPeerId in
if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController { if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController {
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(id: actualPeerId), subject: message.id.peerId == actualPeerId ? .message(id: .id(message.id), highlight: true, timecode: nil) : nil, keepStack: .always)) strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(id: actualPeerId), subject: message.id.peerId == actualPeerId ? .message(id: .id(message.id), highlight: true, timecode: nil) : nil, keepStack: .always))
} }

View File

@ -0,0 +1,36 @@
import Foundation
final class MutableLocalNoticeEntryView: MutablePostboxView {
private let key: NoticeEntryKey
fileprivate var value: CodableEntry?
init(postbox: PostboxImpl, key: NoticeEntryKey) {
self.key = key
self.value = postbox.noticeTable.get(key: key)
}
func replay(postbox: PostboxImpl, transaction: PostboxTransaction) -> Bool {
var updated = false
if transaction.updatedNoticeEntryKeys.contains(self.key) {
self.value = postbox.noticeTable.get(key: key)
updated = true
}
return updated
}
func refreshDueToExternalTransaction(postbox: PostboxImpl) -> Bool {
return false
}
func immutableView() -> PostboxView {
return LocalNoticeEntryView(self)
}
}
public final class LocalNoticeEntryView: PostboxView {
public let value: CodableEntry?
init(_ view: MutableLocalNoticeEntryView) {
self.value = view.value
}
}

View File

@ -33,6 +33,7 @@ public enum PostboxViewKey: Hashable {
case topChatMessage(peerIds: [PeerId]) case topChatMessage(peerIds: [PeerId])
case contacts(accountPeerId: PeerId?, includePresences: Bool) case contacts(accountPeerId: PeerId?, includePresences: Bool)
case deletedMessages(peerId: PeerId) case deletedMessages(peerId: PeerId)
case notice(key: NoticeEntryKey)
public func hash(into hasher: inout Hasher) { public func hash(into hasher: inout Hasher) {
switch self { switch self {
@ -109,6 +110,8 @@ public enum PostboxViewKey: Hashable {
hasher.combine(16) hasher.combine(16)
case let .deletedMessages(peerId): case let .deletedMessages(peerId):
hasher.combine(peerId) hasher.combine(peerId)
case let .notice(key):
hasher.combine(key)
} }
} }
@ -306,6 +309,12 @@ public enum PostboxViewKey: Hashable {
} else { } else {
return false return false
} }
case let .notice(key):
if case .notice(key) = rhs {
return true
} else {
return false
}
} }
} }
} }
@ -376,5 +385,7 @@ func postboxViewForKey(postbox: PostboxImpl, key: PostboxViewKey) -> MutablePost
return MutableContactPeersView(postbox: postbox, accountPeerId: accountPeerId, includePresences: includePresences) return MutableContactPeersView(postbox: postbox, accountPeerId: accountPeerId, includePresences: includePresences)
case let .deletedMessages(peerId): case let .deletedMessages(peerId):
return MutableDeletedMessagesView(peerId: peerId) return MutableDeletedMessagesView(peerId: peerId)
case let .notice(key):
return MutableLocalNoticeEntryView(postbox: postbox, key: key)
} }
} }

View File

@ -174,6 +174,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1460809483] = { return Api.Dialog.parse_dialog($0) } dict[-1460809483] = { return Api.Dialog.parse_dialog($0) }
dict[1908216652] = { return Api.Dialog.parse_dialogFolder($0) } dict[1908216652] = { return Api.Dialog.parse_dialogFolder($0) }
dict[1949890536] = { return Api.DialogFilter.parse_dialogFilter($0) } dict[1949890536] = { return Api.DialogFilter.parse_dialogFilter($0) }
dict[909284270] = { return Api.DialogFilter.parse_dialogFilterDefault($0) }
dict[2004110666] = { return Api.DialogFilterSuggested.parse_dialogFilterSuggested($0) } dict[2004110666] = { return Api.DialogFilterSuggested.parse_dialogFilterSuggested($0) }
dict[-445792507] = { return Api.DialogPeer.parse_dialogPeer($0) } dict[-445792507] = { return Api.DialogPeer.parse_dialogPeer($0) }
dict[1363483106] = { return Api.DialogPeer.parse_dialogPeerFolder($0) } dict[1363483106] = { return Api.DialogPeer.parse_dialogPeerFolder($0) }
@ -426,6 +427,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1262252875] = { return Api.MessageAction.parse_messageActionWebViewDataSent($0) } dict[-1262252875] = { return Api.MessageAction.parse_messageActionWebViewDataSent($0) }
dict[1205698681] = { return Api.MessageAction.parse_messageActionWebViewDataSentMe($0) } dict[1205698681] = { return Api.MessageAction.parse_messageActionWebViewDataSentMe($0) }
dict[546203849] = { return Api.MessageEntity.parse_inputMessageEntityMentionName($0) } dict[546203849] = { return Api.MessageEntity.parse_inputMessageEntityMentionName($0) }
dict[1592721940] = { return Api.MessageEntity.parse_messageEntityAnimatedEmoji($0) }
dict[1981704948] = { return Api.MessageEntity.parse_messageEntityBankCard($0) } dict[1981704948] = { return Api.MessageEntity.parse_messageEntityBankCard($0) }
dict[34469328] = { return Api.MessageEntity.parse_messageEntityBlockquote($0) } dict[34469328] = { return Api.MessageEntity.parse_messageEntityBlockquote($0) }
dict[-1117713463] = { return Api.MessageEntity.parse_messageEntityBold($0) } dict[-1117713463] = { return Api.MessageEntity.parse_messageEntityBold($0) }
@ -985,7 +987,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[946083368] = { return Api.messages.StickerSetInstallResult.parse_stickerSetInstallResultSuccess($0) } dict[946083368] = { return Api.messages.StickerSetInstallResult.parse_stickerSetInstallResultSuccess($0) }
dict[816245886] = { return Api.messages.Stickers.parse_stickers($0) } dict[816245886] = { return Api.messages.Stickers.parse_stickers($0) }
dict[-244016606] = { return Api.messages.Stickers.parse_stickersNotModified($0) } dict[-244016606] = { return Api.messages.Stickers.parse_stickersNotModified($0) }
dict[-1442723025] = { return Api.messages.TranscribedAudio.parse_transcribedAudio($0) } dict[-1077051894] = { return Api.messages.TranscribedAudio.parse_transcribedAudio($0) }
dict[1741309751] = { return Api.messages.TranslatedText.parse_translateNoResult($0) } dict[1741309751] = { return Api.messages.TranslatedText.parse_translateNoResult($0) }
dict[-1575684144] = { return Api.messages.TranslatedText.parse_translateResultText($0) } dict[-1575684144] = { return Api.messages.TranslatedText.parse_translateResultText($0) }
dict[136574537] = { return Api.messages.VotesList.parse_votesList($0) } dict[136574537] = { return Api.messages.VotesList.parse_votesList($0) }

View File

@ -1,6 +1,7 @@
public extension Api { public extension Api {
enum MessageEntity: TypeConstructorDescription { enum MessageEntity: TypeConstructorDescription {
case inputMessageEntityMentionName(offset: Int32, length: Int32, userId: Api.InputUser) case inputMessageEntityMentionName(offset: Int32, length: Int32, userId: Api.InputUser)
case messageEntityAnimatedEmoji(offset: Int32, length: Int32)
case messageEntityBankCard(offset: Int32, length: Int32) case messageEntityBankCard(offset: Int32, length: Int32)
case messageEntityBlockquote(offset: Int32, length: Int32) case messageEntityBlockquote(offset: Int32, length: Int32)
case messageEntityBold(offset: Int32, length: Int32) case messageEntityBold(offset: Int32, length: Int32)
@ -31,6 +32,13 @@ public extension Api {
serializeInt32(length, buffer: buffer, boxed: false) serializeInt32(length, buffer: buffer, boxed: false)
userId.serialize(buffer, true) userId.serialize(buffer, true)
break break
case .messageEntityAnimatedEmoji(let offset, let length):
if boxed {
buffer.appendInt32(1592721940)
}
serializeInt32(offset, buffer: buffer, boxed: false)
serializeInt32(length, buffer: buffer, boxed: false)
break
case .messageEntityBankCard(let offset, let length): case .messageEntityBankCard(let offset, let length):
if boxed { if boxed {
buffer.appendInt32(1981704948) buffer.appendInt32(1981704948)
@ -174,6 +182,8 @@ public extension Api {
switch self { switch self {
case .inputMessageEntityMentionName(let offset, let length, let userId): case .inputMessageEntityMentionName(let offset, let length, let userId):
return ("inputMessageEntityMentionName", [("offset", String(describing: offset)), ("length", String(describing: length)), ("userId", String(describing: userId))]) return ("inputMessageEntityMentionName", [("offset", String(describing: offset)), ("length", String(describing: length)), ("userId", String(describing: userId))])
case .messageEntityAnimatedEmoji(let offset, let length):
return ("messageEntityAnimatedEmoji", [("offset", String(describing: offset)), ("length", String(describing: length))])
case .messageEntityBankCard(let offset, let length): case .messageEntityBankCard(let offset, let length):
return ("messageEntityBankCard", [("offset", String(describing: offset)), ("length", String(describing: length))]) return ("messageEntityBankCard", [("offset", String(describing: offset)), ("length", String(describing: length))])
case .messageEntityBlockquote(let offset, let length): case .messageEntityBlockquote(let offset, let length):
@ -234,6 +244,20 @@ public extension Api {
return nil return nil
} }
} }
public static func parse_messageEntityAnimatedEmoji(_ reader: BufferReader) -> MessageEntity? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.MessageEntity.messageEntityAnimatedEmoji(offset: _1!, length: _2!)
}
else {
return nil
}
}
public static func parse_messageEntityBankCard(_ reader: BufferReader) -> MessageEntity? { public static func parse_messageEntityBankCard(_ reader: BufferReader) -> MessageEntity? {
var _1: Int32? var _1: Int32?
_1 = reader.readInt32() _1 = reader.readInt32()

View File

@ -490,14 +490,15 @@ public extension Api.messages {
} }
public extension Api.messages { public extension Api.messages {
enum TranscribedAudio: TypeConstructorDescription { enum TranscribedAudio: TypeConstructorDescription {
case transcribedAudio(text: String) case transcribedAudio(transcriptionId: Int64, text: String)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .transcribedAudio(let text): case .transcribedAudio(let transcriptionId, let text):
if boxed { if boxed {
buffer.appendInt32(-1442723025) buffer.appendInt32(-1077051894)
} }
serializeInt64(transcriptionId, buffer: buffer, boxed: false)
serializeString(text, buffer: buffer, boxed: false) serializeString(text, buffer: buffer, boxed: false)
break break
} }
@ -505,17 +506,20 @@ public extension Api.messages {
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .transcribedAudio(let text): case .transcribedAudio(let transcriptionId, let text):
return ("transcribedAudio", [("text", String(describing: text))]) return ("transcribedAudio", [("transcriptionId", String(describing: transcriptionId)), ("text", String(describing: text))])
} }
} }
public static func parse_transcribedAudio(_ reader: BufferReader) -> TranscribedAudio? { public static func parse_transcribedAudio(_ reader: BufferReader) -> TranscribedAudio? {
var _1: String? var _1: Int64?
_1 = parseString(reader) _1 = reader.readInt64()
var _2: String?
_2 = parseString(reader)
let _c1 = _1 != nil let _c1 = _1 != nil
if _c1 { let _c2 = _2 != nil
return Api.messages.TranscribedAudio.transcribedAudio(text: _1!) if _c1 && _c2 {
return Api.messages.TranscribedAudio.transcribedAudio(transcriptionId: _1!, text: _2!)
} }
else { else {
return nil return nil

View File

@ -4963,6 +4963,24 @@ public extension Api.functions.messages {
}) })
} }
} }
public extension Api.functions.messages {
static func rateTranscribedAudio(peer: Api.InputPeer, msgId: Int32, transcriptionId: Int64, good: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
buffer.appendInt32(2132608815)
peer.serialize(buffer, true)
serializeInt32(msgId, buffer: buffer, boxed: false)
serializeInt64(transcriptionId, buffer: buffer, boxed: false)
good.serialize(buffer, true)
return (FunctionDescription(name: "messages.rateTranscribedAudio", parameters: [("peer", String(describing: peer)), ("msgId", String(describing: msgId)), ("transcriptionId", String(describing: transcriptionId)), ("good", String(describing: good))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
let reader = BufferReader(buffer)
var result: Api.Bool?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Bool
}
return result
})
}
}
public extension Api.functions.messages { public extension Api.functions.messages {
static func readDiscussion(peer: Api.InputPeer, msgId: Int32, readMaxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) { static func readDiscussion(peer: Api.InputPeer, msgId: Int32, readMaxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer() let buffer = Buffer()

View File

@ -897,6 +897,7 @@ public extension Api {
public extension Api { public extension Api {
enum DialogFilter: TypeConstructorDescription { enum DialogFilter: TypeConstructorDescription {
case dialogFilter(flags: Int32, id: Int32, title: String, emoticon: String?, pinnedPeers: [Api.InputPeer], includePeers: [Api.InputPeer], excludePeers: [Api.InputPeer]) case dialogFilter(flags: Int32, id: Int32, title: String, emoticon: String?, pinnedPeers: [Api.InputPeer], includePeers: [Api.InputPeer], excludePeers: [Api.InputPeer])
case dialogFilterDefault
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
@ -923,6 +924,12 @@ public extension Api {
for item in excludePeers { for item in excludePeers {
item.serialize(buffer, true) item.serialize(buffer, true)
} }
break
case .dialogFilterDefault:
if boxed {
buffer.appendInt32(909284270)
}
break break
} }
} }
@ -931,6 +938,8 @@ public extension Api {
switch self { switch self {
case .dialogFilter(let flags, let id, let title, let emoticon, let pinnedPeers, let includePeers, let excludePeers): case .dialogFilter(let flags, let id, let title, let emoticon, let pinnedPeers, let includePeers, let excludePeers):
return ("dialogFilter", [("flags", String(describing: flags)), ("id", String(describing: id)), ("title", String(describing: title)), ("emoticon", String(describing: emoticon)), ("pinnedPeers", String(describing: pinnedPeers)), ("includePeers", String(describing: includePeers)), ("excludePeers", String(describing: excludePeers))]) return ("dialogFilter", [("flags", String(describing: flags)), ("id", String(describing: id)), ("title", String(describing: title)), ("emoticon", String(describing: emoticon)), ("pinnedPeers", String(describing: pinnedPeers)), ("includePeers", String(describing: includePeers)), ("excludePeers", String(describing: excludePeers))])
case .dialogFilterDefault:
return ("dialogFilterDefault", [])
} }
} }
@ -969,6 +978,9 @@ public extension Api {
return nil return nil
} }
} }
public static func parse_dialogFilterDefault(_ reader: BufferReader) -> DialogFilter? {
return Api.DialogFilter.dialogFilterDefault
}
} }
} }

View File

@ -336,44 +336,46 @@ func messageTextEntitiesFromApiEntities(_ entities: [Api.MessageEntity]) -> [Mes
var result: [MessageTextEntity] = [] var result: [MessageTextEntity] = []
for entity in entities { for entity in entities {
switch entity { switch entity {
case .messageEntityUnknown, .inputMessageEntityMentionName: case .messageEntityUnknown, .inputMessageEntityMentionName:
break break
case let .messageEntityMention(offset, length): case let .messageEntityMention(offset, length):
result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Mention)) result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Mention))
case let .messageEntityHashtag(offset, length): case let .messageEntityHashtag(offset, length):
result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Hashtag)) result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Hashtag))
case let .messageEntityBotCommand(offset, length): case let .messageEntityBotCommand(offset, length):
result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .BotCommand)) result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .BotCommand))
case let .messageEntityUrl(offset, length): case let .messageEntityUrl(offset, length):
result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Url)) result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Url))
case let .messageEntityEmail(offset, length): case let .messageEntityEmail(offset, length):
result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Email)) result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Email))
case let .messageEntityBold(offset, length): case let .messageEntityBold(offset, length):
result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Bold)) result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Bold))
case let .messageEntityItalic(offset, length): case let .messageEntityItalic(offset, length):
result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Italic)) result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Italic))
case let .messageEntityCode(offset, length): case let .messageEntityCode(offset, length):
result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Code)) result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Code))
case let .messageEntityPre(offset, length, _): case let .messageEntityPre(offset, length, _):
result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Pre)) result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Pre))
case let .messageEntityTextUrl(offset, length, url): case let .messageEntityTextUrl(offset, length, url):
result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .TextUrl(url: url))) result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .TextUrl(url: url)))
case let .messageEntityMentionName(offset, length, userId): case let .messageEntityMentionName(offset, length, userId):
result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .TextMention(peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))))) result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .TextMention(peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)))))
case let .messageEntityPhone(offset, length): case let .messageEntityPhone(offset, length):
result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .PhoneNumber)) result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .PhoneNumber))
case let .messageEntityCashtag(offset, length): case let .messageEntityCashtag(offset, length):
result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Hashtag)) result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Hashtag))
case let .messageEntityUnderline(offset, length): case let .messageEntityUnderline(offset, length):
result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Underline)) result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Underline))
case let .messageEntityStrike(offset, length): case let .messageEntityStrike(offset, length):
result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Strikethrough)) result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Strikethrough))
case let .messageEntityBlockquote(offset, length): case let .messageEntityBlockquote(offset, length):
result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .BlockQuote)) result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .BlockQuote))
case let .messageEntityBankCard(offset, length): case let .messageEntityBankCard(offset, length):
result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .BankCard)) result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .BankCard))
case let .messageEntitySpoiler(offset, length): case let .messageEntitySpoiler(offset, length):
result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Spoiler)) result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Spoiler))
case let .messageEntityAnimatedEmoji(offset, length):
result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .AnimatedEmoji))
} }
} }
return result return result

View File

@ -48,6 +48,8 @@ func apiEntitiesFromMessageTextEntities(_ entities: [MessageTextEntity], associa
apiEntities.append(.messageEntityBankCard(offset: offset, length: length)) apiEntities.append(.messageEntityBankCard(offset: offset, length: length))
case .Spoiler: case .Spoiler:
apiEntities.append(.messageEntitySpoiler(offset: offset, length: length)) apiEntities.append(.messageEntitySpoiler(offset: offset, length: length))
case .AnimatedEmoji:
apiEntities.append(.messageEntityAnimatedEmoji(offset: offset, length: length))
case .Custom: case .Custom:
break break
} }

View File

@ -142,7 +142,7 @@ private func findMediaResource(media: Media, previousMedia: Media?, resource: Me
return nil return nil
} }
public func findMediaResourceById(message: Message, resourceId: MediaResourceId) -> TelegramMediaResource? { public func findMediaResourceById(message: EngineMessage, resourceId: MediaResourceId) -> TelegramMediaResource? {
for media in message.media { for media in message.media {
if let result = findMediaResourceById(media: media, resourceId: resourceId) { if let result = findMediaResourceById(media: media, resourceId: resourceId) {
return result return result

View File

@ -709,6 +709,8 @@ private func decryptedEntities73(_ entities: [MessageTextEntity]?) -> [SecretApi
break break
case .Spoiler: case .Spoiler:
break break
case .AnimatedEmoji:
break
case .Custom: case .Custom:
break break
} }
@ -760,6 +762,8 @@ private func decryptedEntities101(_ entities: [MessageTextEntity]?) -> [SecretAp
break break
case .Spoiler: case .Spoiler:
break break
case .AnimatedEmoji:
break
case .Custom: case .Custom:
break break
} }

View File

@ -21,6 +21,7 @@ public enum MessageTextEntityType: Equatable {
case Underline case Underline
case BankCard case BankCard
case Spoiler case Spoiler
case AnimatedEmoji
case Custom(type: CustomEntityType) case Custom(type: CustomEntityType)
} }
@ -71,6 +72,8 @@ public struct MessageTextEntity: PostboxCoding, Codable, Equatable {
self.type = .BankCard self.type = .BankCard
case 17: case 17:
self.type = .Spoiler self.type = .Spoiler
case 18:
self.type = .AnimatedEmoji
case Int32.max: case Int32.max:
self.type = .Custom(type: decoder.decodeInt32ForKey("type", orElse: 0)) self.type = .Custom(type: decoder.decodeInt32ForKey("type", orElse: 0))
default: default:
@ -126,6 +129,8 @@ public struct MessageTextEntity: PostboxCoding, Codable, Equatable {
self.type = .BankCard self.type = .BankCard
case 17: case 17:
self.type = .Spoiler self.type = .Spoiler
case 18:
self.type = .AnimatedEmoji
case Int32.max: case Int32.max:
let customType: Int32 = (try? container.decode(Int32.self, forKey: "type")) ?? 0 let customType: Int32 = (try? container.decode(Int32.self, forKey: "type")) ?? 0
self.type = .Custom(type: customType) self.type = .Custom(type: customType)
@ -176,6 +181,8 @@ public struct MessageTextEntity: PostboxCoding, Codable, Equatable {
encoder.encodeInt32(16, forKey: "_rawValue") encoder.encodeInt32(16, forKey: "_rawValue")
case .Spoiler: case .Spoiler:
encoder.encodeInt32(17, forKey: "_rawValue") encoder.encodeInt32(17, forKey: "_rawValue")
case .AnimatedEmoji:
encoder.encodeInt32(18, forKey: "_rawValue")
case let .Custom(type): case let .Custom(type):
encoder.encodeInt32(Int32.max, forKey: "_rawValue") encoder.encodeInt32(Int32.max, forKey: "_rawValue")
encoder.encodeInt32(type, forKey: "type") encoder.encodeInt32(type, forKey: "type")
@ -226,6 +233,8 @@ public struct MessageTextEntity: PostboxCoding, Codable, Equatable {
try container.encode(16 as Int32, forKey: "_rawValue") try container.encode(16 as Int32, forKey: "_rawValue")
case .Spoiler: case .Spoiler:
try container.encode(17 as Int32, forKey: "_rawValue") try container.encode(17 as Int32, forKey: "_rawValue")
case .AnimatedEmoji:
try container.encode(18 as Int32, forKey: "_rawValue")
case let .Custom(type): case let .Custom(type):
try container.encode(Int32.max as Int32, forKey: "_rawValue") try container.encode(Int32.max as Int32, forKey: "_rawValue")
try container.encode(type as Int32, forKey: "type") try container.encode(type as Int32, forKey: "type")

View File

@ -166,5 +166,27 @@ public extension TelegramEngine.EngineData.Item {
return EngineConfiguration.UserLimits(UserLimitsConfiguration(appConfiguration: appConfiguration, isPremium: self.isPremium)) return EngineConfiguration.UserLimits(UserLimitsConfiguration(appConfiguration: appConfiguration, isPremium: self.isPremium))
} }
} }
public struct SuggestedLocalization: TelegramEngineDataItem, PostboxViewDataItem {
public typealias Result = SuggestedLocalizationEntry?
public init() {
}
var key: PostboxViewKey {
return .preferences(keys: Set([PreferencesKeys.suggestedLocalization]))
}
func extract(view: PostboxView) -> Result {
guard let view = view as? PreferencesView else {
preconditionFailure()
}
guard let suggestedLocalization = view.values[PreferencesKeys.suggestedLocalization]?.get(SuggestedLocalizationEntry.self) else {
return nil
}
return suggestedLocalization
}
}
} }
} }

View File

@ -54,10 +54,14 @@ public extension EnginePeerReadCounters {
public extension TelegramEngine.EngineData.Item { public extension TelegramEngine.EngineData.Item {
enum Messages { enum Messages {
public struct Message: TelegramEngineDataItem, PostboxViewDataItem { public struct Message: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
public typealias Result = Optional<EngineMessage> public typealias Result = Optional<EngineMessage>
fileprivate var id: EngineMessage.Id fileprivate var id: EngineMessage.Id
public var mapKey: EngineMessage.Id {
return self.id
}
public init(id: EngineMessage.Id) { public init(id: EngineMessage.Id) {
self.id = id self.id = id

View File

@ -0,0 +1,27 @@
import SwiftSignalKit
import Postbox
public extension TelegramEngine.EngineData.Item {
enum Notices {
public struct Notice: TelegramEngineDataItem, PostboxViewDataItem {
public typealias Result = CodableEntry?
private let entryKey: NoticeEntryKey
public init(key: NoticeEntryKey) {
self.entryKey = key
}
var key: PostboxViewKey {
return .notice(key: self.entryKey)
}
func extract(view: PostboxView) -> Result {
guard let view = view as? LocalNoticeEntryView else {
preconditionFailure()
}
return view.value
}
}
}
}

View File

@ -32,7 +32,7 @@ public extension TelegramEngine.EngineData.Item {
} }
} }
public struct RenderedPeer: TelegramEngineDataItem, PostboxViewDataItem { public struct RenderedPeer: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
public typealias Result = Optional<EngineRenderedPeer> public typealias Result = Optional<EngineRenderedPeer>
fileprivate var id: EnginePeer.Id fileprivate var id: EnginePeer.Id

View File

@ -322,7 +322,7 @@ public extension TelegramEngine {
return _internal_translate(network: self.account.network, text: text, fromLang: fromLang, toLang: toLang) return _internal_translate(network: self.account.network, text: text, fromLang: fromLang, toLang: toLang)
} }
public func transcribeAudio(messageId: MessageId) -> Signal<String?, NoError> { public func transcribeAudio(messageId: MessageId) -> Signal<EngineAudioTranscriptionResult?, NoError> {
return _internal_transcribeAudio(postbox: self.account.postbox, network: self.account.network, messageId: messageId) return _internal_transcribeAudio(postbox: self.account.postbox, network: self.account.network, messageId: messageId)
} }
@ -354,5 +354,13 @@ public extension TelegramEngine {
public func attachMenuBots() -> Signal<[AttachMenuBot], NoError> { public func attachMenuBots() -> Signal<[AttachMenuBot], NoError> {
return _internal_attachMenuBots(postbox: self.account.postbox) return _internal_attachMenuBots(postbox: self.account.postbox)
} }
public func ensureMessagesAreLocallyAvailable(messages: [EngineMessage]) {
let _ = self.account.postbox.transaction({ transaction in
for message in messages {
_internal_storeMessageFromSearch(transaction: transaction, message: message._asMessage())
}
}).start()
}
} }
} }

View File

@ -29,11 +29,16 @@ func _internal_translate(network: Network, text: String, fromLang: String?, toLa
} }
} }
func _internal_transcribeAudio(postbox: Postbox, network: Network, messageId: MessageId) -> Signal<String?, NoError> { public struct EngineAudioTranscriptionResult {
public var id: Int64
public var text: String
}
func _internal_transcribeAudio(postbox: Postbox, network: Network, messageId: MessageId) -> Signal<EngineAudioTranscriptionResult?, NoError> {
return postbox.transaction { transaction -> Api.InputPeer? in return postbox.transaction { transaction -> Api.InputPeer? in
return transaction.getPeer(messageId.peerId).flatMap(apiInputPeer) return transaction.getPeer(messageId.peerId).flatMap(apiInputPeer)
} }
|> mapToSignal { inputPeer -> Signal<String?, NoError> in |> mapToSignal { inputPeer -> Signal<EngineAudioTranscriptionResult?, NoError> in
guard let inputPeer = inputPeer else { guard let inputPeer = inputPeer else {
return .single(nil) return .single(nil)
} }
@ -42,13 +47,13 @@ func _internal_transcribeAudio(postbox: Postbox, network: Network, messageId: Me
|> `catch` { _ -> Signal<Api.messages.TranscribedAudio?, NoError> in |> `catch` { _ -> Signal<Api.messages.TranscribedAudio?, NoError> in
return .single(nil) return .single(nil)
} }
|> mapToSignal { result -> Signal<String?, NoError> in |> mapToSignal { result -> Signal<EngineAudioTranscriptionResult?, NoError> in
guard let result = result else { guard let result = result else {
return .single(nil) return .single(nil)
} }
switch result { switch result {
case let .transcribedAudio(string): case let .transcribedAudio(transcriptionId, text):
return .single(string) return .single(EngineAudioTranscriptionResult(id: transcriptionId, text: text))
} }
} }
} }

View File

@ -336,6 +336,8 @@ extension ChatListFilter {
} }
) )
) )
case .dialogFilterDefault:
preconditionFailure()
} }
} }
@ -465,6 +467,8 @@ private func requestChatListFilters(accountPeerId: PeerId, postbox: Postbox, net
} }
} }
} }
case .dialogFilterDefault:
break
} }
} }
return (filters, missingPeers, missingChats) return (filters, missingPeers, missingChats)

View File

@ -718,6 +718,10 @@ public extension TelegramEngine {
public func deleteNotificationSound(fileId: Int64) -> Signal<Never, DeleteNotificationSoundError> { public func deleteNotificationSound(fileId: Int64) -> Signal<Never, DeleteNotificationSoundError> {
return _internal_deleteNotificationSound(account: self.account, fileId: fileId) return _internal_deleteNotificationSound(account: self.account, fileId: fileId)
} }
public func ensurePeerIsLocallyAvailable(peer: EnginePeer) -> Signal<EnginePeer.Id, NoError> {
return _internal_storedMessageFromSearchPeer(account: self.account, peer: peer._asPeer())
}
} }
} }

View File

@ -1,9 +1,8 @@
import Foundation import Foundation
import Postbox import Postbox
import TelegramCore
import SwiftSignalKit import SwiftSignalKit
public func storedMessageFromSearchPeer(account: Account, peer: Peer) -> Signal<PeerId, NoError> { func _internal_storedMessageFromSearchPeer(account: Account, peer: Peer) -> Signal<PeerId, NoError> {
return account.postbox.transaction { transaction -> PeerId in return account.postbox.transaction { transaction -> PeerId in
if transaction.getPeer(peer.id) == nil { if transaction.getPeer(peer.id) == nil {
updatePeers(transaction: transaction, peers: [peer], update: { previousPeer, updatedPeer in updatePeers(transaction: transaction, peers: [peer], update: { previousPeer, updatedPeer in
@ -17,25 +16,7 @@ public func storedMessageFromSearchPeer(account: Account, peer: Peer) -> Signal<
} }
} }
public func storedMessageFromSearch(account: Account, message: Message) -> Signal<Void, NoError> { func _internal_storeMessageFromSearch(transaction: Transaction, message: Message) {
return account.postbox.transaction { transaction -> Void in
if transaction.getMessage(message.id) == nil {
for (_, peer) in message.peers {
if transaction.getPeer(peer.id) == nil {
updatePeers(transaction: transaction, peers: [peer], update: { previousPeer, updatedPeer in
return updatedPeer
})
}
}
let storeMessage = StoreMessage(id: .Id(message.id), globallyUniqueId: message.globallyUniqueId, groupingKey: message.groupingKey, threadId: message.threadId, timestamp: message.timestamp, flags: StoreMessageFlags(message.flags), tags: message.tags, globalTags: message.globalTags, localTags: message.localTags, forwardInfo: message.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: message.author?.id, text: message.text, attributes: message.attributes, media: message.media)
let _ = transaction.addMessages([storeMessage], location: .Random)
}
}
}
public func storeMessageFromSearch(transaction: Transaction, message: Message) {
if transaction.getMessage(message.id) == nil { if transaction.getMessage(message.id) == nil {
for (_, peer) in message.peers { for (_, peer) in message.peers {
if transaction.getPeer(peer.id) == nil { if transaction.getPeer(peer.id) == nil {

View File

@ -13,6 +13,7 @@ public final class AudioWaveformComponent: Component {
public let samples: Data public let samples: Data
public let peak: Int32 public let peak: Int32
public let status: Signal<MediaPlayerStatus, NoError> public let status: Signal<MediaPlayerStatus, NoError>
public let seek: (Double) -> Void
public init( public init(
backgroundColor: UIColor, backgroundColor: UIColor,
@ -20,7 +21,8 @@ public final class AudioWaveformComponent: Component {
shimmerColor: UIColor?, shimmerColor: UIColor?,
samples: Data, samples: Data,
peak: Int32, peak: Int32,
status: Signal<MediaPlayerStatus, NoError> status: Signal<MediaPlayerStatus, NoError>,
seek: @escaping (Double) -> Void
) { ) {
self.backgroundColor = backgroundColor self.backgroundColor = backgroundColor
self.foregroundColor = foregroundColor self.foregroundColor = foregroundColor
@ -28,6 +30,7 @@ public final class AudioWaveformComponent: Component {
self.samples = samples self.samples = samples
self.peak = peak self.peak = peak
self.status = status self.status = status
self.seek = seek
} }
public static func ==(lhs: AudioWaveformComponent, rhs: AudioWaveformComponent) -> Bool { public static func ==(lhs: AudioWaveformComponent, rhs: AudioWaveformComponent) -> Bool {
@ -49,7 +52,7 @@ public final class AudioWaveformComponent: Component {
return true return true
} }
public final class View: UIView { public final class View: UIView, UIGestureRecognizerDelegate {
private struct ShimmerParams: Equatable { private struct ShimmerParams: Equatable {
var backgroundColor: UIColor var backgroundColor: UIColor
var foregroundColor: UIColor var foregroundColor: UIColor
@ -147,17 +150,39 @@ public final class AudioWaveformComponent: Component {
return LayerImpl.self return LayerImpl.self
} }
private var panRecognizer: UIPanGestureRecognizer?
private var endScrubbing: ((Bool) -> Void)?
private var updateScrubbing: ((CGFloat, Double) -> Void)?
private var updateMultiplier: ((Double) -> Void)?
private var verticalPanEnabled = false
private var scrubbingMultiplier: Double = 1.0
private var scrubbingStartLocation: CGPoint?
private var component: AudioWaveformComponent? private var component: AudioWaveformComponent?
private var validSize: CGSize? private var validSize: CGSize?
private var playbackStatus: MediaPlayerStatus? private var playbackStatus: MediaPlayerStatus?
private var scrubbingBeginTimestamp: Double?
private var scrubbingTimestampValue: Double? private var scrubbingTimestampValue: Double?
private var isAwaitingScrubbingApplication: Bool = false
private var statusDisposable: Disposable? private var statusDisposable: Disposable?
private var playbackStatusAnimator: ConstantDisplayLinkAnimator? private var playbackStatusAnimator: ConstantDisplayLinkAnimator?
private var revealProgress: CGFloat = 1.0 private var revealProgress: CGFloat = 1.0
private var animator: DisplayLinkAnimator? private var animator: DisplayLinkAnimator?
public var enableScrubbing: Bool = false {
didSet {
if self.enableScrubbing != oldValue {
self.disablesInteractiveTransitionGestureRecognizer = self.enableScrubbing
self.panRecognizer?.isEnabled = self.enableScrubbing
}
}
}
override init(frame: CGRect) { override init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
@ -170,6 +195,12 @@ public final class AudioWaveformComponent: Component {
(self.layer as! LayerImpl).didExitHierarchy = { [weak self] in (self.layer as! LayerImpl).didExitHierarchy = { [weak self] in
self?.updatePlaybackAnimation() self?.updatePlaybackAnimation()
} }
let panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:)))
panRecognizer.delegate = self
self.addGestureRecognizer(panRecognizer)
panRecognizer.isEnabled = false
self.panRecognizer = panRecognizer
} }
required public init?(coder: NSCoder) { required public init?(coder: NSCoder) {
@ -180,6 +211,86 @@ public final class AudioWaveformComponent: Component {
self.statusDisposable?.dispose() self.statusDisposable?.dispose()
} }
@objc private func panGesture(_ recognizer: UIPanGestureRecognizer) {
var location = recognizer.location(in: self)
location.x -= self.bounds.minX
switch recognizer.state {
case .began:
self.scrubbingStartLocation = location
self.beginScrubbing()
case .changed:
if let scrubbingStartLocation = self.scrubbingStartLocation {
let delta = location.x - scrubbingStartLocation.x
var multiplier: Double = 1.0
var skipUpdate = false
if self.verticalPanEnabled, location.y > scrubbingStartLocation.y {
let verticalDelta = abs(location.y - scrubbingStartLocation.y)
if verticalDelta > 150.0 {
multiplier = 0.01
} else if verticalDelta > 100.0 {
multiplier = 0.25
} else if verticalDelta > 50.0 {
multiplier = 0.5
}
if multiplier != self.scrubbingMultiplier {
skipUpdate = true
self.scrubbingMultiplier = multiplier
self.scrubbingStartLocation = CGPoint(x: location.x, y: scrubbingStartLocation.y)
self.updateMultiplier?(multiplier)
}
}
if !skipUpdate {
self.updateScrubbing(addedFraction: delta / self.bounds.size.width, multiplier: multiplier)
}
}
case .ended, .cancelled:
if let scrubbingStartLocation = self.scrubbingStartLocation {
self.scrubbingStartLocation = nil
let delta = location.x - scrubbingStartLocation.x
self.updateScrubbing?(delta / self.bounds.size.width, self.scrubbingMultiplier)
self.endScrubbing(apply: recognizer.state == .ended)
//self.highlighted?(false)
self.scrubbingMultiplier = 1.0
}
default:
break
}
}
private func beginScrubbing() {
if let statusValue = self.playbackStatus, statusValue.duration > 0.0 {
self.scrubbingBeginTimestamp = statusValue.timestamp
self.scrubbingTimestampValue = statusValue.timestamp
self.setNeedsDisplay()
}
}
private func endScrubbing(apply: Bool) {
self.scrubbingBeginTimestamp = nil
let scrubbingTimestampValue = self.scrubbingTimestampValue
self.isAwaitingScrubbingApplication = true
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.2, execute: { [weak self] in
guard let strongSelf = self, strongSelf.isAwaitingScrubbingApplication else {
return
}
strongSelf.isAwaitingScrubbingApplication = false
strongSelf.scrubbingTimestampValue = nil
strongSelf.setNeedsDisplay()
})
if let scrubbingTimestampValue = scrubbingTimestampValue, apply {
self.component?.seek(scrubbingTimestampValue)
}
}
private func updateScrubbing(addedFraction: CGFloat, multiplier: Double) {
if let statusValue = self.playbackStatus, let scrubbingBeginTimestamp = self.scrubbingBeginTimestamp, Double(0.0).isLess(than: statusValue.duration) {
self.scrubbingTimestampValue = scrubbingBeginTimestamp + (statusValue.duration * Double(addedFraction)) * multiplier
self.setNeedsDisplay()
}
}
public func animateIn() { public func animateIn() {
if self.animator == nil { if self.animator == nil {
self.revealProgress = 0.0 self.revealProgress = 0.0
@ -226,6 +337,12 @@ public final class AudioWaveformComponent: Component {
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
if strongSelf.isAwaitingScrubbingApplication, value.duration > 0.0, let scrubbingTimestampValue = strongSelf.scrubbingTimestampValue, abs(value.timestamp - scrubbingTimestampValue) <= value.duration * 0.01 {
strongSelf.isAwaitingScrubbingApplication = false
strongSelf.scrubbingTimestampValue = nil
}
if strongSelf.playbackStatus != value { if strongSelf.playbackStatus != value {
strongSelf.playbackStatus = value strongSelf.playbackStatus = value
strongSelf.setNeedsDisplay() strongSelf.setNeedsDisplay()
@ -439,6 +556,7 @@ public final class AudioWaveformComponent: Component {
}*/ }*/
context.setFillColor(component.backgroundColor.mixedWith(component.foregroundColor, alpha: colorMixFraction).cgColor) context.setFillColor(component.backgroundColor.mixedWith(component.foregroundColor, alpha: colorMixFraction).cgColor)
context.setBlendMode(.copy)
let adjustedSampleHeight = sampleHeight - diff let adjustedSampleHeight = sampleHeight - diff
if adjustedSampleHeight.isLessThanOrEqualTo(sampleWidth) { if adjustedSampleHeight.isLessThanOrEqualTo(sampleWidth) {
@ -450,9 +568,9 @@ public final class AudioWaveformComponent: Component {
width: sampleWidth, width: sampleWidth,
height: adjustedSampleHeight - halfSampleWidth height: adjustedSampleHeight - halfSampleWidth
) )
context.fill(adjustedRect)
context.fillEllipse(in: CGRect(x: adjustedRect.minX, y: adjustedRect.minY - halfSampleWidth, width: sampleWidth, height: sampleWidth)) context.fillEllipse(in: CGRect(x: adjustedRect.minX, y: adjustedRect.minY - halfSampleWidth, width: sampleWidth, height: sampleWidth))
context.fillEllipse(in: CGRect(x: adjustedRect.minX, y: adjustedRect.maxY - halfSampleWidth, width: sampleWidth, height: sampleWidth)) context.fillEllipse(in: CGRect(x: adjustedRect.minX, y: adjustedRect.maxY - halfSampleWidth, width: sampleWidth, height: sampleWidth))
context.fill(adjustedRect)
} }
} }
} }

View File

@ -368,7 +368,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
} }
strongSelf.transcribeDisposable = nil strongSelf.transcribeDisposable = nil
strongSelf.audioTranscriptionState = .expanded strongSelf.audioTranscriptionState = .expanded
strongSelf.transcribedText = result strongSelf.transcribedText = result?.text
strongSelf.requestUpdateLayout(true) strongSelf.requestUpdateLayout(true)
}) })
} }
@ -962,7 +962,12 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
shimmerColor: isTranscriptionInProgress ? messageTheme.mediaActiveControlColor : nil, shimmerColor: isTranscriptionInProgress ? messageTheme.mediaActiveControlColor : nil,
samples: audioWaveform?.samples ?? Data(), samples: audioWaveform?.samples ?? Data(),
peak: audioWaveform?.peak ?? 0, peak: audioWaveform?.peak ?? 0,
status: strongSelf.playbackStatus.get() status: strongSelf.playbackStatus.get(),
seek: { timestamp in
if let strongSelf = self, let context = strongSelf.context, let message = strongSelf.message, let type = peerMessageMediaPlayerType(message) {
context.sharedContext.mediaManager.playlistControl(.seek(timestamp), type: type)
}
}
)), )),
environment: {}, environment: {},
containerSize: scrubbingFrame.size containerSize: scrubbingFrame.size
@ -1249,7 +1254,9 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
if self.message?.forwardInfo != nil { if self.message?.forwardInfo != nil {
fetchStatus = resourceStatus.fetchStatus fetchStatus = resourceStatus.fetchStatus
} }
(self.waveformView?.componentView as? AudioWaveformComponent.View)?.enableScrubbing = false
//self.waveformScrubbingNode?.enableScrubbing = false //self.waveformScrubbingNode?.enableScrubbing = false
switch fetchStatus { switch fetchStatus {
case let .Fetching(_, progress): case let .Fetching(_, progress):
let adjustedProgress = max(progress, 0.027) let adjustedProgress = max(progress, 0.027)
@ -1283,7 +1290,9 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
} }
} }
case let .playbackStatus(playbackStatus): case let .playbackStatus(playbackStatus):
(self.waveformView?.componentView as? AudioWaveformComponent.View)?.enableScrubbing = true
//self.waveformScrubbingNode?.enableScrubbing = true //self.waveformScrubbingNode?.enableScrubbing = true
switch playbackStatus { switch playbackStatus {
case .playing: case .playing:
state = .pause state = .pause

View File

@ -1846,7 +1846,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
guard let strongSelf = self, let node = node as? ContextExtractedContentContainingNode else { guard let strongSelf = self, let node = node as? ContextExtractedContentContainingNode else {
return return
} }
let _ = storedMessageFromSearch(account: strongSelf.context.account, message: message).start()
strongSelf.context.engine.messages.ensureMessagesAreLocallyAvailable(messages: [EngineMessage(message)])
var linkForCopying: String? var linkForCopying: String?
var currentSupernode: ASDisplayNode? = node var currentSupernode: ASDisplayNode? = node
@ -2196,11 +2197,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
var foundGalleryMessage: Message? var foundGalleryMessage: Message?
if let searchContentNode = strongSelf.searchDisplayController?.contentNode as? ChatHistorySearchContainerNode { if let searchContentNode = strongSelf.searchDisplayController?.contentNode as? ChatHistorySearchContainerNode {
if let galleryMessage = searchContentNode.messageForGallery(message.id) { if let galleryMessage = searchContentNode.messageForGallery(message.id) {
let _ = (strongSelf.context.account.postbox.transaction { transaction -> Void in strongSelf.context.engine.messages.ensureMessagesAreLocallyAvailable(messages: [EngineMessage(galleryMessage)])
if transaction.getMessage(galleryMessage.id) == nil {
storeMessageFromSearch(transaction: transaction, message: galleryMessage)
}
}).start()
foundGalleryMessage = galleryMessage foundGalleryMessage = galleryMessage
} }
} }
@ -3200,11 +3197,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
var foundGalleryMessage: Message? var foundGalleryMessage: Message?
if let searchContentNode = self.searchDisplayController?.contentNode as? ChatHistorySearchContainerNode { if let searchContentNode = self.searchDisplayController?.contentNode as? ChatHistorySearchContainerNode {
if let galleryMessage = searchContentNode.messageForGallery(id) { if let galleryMessage = searchContentNode.messageForGallery(id) {
let _ = (self.context.account.postbox.transaction { transaction -> Void in self.context.engine.messages.ensureMessagesAreLocallyAvailable(messages: [EngineMessage(galleryMessage)])
if transaction.getMessage(galleryMessage.id) == nil {
storeMessageFromSearch(transaction: transaction, message: galleryMessage)
}
}).start()
foundGalleryMessage = galleryMessage foundGalleryMessage = galleryMessage
} }
} }
@ -5754,7 +5747,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
} }
for childController in tabController.controllers { for childController in tabController.controllers {
if let chatListController = childController as? ChatListController { if let chatListController = childController as? ChatListController {
chatListController.maybeAskForPeerChatRemoval(peer: RenderedPeer(peer: peer), joined: false, deleteGloballyIfPossible: globally, completion: { [weak navigationController] deleted in chatListController.maybeAskForPeerChatRemoval(peer: EngineRenderedPeer(peer: EnginePeer(peer)), joined: false, deleteGloballyIfPossible: globally, completion: { [weak navigationController] deleted in
if deleted { if deleted {
navigationController?.popToRoot(animated: true) navigationController?.popToRoot(animated: true)
} }