From 3eead87254f1a7b4fddcad15566041702bad1e7a Mon Sep 17 00:00:00 2001 From: Ali <> Date: Thu, 23 Sep 2021 18:59:10 +0300 Subject: [PATCH] Refactoring --- .../Sources/AccountContext.swift | 4 +- submodules/AppLock/Sources/AppLock.swift | 1 - .../AvatarNode/Sources/PeerAvatar.swift | 7 +- submodules/ChatHistoryImportTasks/BUILD | 17 - .../Sources/ChatHistoryImportTask.swift | 4 - submodules/ChatImportUI/BUILD | 1 - .../Sources/ChatListController.swift | 12 +- .../Sources/ChatListControllerNode.swift | 63 ++- .../Sources/ChatListRecentPeersListItem.swift | 15 +- .../Sources/ChatListSearchContainerNode.swift | 105 ++-- .../Sources/ChatListSearchListPaneNode.swift | 496 +++++++++++------- .../Sources/ChatListSearchMediaNode.swift | 2 +- .../ChatListSearchPaneContainerNode.swift | 19 +- .../Sources/Node/ChatListItem.swift | 207 ++++---- .../Sources/Node/ChatListItemStrings.swift | 25 +- .../Sources/Node/ChatListNode.swift | 421 +++++++++------ .../Sources/Node/ChatListNodeEntries.swift | 195 +++---- .../Sources/Node/ChatListTypingNode.swift | 11 +- .../Sources/ContactListNode.swift | 2 +- .../Sources/ContactsSearchContainerNode.swift | 2 +- submodules/CountrySelectionUI/BUILD | 1 - ...onSequenceCountrySelectionController.swift | 1 - ...quenceCountrySelectionControllerNode.swift | 42 +- submodules/HashtagSearchUI/BUILD | 1 - .../Sources/HashtagSearchController.swift | 9 +- .../Sources/HashtagSearchControllerNode.swift | 5 +- .../ChannelMembersSearchContainerNode.swift | 4 +- .../Postbox/Sources/MetadataTable.swift | 9 - submodules/Postbox/Sources/NoticeTable.swift | 20 +- submodules/Postbox/Sources/Postbox.swift | 9 - .../Postbox/Sources/PostboxLogging.swift | 2 +- .../Utils/Decoder/AdaptedPostboxDecoder.swift | 2 +- .../BubbleSettingsController.swift | 2 +- .../TextSizeSelectionController.swift | 148 +++++- .../ThemeAccentColorControllerNode.swift | 125 ++++- .../Themes/ThemePreviewControllerNode.swift | 145 ++++- .../Sources/ShareSearchContainerNode.swift | 2 +- .../ShareItems/Sources/ShareItems.swift | 2 +- .../Sources/VoiceChatController.swift | 4 +- .../Sources/VoiceChatMainStageNode.swift | 4 +- .../Sources/VoiceChatTileItemNode.swift | 2 +- .../Sources/Account/AccountManager.swift | 2 + .../AccessChallengeDataView.swift | 1 + .../AccountManagerAtomicState.swift | 0 .../AccountManager/AccountManagerImpl.swift} | 1 + .../AccountManagerMetadataTable.swift | 1 + .../AccountManagerRecordTable.swift | 1 + .../AccountManagerSharedDataTable.swift | 1 + .../AccountManager}/AccountRecord.swift | 1 + .../AccountManager}/AccountRecordsView.swift | 0 .../AccountManager}/AccountSharedData.swift | 1 + .../AccountManager}/NoticeEntryView.swift | 1 + .../Sources/ApiUtils/TelegramMediaFile.swift | 7 +- .../PendingMessageUploadedContent.swift | 2 +- .../ManagedSecretChatOutgoingOperations.swift | 6 +- ...ecretChatIncomingDecryptedOperations.swift | 21 +- .../SyncCore/SyncCore_TelegramMediaFile.swift | 8 +- .../Contacts/TelegramEngineContacts.swift | 11 + .../TelegramEngine/Data/Messages.swift | 64 +++ .../TelegramEngine/Data/PeerSummary.swift | 106 +++- .../Data/TelegramEngineData.swift | 66 ++- .../TelegramEngine/Messages/ChatList.swift | 164 +++++- .../TelegramEngine/Messages/Media.swift | 33 ++ .../TelegramEngine/Messages/Message.swift | 83 ++- .../TelegramEngine/Messages/ReadState.swift | 23 - .../Sources/TelegramEngine/Peers/Peer.swift | 135 ++++- .../Peers/TelegramEnginePeers.swift | 4 - submodules/TelegramUI/BUILD | 1 - .../TelegramUI/Sources/ChatController.swift | 28 +- .../ChatInterfaceStateContextMenus.swift | 2 +- .../ChatMessageInteractiveFileNode.swift | 4 +- .../Sources/ChatMessageItemView.swift | 2 +- .../ChatRecentActionsControllerNode.swift | 4 +- .../ChatSearchResultsContollerNode.swift | 29 +- .../ContactMultiselectionControllerNode.swift | 2 +- .../Sources/PeerInfo/PeerInfoScreen.swift | 10 +- .../Sources/PeerSelectionControllerNode.swift | 130 +++-- .../Sources/SharedAccountContext.swift | 6 +- .../TelegramUI/Sources/TextLinkHandling.swift | 2 +- 79 files changed, 2106 insertions(+), 1005 deletions(-) delete mode 100644 submodules/ChatHistoryImportTasks/BUILD delete mode 100644 submodules/ChatHistoryImportTasks/Sources/ChatHistoryImportTask.swift rename submodules/{Postbox/Sources => TelegramCore/Sources/AccountManager}/AccessChallengeDataView.swift (97%) rename submodules/{Postbox/Sources => TelegramCore/Sources/AccountManager}/AccountManagerAtomicState.swift (100%) rename submodules/{Postbox/Sources/AccountManager.swift => TelegramCore/Sources/AccountManager/AccountManagerImpl.swift} (99%) rename submodules/{Postbox/Sources => TelegramCore/Sources/AccountManager}/AccountManagerMetadataTable.swift (99%) rename submodules/{Postbox/Sources => TelegramCore/Sources/AccountManager}/AccountManagerRecordTable.swift (99%) rename submodules/{Postbox/Sources => TelegramCore/Sources/AccountManager}/AccountManagerSharedDataTable.swift (98%) rename submodules/{Postbox/Sources => TelegramCore/Sources/AccountManager}/AccountRecord.swift (99%) rename submodules/{Postbox/Sources => TelegramCore/Sources/AccountManager}/AccountRecordsView.swift (100%) rename submodules/{Postbox/Sources => TelegramCore/Sources/AccountManager}/AccountSharedData.swift (98%) rename submodules/{Postbox/Sources => TelegramCore/Sources/AccountManager}/NoticeEntryView.swift (98%) delete mode 100644 submodules/TelegramCore/Sources/TelegramEngine/Messages/ReadState.swift diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index 86267a434e..4b02f70c9d 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -613,8 +613,8 @@ public protocol SharedAccountContext: AnyObject { func navigateToChatController(_ params: NavigateToChatControllerParams) func openLocationScreen(context: AccountContext, messageId: MessageId, navigationController: NavigationController) func openExternalUrl(context: AccountContext, urlContext: OpenURLContext, url: String, forceExternal: Bool, presentationData: PresentationData, navigationController: NavigationController?, dismissInput: @escaping () -> Void) - func chatAvailableMessageActions(postbox: Postbox, accountPeerId: PeerId, messageIds: Set) -> Signal - func chatAvailableMessageActions(postbox: Postbox, accountPeerId: PeerId, messageIds: Set, messages: [MessageId: Message], peers: [PeerId: Peer]) -> Signal + func chatAvailableMessageActions(postbox: Postbox, accountPeerId: EnginePeer.Id, messageIds: Set) -> Signal + func chatAvailableMessageActions(postbox: Postbox, accountPeerId: EnginePeer.Id, messageIds: Set, messages: [EngineMessage.Id: EngineMessage], peers: [EnginePeer.Id: EnginePeer]) -> Signal func resolveUrl(context: AccountContext, peerId: PeerId?, url: String, skipUrlAuth: Bool) -> Signal func openResolvedUrl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, openPeer: @escaping (PeerId, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)?, requestMessageActionUrlAuth: ((MessageActionUrlSubject) -> Void)?, joinVoiceChat: ((PeerId, String?, CachedChannelData.ActiveCall) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, contentContext: Any?) func openAddContact(context: AccountContext, firstName: String, lastName: String, phoneNumber: String, label: String, present: @escaping (ViewController, Any?) -> Void, pushController: @escaping (ViewController) -> Void, completed: @escaping () -> Void) diff --git a/submodules/AppLock/Sources/AppLock.swift b/submodules/AppLock/Sources/AppLock.swift index ccaceca2ac..94e973538b 100644 --- a/submodules/AppLock/Sources/AppLock.swift +++ b/submodules/AppLock/Sources/AppLock.swift @@ -1,6 +1,5 @@ import Foundation import UIKit -import Postbox import TelegramCore import Display import SwiftSignalKit diff --git a/submodules/AvatarNode/Sources/PeerAvatar.swift b/submodules/AvatarNode/Sources/PeerAvatar.swift index ca5cb90297..2427f8937f 100644 --- a/submodules/AvatarNode/Sources/PeerAvatar.swift +++ b/submodules/AvatarNode/Sources/PeerAvatar.swift @@ -1,7 +1,6 @@ import Foundation import UIKit import SwiftSignalKit -import Postbox import Display import ImageIO import TelegramCore @@ -85,10 +84,10 @@ public func peerAvatarImageData(account: Account, peerReference: PeerReference?, } } -public func peerAvatarCompleteImage(account: Account, peer: Peer, size: CGSize, round: Bool = true, font: UIFont = avatarPlaceholderFont(size: 13.0), drawLetters: Bool = true, fullSize: Bool = false, blurred: Bool = false) -> Signal { +public func peerAvatarCompleteImage(account: Account, peer: EnginePeer, size: CGSize, round: Bool = true, font: UIFont = avatarPlaceholderFont(size: 13.0), drawLetters: Bool = true, fullSize: Bool = false, blurred: Bool = false) -> Signal { let iconSignal: Signal - if let signal = peerAvatarImage(account: account, peerReference: PeerReference(peer), authorOfMessage: nil, representation: peer.profileImageRepresentations.first, displayDimensions: size, round: round, blurred: blurred, inset: 0.0, emptyColor: nil, synchronousLoad: fullSize) { - if fullSize, let fullSizeSignal = peerAvatarImage(account: account, peerReference: PeerReference(peer), authorOfMessage: nil, representation: peer.profileImageRepresentations.last, displayDimensions: size, emptyColor: nil, synchronousLoad: true) { + if let signal = peerAvatarImage(account: account, peerReference: PeerReference(peer._asPeer()), authorOfMessage: nil, representation: peer.profileImageRepresentations.first, displayDimensions: size, round: round, blurred: blurred, inset: 0.0, emptyColor: nil, synchronousLoad: fullSize) { + if fullSize, let fullSizeSignal = peerAvatarImage(account: account, peerReference: PeerReference(peer._asPeer()), authorOfMessage: nil, representation: peer.profileImageRepresentations.last, displayDimensions: size, emptyColor: nil, synchronousLoad: true) { iconSignal = combineLatest(.single(nil) |> then(signal), .single(nil) |> then(fullSizeSignal)) |> mapToSignal { thumbnailImage, fullSizeImage -> Signal in if let fullSizeImage = fullSizeImage { diff --git a/submodules/ChatHistoryImportTasks/BUILD b/submodules/ChatHistoryImportTasks/BUILD deleted file mode 100644 index b7be33ae9a..0000000000 --- a/submodules/ChatHistoryImportTasks/BUILD +++ /dev/null @@ -1,17 +0,0 @@ -load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library") - -swift_library( - name = "ChatHistoryImportTasks", - module_name = "ChatHistoryImportTasks", - srcs = glob([ - "Sources/**/*.swift", - ]), - copts = [ - "-warnings-as-errors", - ], - deps = [ - ], - visibility = [ - "//visibility:public", - ], -) diff --git a/submodules/ChatHistoryImportTasks/Sources/ChatHistoryImportTask.swift b/submodules/ChatHistoryImportTasks/Sources/ChatHistoryImportTask.swift deleted file mode 100644 index 66621571a3..0000000000 --- a/submodules/ChatHistoryImportTasks/Sources/ChatHistoryImportTask.swift +++ /dev/null @@ -1,4 +0,0 @@ -import Foundation - -public enum ChatHistoryImportTasks { -} diff --git a/submodules/ChatImportUI/BUILD b/submodules/ChatImportUI/BUILD index 4a4235c56a..0fe6a7232f 100644 --- a/submodules/ChatImportUI/BUILD +++ b/submodules/ChatImportUI/BUILD @@ -22,7 +22,6 @@ swift_library( "//submodules/PresentationDataUtils:PresentationDataUtils", "//submodules/RadialStatusNode:RadialStatusNode", "//submodules/AnimatedStickerNode:AnimatedStickerNode", - "//submodules/ChatHistoryImportTasks:ChatHistoryImportTasks", "//submodules/MimeTypes:MimeTypes", "//submodules/ConfettiEffect:ConfettiEffect", "//submodules/TelegramUniversalVideoContent:TelegramUniversalVideoContent", diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 8fb772c647..d9675b81bd 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -559,7 +559,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController } override public func loadDisplayNode() { - self.displayNode = ChatListControllerNode(context: self.context, groupId: self.groupId, filter: self.filter, previewing: self.previewing, controlsHistoryPreload: self.controlsHistoryPreload, presentationData: self.presentationData, controller: self) + self.displayNode = ChatListControllerNode(context: self.context, groupId: EngineChatList.Group(self.groupId), filter: self.filter, previewing: self.previewing, controlsHistoryPreload: self.controlsHistoryPreload, presentationData: self.presentationData, controller: self) self.chatListDisplayNode.navigationBar = self.navigationBar @@ -656,7 +656,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController self.chatListDisplayNode.containerNode.groupSelected = { [weak self] groupId in if let strongSelf = self { if let navigationController = strongSelf.navigationController as? NavigationController { - let chatListController = ChatListControllerImpl(context: strongSelf.context, groupId: groupId, controlsHistoryPreload: false, enableDebugActions: false) + let chatListController = ChatListControllerImpl(context: strongSelf.context, groupId: groupId._asGroup(), controlsHistoryPreload: false, enableDebugActions: false) chatListController.navigationPresentation = .master navigationController.pushViewController(chatListController) strongSelf.chatListDisplayNode.containerNode.currentItemNode.clearHighlightAnimated(true) @@ -683,7 +683,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController self.chatListDisplayNode.requestOpenMessageFromSearch = { [weak self] peer, messageId, deactivateOnAction in if let strongSelf = self { - strongSelf.openMessageFromSearchDisposable.set((storedMessageFromSearchPeer(account: strongSelf.context.account, peer: peer) + strongSelf.openMessageFromSearchDisposable.set((storedMessageFromSearchPeer(account: strongSelf.context.account, peer: peer._asPeer()) |> deliverOnMainQueue).start(next: { [weak strongSelf] actualPeerId in if let strongSelf = strongSelf { if let navigationController = strongSelf.navigationController as? NavigationController { @@ -707,7 +707,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController if let strongSelf = self { let storedPeer = strongSelf.context.account.postbox.transaction { transaction -> Void in if transaction.getPeer(peer.id) == nil { - updatePeers(transaction: transaction, peers: [peer], update: { previousPeer, updatedPeer in + updatePeers(transaction: transaction, peers: [peer._asPeer()], update: { previousPeer, updatedPeer in return updatedPeer }) } @@ -837,9 +837,9 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController switch item.content { case let .groupReference(groupId, _, _, _, _): - let chatListController = ChatListControllerImpl(context: strongSelf.context, groupId: groupId, controlsHistoryPreload: false, hideNetworkActivityStatus: true, previewing: true, enableDebugActions: false) + let chatListController = ChatListControllerImpl(context: strongSelf.context, groupId: groupId._asGroup(), controlsHistoryPreload: false, hideNetworkActivityStatus: true, previewing: true, enableDebugActions: false) chatListController.navigationPresentation = .master - let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatListController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController)), items: archiveContextMenuItems(context: strongSelf.context, groupId: groupId, chatListController: strongSelf) |> map { ContextController.Items(items: $0) }, gesture: gesture) + let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatListController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController)), items: archiveContextMenuItems(context: strongSelf.context, groupId: groupId._asGroup(), chatListController: strongSelf) |> map { ContextController.Items(items: $0) }, gesture: gesture) strongSelf.presentInGlobalOverlay(contextController) case let .peer(_, peer, _, _, _, _, _, _, promoInfo, _, _, _): let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peer.peerId), subject: nil, botStart: nil, mode: .standard(previewing: true)) diff --git a/submodules/ChatListUI/Sources/ChatListControllerNode.swift b/submodules/ChatListUI/Sources/ChatListControllerNode.swift index bb2f79857e..5c9e5f0d3f 100644 --- a/submodules/ChatListUI/Sources/ChatListControllerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListControllerNode.swift @@ -2,7 +2,6 @@ import Foundation import UIKit import AsyncDisplayKit import Display -import Postbox import TelegramCore import SwiftSignalKit import TelegramPresentationData @@ -178,16 +177,40 @@ private final class ChatListShimmerNode: ASDisplayNode { let chatListPresentationData = ChatListPresentationData(theme: presentationData.theme, fontSize: presentationData.chatFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: true) - let peer1 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(0)), accessHash: nil, firstName: "FirstName", lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) + let peer1: EnginePeer = .user(TelegramUser(id: EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: EnginePeer.Id.Id._internalFromInt64Value(0)), accessHash: nil, firstName: "FirstName", lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])) let timestamp1: Int32 = 100000 - let peers = SimpleDictionary() + let peers: [EnginePeer.Id: EnginePeer] = [:] let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _, _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in }, messageSelected: { _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in }, activateChatPreview: { _, _, gesture in gesture?.cancel() }, present: { _ in }) let items = (0 ..< 2).map { _ -> ChatListItem in - return ChatListItem(presentationData: chatListPresentationData, context: context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(messages: [Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: timestamp1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer1, text: "Text", attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])], peer: RenderedPeer(peer: peer1), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false))]), isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction) + let message = EngineMessage( + stableId: 0, + stableVersion: 0, + id: EngineMessage.Id(peerId: peer1.id, namespace: 0, id: 0), + globallyUniqueId: nil, + groupingKey: nil, + groupInfo: nil, + threadId: nil, + timestamp: timestamp1, + flags: [], + tags: [], + globalTags: [], + localTags: [], + forwardInfo: nil, + author: peer1, + text: "Text", + attributes: [], + media: [], + peers: peers, + associatedMessages: [:], + associatedMessageIds: [] + ) + let readState = EnginePeerReadCounters() + + return ChatListItem(presentationData: chatListPresentationData, context: context, peerGroupId: .root, filterData: nil, index: EngineChatList.Item.Index(pinningIndex: 0, messageIndex: EngineMessage.Index(id: EngineMessage.Id(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(messages: [message], peer: EngineRenderedPeer(peer: peer1), combinedReadState: readState, isRemovedFromTotalUnreadCount: false, presence: nil, hasUnseenMentions: false, draftState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction) } var itemNodes: [ChatListItemNode] = [] @@ -268,7 +291,7 @@ private final class ChatListContainerItemNode: ASDisplayNode { private var validLayout: (CGSize, UIEdgeInsets, CGFloat)? - init(context: AccountContext, groupId: PeerGroupId, filter: ChatListFilter?, previewing: Bool, controlsHistoryPreload: Bool, presentationData: PresentationData, becameEmpty: @escaping (ChatListFilter?) -> Void, emptyAction: @escaping (ChatListFilter?) -> Void) { + init(context: AccountContext, groupId: EngineChatList.Group, filter: ChatListFilter?, previewing: Bool, controlsHistoryPreload: Bool, presentationData: PresentationData, becameEmpty: @escaping (ChatListFilter?) -> Void, emptyAction: @escaping (ChatListFilter?) -> Void) { self.context = context self.presentationData = presentationData self.becameEmpty = becameEmpty @@ -396,7 +419,7 @@ private final class ChatListContainerItemNode: ASDisplayNode { final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate { private let context: AccountContext - private let groupId: PeerGroupId + private let groupId: EngineChatList.Group private let previewing: Bool private let controlsHistoryPreload: Bool private let filterBecameEmpty: (ChatListFilter?) -> Void @@ -525,18 +548,18 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate { var presentAlert: ((String) -> Void)? var present: ((ViewController) -> Void)? var toggleArchivedFolderHiddenByDefault: (() -> Void)? - var hidePsa: ((PeerId) -> Void)? - var deletePeerChat: ((PeerId, Bool) -> Void)? - var peerSelected: ((Peer, Bool, Bool, ChatListNodeEntryPromoInfo?) -> Void)? - var groupSelected: ((PeerGroupId) -> Void)? - var updatePeerGrouping: ((PeerId, Bool) -> Void)? + var hidePsa: ((EnginePeer.Id) -> Void)? + var deletePeerChat: ((EnginePeer.Id, Bool) -> Void)? + var peerSelected: ((EnginePeer, Bool, Bool, ChatListNodeEntryPromoInfo?) -> Void)? + var groupSelected: ((EngineChatList.Group) -> Void)? + var updatePeerGrouping: ((EnginePeer.Id, Bool) -> Void)? var contentOffsetChanged: ((ListViewVisibleContentOffset) -> Void)? var contentScrollingEnded: ((ListView) -> Bool)? var activateChatPreview: ((ChatListItem, ASDisplayNode, ContextGesture?) -> Void)? - var addedVisibleChatsWithPeerIds: (([PeerId]) -> Void)? + var addedVisibleChatsWithPeerIds: (([EnginePeer.Id]) -> Void)? var didBeginSelectingChats: (() -> Void)? - init(context: AccountContext, groupId: PeerGroupId, previewing: Bool, controlsHistoryPreload: Bool, presentationData: PresentationData, filterBecameEmpty: @escaping (ChatListFilter?) -> Void, filterEmptyAction: @escaping (ChatListFilter?) -> Void) { + init(context: AccountContext, groupId: EngineChatList.Group, previewing: Bool, controlsHistoryPreload: Bool, presentationData: PresentationData, filterBecameEmpty: @escaping (ChatListFilter?) -> Void, filterEmptyAction: @escaping (ChatListFilter?) -> Void) { self.context = context self.groupId = groupId self.previewing = previewing @@ -983,7 +1006,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate { final class ChatListControllerNode: ASDisplayNode { private let context: AccountContext - private let groupId: PeerGroupId + private let groupId: EngineChatList.Group private var presentationData: PresentationData let containerNode: ChatListContainerNode @@ -1005,11 +1028,11 @@ final class ChatListControllerNode: ASDisplayNode { private var containerLayout: (ContainerViewLayout, CGFloat, CGFloat, CGFloat)? var requestDeactivateSearch: (() -> Void)? - var requestOpenPeerFromSearch: ((Peer, Bool) -> Void)? - var requestOpenRecentPeerOptions: ((Peer) -> Void)? - var requestOpenMessageFromSearch: ((Peer, MessageId, Bool) -> Void)? + var requestOpenPeerFromSearch: ((EnginePeer, Bool) -> Void)? + var requestOpenRecentPeerOptions: ((EnginePeer) -> Void)? + var requestOpenMessageFromSearch: ((EnginePeer, EngineMessage.Id, Bool) -> Void)? var requestAddContact: ((String) -> Void)? - var peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)? + var peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)? var dismissSelfIfCompletedPresentation: (() -> Void)? var isEmptyUpdated: ((Bool) -> Void)? var emptyListAction: (() -> Void)? @@ -1017,7 +1040,7 @@ final class ChatListControllerNode: ASDisplayNode { let debugListView = ListView() - init(context: AccountContext, groupId: PeerGroupId, filter: ChatListFilter?, previewing: Bool, controlsHistoryPreload: Bool, presentationData: PresentationData, controller: ChatListControllerImpl) { + init(context: AccountContext, groupId: EngineChatList.Group, filter: ChatListFilter?, previewing: Bool, controlsHistoryPreload: Bool, presentationData: PresentationData, controller: ChatListControllerImpl) { self.context = context self.groupId = groupId self.presentationData = presentationData @@ -1051,7 +1074,7 @@ final class ChatListControllerNode: ASDisplayNode { guard let strongSelf = self else { return } - if case .group = strongSelf.groupId { + if case .archive = strongSelf.groupId { strongSelf.dismissSelfIfCompletedPresentation?() } } diff --git a/submodules/ChatListUI/Sources/ChatListRecentPeersListItem.swift b/submodules/ChatListUI/Sources/ChatListRecentPeersListItem.swift index dc71fbd908..4bef020a8b 100644 --- a/submodules/ChatListUI/Sources/ChatListRecentPeersListItem.swift +++ b/submodules/ChatListUI/Sources/ChatListRecentPeersListItem.swift @@ -1,7 +1,6 @@ import Foundation import UIKit import AsyncDisplayKit -import Postbox import Display import SwiftSignalKit import TelegramCore @@ -14,13 +13,13 @@ class ChatListRecentPeersListItem: ListViewItem { let theme: PresentationTheme let strings: PresentationStrings let context: AccountContext - let peers: [Peer] - let peerSelected: (Peer) -> Void - let peerContextAction: (Peer, ASDisplayNode, ContextGesture?) -> Void + let peers: [EnginePeer] + let peerSelected: (EnginePeer) -> Void + let peerContextAction: (EnginePeer, ASDisplayNode, ContextGesture?) -> Void let header: ListViewItemHeader? - init(theme: PresentationTheme, strings: PresentationStrings, context: AccountContext, peers: [Peer], peerSelected: @escaping (Peer) -> Void, peerContextAction: @escaping (Peer, ASDisplayNode, ContextGesture?) -> Void) { + init(theme: PresentationTheme, strings: PresentationStrings, context: AccountContext, peers: [EnginePeer], peerSelected: @escaping (EnginePeer) -> Void, peerContextAction: @escaping (EnginePeer, ASDisplayNode, ContextGesture?) -> Void) { self.theme = theme self.strings = strings self.context = context @@ -122,9 +121,9 @@ class ChatListRecentPeersListItemNode: ListViewItemNode { peersNode.updateThemeAndStrings(theme: item.theme, strings: item.strings) } else { peersNode = ChatListSearchRecentPeersNode(context: item.context, theme: item.theme, mode: .list, strings: item.strings, peerSelected: { peer in - self?.item?.peerSelected(peer._asPeer()) + self?.item?.peerSelected(peer) }, peerContextAction: { peer, node, gesture in - self?.item?.peerContextAction(peer._asPeer(), node, gesture) + self?.item?.peerContextAction(peer, node, gesture) }, isPeerSelected: { _ in return false }) @@ -161,7 +160,7 @@ class ChatListRecentPeersListItemNode: ListViewItemNode { } } - func viewAndPeerAtPoint(_ point: CGPoint) -> (UIView, PeerId)? { + func viewAndPeerAtPoint(_ point: CGPoint) -> (UIView, EnginePeer.Id)? { if let peersNode = self.peersNode { let adjustedLocation = self.convert(point, to: peersNode) if let result = peersNode.viewAndPeerAtPoint(adjustedLocation) { diff --git a/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift b/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift index 49be4fa6eb..5f0698bedb 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift @@ -3,7 +3,6 @@ import UIKit import AsyncDisplayKit import Display import SwiftSignalKit -import Postbox import TelegramCore import TelegramPresentationData import TelegramUIPreferences @@ -38,21 +37,21 @@ private enum ChatListTokenId: Int32 { } final class ChatListSearchInteraction { - let openPeer: (Peer, Peer?, Bool) -> Void - let openDisabledPeer: (Peer) -> Void - let openMessage: (Peer, MessageId, Bool) -> Void + let openPeer: (EnginePeer, EnginePeer?, Bool) -> Void + let openDisabledPeer: (EnginePeer) -> Void + let openMessage: (EnginePeer, EngineMessage.Id, Bool) -> Void let openUrl: (String) -> Void let clearRecentSearch: () -> Void let addContact: (String) -> Void - let toggleMessageSelection: (MessageId, Bool) -> Void - let messageContextAction: ((Message, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void) - let mediaMessageContextAction: ((Message, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void) - let peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)? + let toggleMessageSelection: (EngineMessage.Id, Bool) -> Void + let messageContextAction: ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void) + let mediaMessageContextAction: ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void) + let peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)? let present: (ViewController, Any?) -> Void let dismissInput: () -> Void - let getSelectedMessageIds: () -> Set? + let getSelectedMessageIds: () -> Set? - init(openPeer: @escaping (Peer, Peer?, Bool) -> Void, openDisabledPeer: @escaping (Peer) -> Void, openMessage: @escaping (Peer, MessageId, Bool) -> Void, openUrl: @escaping (String) -> Void, clearRecentSearch: @escaping () -> Void, addContact: @escaping (String) -> Void, toggleMessageSelection: @escaping (MessageId, Bool) -> Void, messageContextAction: @escaping ((Message, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void), mediaMessageContextAction: @escaping ((Message, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void), peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, getSelectedMessageIds: @escaping () -> Set?) { + init(openPeer: @escaping (EnginePeer, EnginePeer?, Bool) -> Void, openDisabledPeer: @escaping (EnginePeer) -> Void, openMessage: @escaping (EnginePeer, EngineMessage.Id, Bool) -> Void, openUrl: @escaping (String) -> Void, clearRecentSearch: @escaping () -> Void, addContact: @escaping (String) -> Void, toggleMessageSelection: @escaping (EngineMessage.Id, Bool) -> Void, messageContextAction: @escaping ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void), mediaMessageContextAction: @escaping ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void), peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, getSelectedMessageIds: @escaping () -> Set?) { self.openPeer = openPeer self.openDisabledPeer = openDisabledPeer self.openMessage = openMessage @@ -70,9 +69,9 @@ final class ChatListSearchInteraction { } private struct ChatListSearchContainerNodeSearchState: Equatable { - var selectedMessageIds: Set? + var selectedMessageIds: Set? - func withUpdatedSelectedMessageIds(_ selectedMessageIds: Set?) -> ChatListSearchContainerNodeSearchState { + func withUpdatedSelectedMessageIds(_ selectedMessageIds: Set?) -> ChatListSearchContainerNodeSearchState { return ChatListSearchContainerNodeSearchState(selectedMessageIds: selectedMessageIds) } } @@ -80,10 +79,10 @@ private struct ChatListSearchContainerNodeSearchState: Equatable { public final class ChatListSearchContainerNode: SearchDisplayControllerContentNode { private let context: AccountContext private let peersFilter: ChatListNodePeersFilter - private let groupId: PeerGroupId + private let groupId: EngineChatList.Group private let displaySearchFilters: Bool private var interaction: ChatListSearchInteraction? - private let openMessage: (Peer, MessageId, Bool) -> Void + private let openMessage: (EnginePeer, EngineMessage.Id, Bool) -> Void private let navigationController: NavigationController? let filterContainerNode: ChatListSearchFiltersContainerNode @@ -124,7 +123,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo private var validLayout: (ContainerViewLayout, CGFloat)? - public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, filter: ChatListNodePeersFilter, groupId: PeerGroupId, displaySearchFilters: Bool, initialFilter: ChatListSearchFilter = .chats, openPeer originalOpenPeer: @escaping (Peer, Peer?, Bool) -> Void, openDisabledPeer: @escaping (Peer) -> Void, openRecentPeerOptions: @escaping (Peer) -> Void, openMessage originalOpenMessage: @escaping (Peer, MessageId, Bool) -> Void, addContact: ((String) -> Void)?, peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, present: @escaping (ViewController, Any?) -> Void, presentInGlobalOverlay: @escaping (ViewController, Any?) -> Void, navigationController: NavigationController?) { + public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, filter: ChatListNodePeersFilter, groupId: EngineChatList.Group, displaySearchFilters: Bool, initialFilter: ChatListSearchFilter = .chats, openPeer originalOpenPeer: @escaping (EnginePeer, EnginePeer?, Bool) -> Void, openDisabledPeer: @escaping (EnginePeer) -> Void, openRecentPeerOptions: @escaping (EnginePeer) -> Void, openMessage originalOpenMessage: @escaping (EnginePeer, EngineMessage.Id, Bool) -> Void, addContact: ((String) -> Void)?, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, present: @escaping (ViewController, Any?) -> Void, presentInGlobalOverlay: @escaping (ViewController, Any?) -> Void, navigationController: NavigationController?) { self.context = context self.peersFilter = filter self.groupId = groupId @@ -224,7 +223,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo present(c, a) }, dismissInput: { [weak self] in self?.dismissInput() - }, getSelectedMessageIds: { [weak self] () -> Set? in + }, getSelectedMessageIds: { [weak self] () -> Set? in if let strongSelf = self { return strongSelf.stateValue.selectedMessageIds } else { @@ -304,11 +303,11 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo self.filterContainerNode.filterPressed?(initialFilter) let suggestedPeers = self.searchQuery.get() - |> mapToSignal { query -> Signal<[Peer], NoError> in + |> mapToSignal { query -> Signal<[EnginePeer], NoError> in if let query = query { return context.account.postbox.searchPeers(query: query.lowercased()) - |> map { local -> [Peer] in - return Array(local.compactMap { $0.peer }.prefix(10)) + |> map { local -> [EnginePeer] in + return Array(local.compactMap { $0.peer }.prefix(10).map(EnginePeer.init)) } } else { return .single([]) @@ -319,12 +318,12 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo |> take(1) self.suggestedFiltersDisposable.set((combineLatest(suggestedPeers, self.suggestedDates.get(), self.selectedFilterKeyPromise.get(), self.searchQuery.get(), accountPeer) - |> mapToSignal { peers, dates, selectedFilter, searchQuery, accountPeer -> Signal<([Peer], [(Date?, Date, String?)], ChatListSearchFilterEntryId?, String?, Peer?), NoError> in + |> mapToSignal { peers, dates, selectedFilter, searchQuery, accountPeer -> Signal<([EnginePeer], [(Date?, Date, String?)], ChatListSearchFilterEntryId?, String?, EnginePeer?), NoError> in if searchQuery?.isEmpty ?? true { - return .single((peers, dates, selectedFilter, searchQuery, accountPeer)) + return .single((peers, dates, selectedFilter, searchQuery, EnginePeer(accountPeer))) } else { return (.complete() |> delay(0.25, queue: Queue.mainQueue())) - |> then(.single((peers, dates, selectedFilter, searchQuery, accountPeer))) + |> then(.single((peers, dates, selectedFilter, searchQuery, EnginePeer(accountPeer)))) } } |> map { peers, dates, selectedFilter, searchQuery, accountPeer -> [ChatListSearchFilter] in var suggestedFilters: [ChatListSearchFilter] = [] @@ -340,7 +339,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo } let presentationData = context.sharedContext.currentPresentationData.with { $0 } - var existingPeerIds = Set() + var existingPeerIds = Set() var peers = peers if let accountPeer = accountPeer, let lowercasedQuery = searchQuery?.lowercased(), lowercasedQuery.count > 1 && (presentationData.strings.DialogList_SavedMessages.lowercased().hasPrefix(lowercasedQuery) || "saved messages".hasPrefix(lowercasedQuery)) { peers.insert(accountPeer, at: 0) @@ -354,7 +353,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo let isGroup: Bool if peer.id.namespace == Namespaces.Peer.SecretChat { continue - } else if let channel = peer as? TelegramChannel, case .group = channel.info { + } else if case let .channel(channel) = peer, case .group = channel.info { isGroup = true } else if peer.id.namespace == Namespaces.Peer.CloudGroup { isGroup = true @@ -362,8 +361,8 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo isGroup = false } - var title: String = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - var compactDisplayTitle = EnginePeer(peer).compactDisplayTitle + var title: String = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + var compactDisplayTitle = peer.compactDisplayTitle if peer.id == accountPeer?.id { title = presentationData.strings.DialogList_SavedMessages compactDisplayTitle = title @@ -566,11 +565,11 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo guard let strongSelf = self, let messageIds = strongSelf.stateValue.selectedMessageIds, !messageIds.isEmpty else { return } - let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Message] in - var messages: [Message] = [] + let _ = (strongSelf.context.account.postbox.transaction { transaction -> [EngineMessage] in + var messages: [EngineMessage] = [] for id in messageIds { if let message = transaction.getMessage(id) { - messages.append(message) + messages.append(EngineMessage(message)) } } return messages @@ -579,7 +578,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo if let strongSelf = self, !messages.isEmpty { let shareController = ShareController(context: strongSelf.context, subject: .messages(messages.sorted(by: { lhs, rhs in return lhs.index < rhs.index - })), externalShare: true, immediateExternalShare: true) + }).map({ $0._asMessage() })), externalShare: true, immediateExternalShare: true) strongSelf.dismissInput() strongSelf.present?(shareController, nil) } @@ -641,12 +640,12 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo self.paneContainerNode.update(size: CGSize(width: layout.size.width, height: layout.size.height - topInset), sideInset: layout.safeInsets.left, bottomInset: bottomInset, visibleHeight: layout.size.height - topInset, presentationData: self.presentationData, availablePanes: availablePanes, transition: transition) } - private var currentMessages: ([PeerId: Peer], [MessageId: Message]) { - var peers: [PeerId: Peer] = [:] - let messages: [MessageId: Message] = self.paneContainerNode.allCurrentMessages() + private var currentMessages: ([EnginePeer.Id: EnginePeer], [EngineMessage.Id: EngineMessage]) { + var peers: [EnginePeer.Id: EnginePeer] = [:] + let messages: [EngineMessage.Id: EngineMessage] = self.paneContainerNode.allCurrentMessages() for (_, message) in messages { for (_, peer) in message.peers { - peers[peer.id] = peer + peers[peer.id] = EnginePeer(peer) } } return (peers, messages) @@ -665,11 +664,11 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo let _ = self.paneContainerNode.scrollToTop() } - private func messageContextAction(_ message: Message, node: ASDisplayNode?, rect: CGRect?, gesture anyRecognizer: UIGestureRecognizer?) { + private func messageContextAction(_ message: EngineMessage, node: ASDisplayNode?, rect: CGRect?, gesture anyRecognizer: UIGestureRecognizer?) { guard let node = node as? ContextExtractedContentContainingNode else { return } - let _ = storedMessageFromSearch(account: self.context.account, message: message).start() + let _ = storedMessageFromSearch(account: self.context.account, message: message._asMessage()).start() var linkForCopying: String? var currentSupernode: ASDisplayNode? = node @@ -714,7 +713,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo }))) items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.SharedMedia_ViewInChat, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in c.dismiss(completion: { [weak self] in - self?.openMessage(message.peers[message.id.peerId]!, message.id, false) + self?.openMessage(EnginePeer(message.peers[message.id.peerId]!), message.id, false) }) }))) @@ -741,9 +740,9 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo self.presentInGlobalOverlay?(controller, nil) } - private func mediaMessageContextAction(_ message: Message, node: ASDisplayNode?, rect: CGRect?, gesture anyRecognizer: UIGestureRecognizer?) { + private func mediaMessageContextAction(_ message: EngineMessage, node: ASDisplayNode?, rect: CGRect?, gesture anyRecognizer: UIGestureRecognizer?) { let gesture: ContextGesture? = anyRecognizer as? ContextGesture - let _ = (chatMediaListPreviewControllerData(context: self.context, chatLocation: .peer(message.id.peerId), chatLocationContextHolder: Atomic(value: nil), message: message, standalone: true, reverseMessageGalleryOrder: false, navigationController: self.navigationController) + let _ = (chatMediaListPreviewControllerData(context: self.context, chatLocation: .peer(message.id.peerId), chatLocationContextHolder: Atomic(value: nil), message: message._asMessage(), standalone: true, reverseMessageGalleryOrder: false, navigationController: self.navigationController) |> deliverOnMainQueue).start(next: { [weak self] previewData in guard let strongSelf = self else { gesture?.cancel() @@ -760,7 +759,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo items.append(.action(ContextMenuActionItem(text: strings.SharedMedia_ViewInChat, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor) }, action: { c, f in c.dismiss(completion: { - self?.openMessage(message.peers[message.id.peerId]!, message.id, false) + self?.openMessage(EnginePeer(message.peers[message.id.peerId]!), message.id, false) }) }))) @@ -811,13 +810,13 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo self.setQuery?(nil, [], self.searchQueryValue ?? "") } - func deleteMessages(messageIds: Set?) { + func deleteMessages(messageIds: Set?) { if let messageIds = messageIds ?? self.stateValue.selectedMessageIds, !messageIds.isEmpty { let (peers, messages) = self.currentMessages let _ = (self.context.account.postbox.transaction { transaction -> Void in for id in messageIds { if transaction.getMessage(id) == nil, let message = messages[id] { - storeMessageFromSearch(transaction: transaction, message: message) + storeMessageFromSearch(transaction: transaction, message: message._asMessage()) } } }).start() @@ -878,14 +877,14 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo } } - func forwardMessages(messageIds: Set?) { + func forwardMessages(messageIds: Set?) { let messageIds = messageIds ?? self.stateValue.selectedMessageIds if let messageIds = messageIds, !messageIds.isEmpty { let messages = self.paneContainerNode.allCurrentMessages() let _ = (self.context.account.postbox.transaction { transaction -> Void in for id in messageIds { if transaction.getMessage(id) == nil, let message = messages[id] { - storeMessageFromSearch(transaction: transaction, message: message) + storeMessageFromSearch(transaction: transaction, message: message._asMessage()) } } }).start() @@ -902,7 +901,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo let inputText = convertMarkdownToAttributes(messageText) for text in breakChatInputText(trimChatInputText(inputText)) { if text.length != 0 { - var attributes: [MessageAttribute] = [] + var attributes: [EngineMessage.Attribute] = [] let entities = generateTextEntities(text.string, enabledTypes: .all, currentEntities: generateChatInputTextEntities(text)) if !entities.isEmpty { attributes.append(TextEntitiesMessageAttribute(entities: entities)) @@ -912,14 +911,14 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo } } - var attributes: [MessageAttribute] = [] + var attributes: [EngineMessage.Attribute] = [] attributes.append(ForwardOptionsMessageAttribute(hideNames: forwardOptions?.hideNames == true, hideCaptions: forwardOptions?.hideCaptions == true)) result.append(contentsOf: messageIds.map { messageId -> EnqueueMessage in return .forward(source: messageId, grouping: .auto, attributes: attributes, correlationId: nil) }) - var displayPeers: [Peer] = [] + var displayPeers: [EnginePeer] = [] for peer in peers { let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peer.id, messages: result) |> deliverOnMainQueue).start(next: { messageIds in @@ -947,10 +946,10 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo }) if let secretPeer = peer as? TelegramSecretChat { if let peer = peerMap[secretPeer.regularPeerId] { - displayPeers.append(peer) + displayPeers.append(EnginePeer(peer)) } } else { - displayPeers.append(peer) + displayPeers.append(EnginePeer(peer)) } } @@ -962,14 +961,14 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo savedMessages = true } else { if displayPeers.count == 1, let peer = displayPeers.first { - let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_Chat_One(peerName).string : presentationData.strings.Conversation_ForwardTooltip_Chat_Many(peerName).string } else if displayPeers.count == 2, let firstPeer = displayPeers.first, let secondPeer = displayPeers.last { - let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(firstPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(secondPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).string : presentationData.strings.Conversation_ForwardTooltip_TwoChats_Many(firstPeerName, secondPeerName).string } else if let peer = displayPeers.first { - let peerName = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_ManyChats_One(peerName, "\(displayPeers.count - 1)").string : presentationData.strings.Conversation_ForwardTooltip_ManyChats_Many(peerName, "\(displayPeers.count - 1)").string } else { text = "" diff --git a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift index da2a79ab18..2c1a10eca8 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift @@ -2,7 +2,6 @@ import AsyncDisplayKit import Display import TelegramCore import SwiftSignalKit -import Postbox import TelegramPresentationData import PresentationDataUtils import AccountContext @@ -30,11 +29,11 @@ import UndoUI private enum ChatListRecentEntryStableId: Hashable { case topPeers - case peerId(PeerId) + case peerId(EnginePeer.Id) } private enum ChatListRecentEntry: Comparable, Identifiable { - case topPeers([Peer], PresentationTheme, PresentationStrings) + case topPeers([EnginePeer], PresentationTheme, PresentationStrings) case peer(index: Int, peer: RecentlySearchedPeer, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, PresentationPersonNameOrder) var stableId: ChatListRecentEntryStableId { @@ -50,14 +49,9 @@ private enum ChatListRecentEntry: Comparable, Identifiable { switch lhs { case let .topPeers(lhsPeers, lhsTheme, lhsStrings): if case let .topPeers(rhsPeers, rhsTheme, rhsStrings) = rhs { - if lhsPeers.count != rhsPeers.count { + if lhsPeers != rhsPeers { return false } - for i in 0 ..< lhsPeers.count { - if !lhsPeers[i].isEqual(rhsPeers[i]) { - return false - } - } if lhsTheme !== rhsTheme { return false } @@ -91,7 +85,7 @@ private enum ChatListRecentEntry: Comparable, Identifiable { } } - func item(context: AccountContext, presentationData: ChatListPresentationData, filter: ChatListNodePeersFilter, peerSelected: @escaping (Peer) -> Void, disabledPeerSelected: @escaping (Peer) -> Void, peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, clearRecentlySearchedPeers: @escaping () -> Void, deletePeer: @escaping (PeerId) -> Void) -> ListViewItem { + func item(context: AccountContext, presentationData: ChatListPresentationData, filter: ChatListNodePeersFilter, peerSelected: @escaping (EnginePeer) -> Void, disabledPeerSelected: @escaping (EnginePeer) -> Void, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, clearRecentlySearchedPeers: @escaping () -> Void, deletePeer: @escaping (EnginePeer.Id) -> Void) -> ListViewItem { switch self { case let .topPeers(peers, theme, strings): return ChatListRecentPeersListItem(theme: theme, strings: strings, context: context, peers: peers, peerSelected: { peer in @@ -104,11 +98,11 @@ private enum ChatListRecentEntry: Comparable, Identifiable { } }) case let .peer(_, peer, theme, strings, timeFormat, nameSortOrder, nameDisplayOrder): - let primaryPeer: Peer - var chatPeer: Peer? - let maybeChatPeer = peer.peer.peers[peer.peer.peerId]! - if let associatedPeerId = maybeChatPeer.associatedPeerId, let associatedPeer = peer.peer.peers[associatedPeerId] { - primaryPeer = associatedPeer + let primaryPeer: EnginePeer + var chatPeer: EnginePeer? + let maybeChatPeer = EnginePeer(peer.peer.peers[peer.peer.peerId]!) + if let associatedPeerId = maybeChatPeer._asPeer().associatedPeerId, let associatedPeer = peer.peer.peers[associatedPeerId] { + primaryPeer = EnginePeer(associatedPeer) chatPeer = maybeChatPeer } else { primaryPeer = maybeChatPeer @@ -118,14 +112,17 @@ private enum ChatListRecentEntry: Comparable, Identifiable { var enabled = true if filter.contains(.onlyWriteable) { if let peer = chatPeer { - enabled = canSendMessagesToPeer(peer) + enabled = canSendMessagesToPeer(peer._asPeer()) } else { - enabled = canSendMessagesToPeer(primaryPeer) + enabled = canSendMessagesToPeer(primaryPeer._asPeer()) } } if filter.contains(.onlyPrivateChats) { if let peer = chatPeer { - if !(peer is TelegramUser || peer is TelegramSecretChat) { + switch peer { + case .user, .secretChat: + break + default: enabled = false } } else { @@ -134,8 +131,8 @@ private enum ChatListRecentEntry: Comparable, Identifiable { } if filter.contains(.onlyGroups) { if let peer = chatPeer { - if let _ = peer as? TelegramGroup { - } else if let peer = peer as? TelegramChannel, case .group = peer.info { + if case .legacyGroup = peer { + } else if case let .channel(peer) = peer, case .group = peer.info { } else { enabled = false } @@ -145,7 +142,7 @@ private enum ChatListRecentEntry: Comparable, Identifiable { } if filter.contains(.excludeChannels) { - if let channel = primaryPeer as? TelegramChannel, case .broadcast = channel.info { + if case let .channel(channel) = primaryPeer, case .broadcast = channel.info { enabled = false } } @@ -153,8 +150,8 @@ private enum ChatListRecentEntry: Comparable, Identifiable { let status: ContactsPeerItemStatus if primaryPeer.id.isReplies { status = .none - } else if let user = primaryPeer as? TelegramUser { - let servicePeer = isServicePeer(primaryPeer) + } else if case let .user(user) = primaryPeer { + let servicePeer = isServicePeer(primaryPeer._asPeer()) if user.flags.contains(.isSupport) && !servicePeer { status = .custom(string: strings.Bot_GenericSupportStatus, multiline: false) } else if let _ = user.botInfo { @@ -165,9 +162,9 @@ private enum ChatListRecentEntry: Comparable, Identifiable { } else { status = .none } - } else if let group = primaryPeer as? TelegramGroup { + } else if case let .legacyGroup(group) = primaryPeer { status = .custom(string: strings.GroupInfo_ParticipantCount(Int32(group.participantCount)), multiline: false) - } else if let channel = primaryPeer as? TelegramChannel { + } else if case let .channel(channel) = primaryPeer { if case .group = channel.info { if let count = peer.subpeerSummary?.count { status = .custom(string: strings.GroupInfo_ParticipantCount(Int32(count)), multiline: false) @@ -194,20 +191,20 @@ private enum ChatListRecentEntry: Comparable, Identifiable { badge = ContactsPeerItemBadge(count: peer.unreadCount, type: isMuted ? .inactive : .active) } - return ContactsPeerItem(presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .generalSearch, peer: .peer(peer: EnginePeer(primaryPeer), chatPeer: chatPeer.flatMap(EnginePeer.init)), status: status, badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: ChatListSearchItemHeader(type: .recentPeers, theme: theme, strings: strings, actionTitle: strings.WebSearch_RecentSectionClear, action: { + return ContactsPeerItem(presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .generalSearch, peer: .peer(peer: primaryPeer, chatPeer: chatPeer), status: status, badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: ChatListSearchItemHeader(type: .recentPeers, theme: theme, strings: strings, actionTitle: strings.WebSearch_RecentSectionClear, action: { clearRecentlySearchedPeers() }), action: { _ in if let chatPeer = peer.peer.peers[peer.peer.peerId] { - peerSelected(chatPeer) + peerSelected(EnginePeer(chatPeer)) } }, disabledAction: { _ in if let chatPeer = peer.peer.peers[peer.peer.peerId] { - disabledPeerSelected(chatPeer) + disabledPeerSelected(EnginePeer(chatPeer)) } }, deletePeer: deletePeer, contextAction: peerContextAction.flatMap { peerContextAction in return { node, gesture in if let chatPeer = peer.peer.peers[peer.peer.peerId] { - peerContextAction(chatPeer, .recentSearch, node, gesture) + peerContextAction(EnginePeer(chatPeer), .recentSearch, node, gesture) } else { gesture?.cancel() } @@ -218,39 +215,10 @@ private enum ChatListRecentEntry: Comparable, Identifiable { } public enum ChatListSearchEntryStableId: Hashable { - case localPeerId(PeerId) - case globalPeerId(PeerId) - case messageId(MessageId) + case localPeerId(EnginePeer.Id) + case globalPeerId(EnginePeer.Id) + case messageId(EngineMessage.Id) case addContact - - public static func ==(lhs: ChatListSearchEntryStableId, rhs: ChatListSearchEntryStableId) -> Bool { - switch lhs { - case let .localPeerId(peerId): - if case .localPeerId(peerId) = rhs { - return true - } else { - return false - } - case let .globalPeerId(peerId): - if case .globalPeerId(peerId) = rhs { - return true - } else { - return false - } - case let .messageId(messageId): - if case .messageId(messageId) = rhs { - return true - } else { - return false - } - case .addContact: - if case .addContact = rhs { - return true - } else { - return false - } - } - } } public enum ChatListSearchSectionExpandType { @@ -260,9 +228,9 @@ public enum ChatListSearchSectionExpandType { } public enum ChatListSearchEntry: Comparable, Identifiable { - case localPeer(Peer, Peer?, (Int32, Bool)?, Int, PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder, ChatListSearchSectionExpandType) + case localPeer(EnginePeer, EnginePeer?, (Int32, Bool)?, Int, PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder, ChatListSearchSectionExpandType) case globalPeer(FoundPeer, (Int32, Bool)?, Int, PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder, ChatListSearchSectionExpandType) - case message(Message, RenderedPeer, CombinedPeerReadState?, ChatListPresentationData, Int32, Bool?, Bool) + case message(EngineMessage, EngineRenderedPeer, EnginePeerReadCounters?, ChatListPresentationData, Int32, Bool?, Bool) case addContact(String, PresentationTheme, PresentationStrings) public var stableId: ChatListSearchEntryStableId { @@ -281,7 +249,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable { public static func ==(lhs: ChatListSearchEntry, rhs: ChatListSearchEntry) -> Bool { switch lhs { case let .localPeer(lhsPeer, lhsAssociatedPeer, lhsUnreadBadge, lhsIndex, lhsTheme, lhsStrings, lhsSortOrder, lhsDisplayOrder, lhsExpandType): - if case let .localPeer(rhsPeer, rhsAssociatedPeer, rhsUnreadBadge, rhsIndex, rhsTheme, rhsStrings, rhsSortOrder, rhsDisplayOrder, rhsExpandType) = rhs, lhsPeer.isEqual(rhsPeer) && arePeersEqual(lhsAssociatedPeer, rhsAssociatedPeer) && lhsIndex == rhsIndex && lhsTheme === rhsTheme && lhsStrings === rhsStrings && lhsSortOrder == rhsSortOrder && lhsDisplayOrder == rhsDisplayOrder && lhsUnreadBadge?.0 == rhsUnreadBadge?.0 && lhsUnreadBadge?.1 == rhsUnreadBadge?.1 && lhsExpandType == rhsExpandType { + if case let .localPeer(rhsPeer, rhsAssociatedPeer, rhsUnreadBadge, rhsIndex, rhsTheme, rhsStrings, rhsSortOrder, rhsDisplayOrder, rhsExpandType) = rhs, lhsPeer == rhsPeer && lhsAssociatedPeer == rhsAssociatedPeer && lhsIndex == rhsIndex && lhsTheme === rhsTheme && lhsStrings === rhsStrings && lhsSortOrder == rhsSortOrder && lhsDisplayOrder == rhsDisplayOrder && lhsUnreadBadge?.0 == rhsUnreadBadge?.0 && lhsUnreadBadge?.1 == rhsUnreadBadge?.1 && lhsExpandType == rhsExpandType { return true } else { return false @@ -370,11 +338,11 @@ public enum ChatListSearchEntry: Comparable, Identifiable { } } - public func item(context: AccountContext, presentationData: PresentationData, enableHeaders: Bool, filter: ChatListNodePeersFilter, tagMask: MessageTags?, interaction: ChatListNodeInteraction, listInteraction: ListMessageItemInteraction, peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, toggleExpandLocalResults: @escaping () -> Void, toggleExpandGlobalResults: @escaping () -> Void, searchPeer: @escaping (Peer) -> Void, searchQuery: String?, searchOptions: ChatListSearchOptions?, messageContextAction: ((Message, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void)?) -> ListViewItem { + public func item(context: AccountContext, presentationData: PresentationData, enableHeaders: Bool, filter: ChatListNodePeersFilter, tagMask: EngineMessage.Tags?, interaction: ChatListNodeInteraction, listInteraction: ListMessageItemInteraction, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, toggleExpandLocalResults: @escaping () -> Void, toggleExpandGlobalResults: @escaping () -> Void, searchPeer: @escaping (EnginePeer) -> Void, searchQuery: String?, searchOptions: ChatListSearchOptions?, messageContextAction: ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void)?) -> ListViewItem { switch self { case let .localPeer(peer, associatedPeer, unreadBadge, _, theme, strings, nameSortOrder, nameDisplayOrder, expandType): - let primaryPeer: Peer - var chatPeer: Peer? + let primaryPeer: EnginePeer + var chatPeer: EnginePeer? if let associatedPeer = associatedPeer { primaryPeer = associatedPeer chatPeer = peer @@ -386,14 +354,17 @@ public enum ChatListSearchEntry: Comparable, Identifiable { var enabled = true if filter.contains(.onlyWriteable) { if let peer = chatPeer { - enabled = canSendMessagesToPeer(peer) + enabled = canSendMessagesToPeer(peer._asPeer()) } else { enabled = false } } if filter.contains(.onlyPrivateChats) { if let peer = chatPeer { - if !(peer is TelegramUser || peer is TelegramSecretChat) { + switch peer { + case .user, .secretChat: + break + default: enabled = false } } else { @@ -402,8 +373,8 @@ public enum ChatListSearchEntry: Comparable, Identifiable { } if filter.contains(.onlyGroups) { if let peer = chatPeer { - if let _ = peer as? TelegramGroup { - } else if let peer = peer as? TelegramChannel, case .group = peer.info { + if case .legacyGroup = peer { + } else if case let .channel(peer) = peer, case .group = peer.info { } else { enabled = false } @@ -441,9 +412,9 @@ public enum ChatListSearchEntry: Comparable, Identifiable { }) } - return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .generalSearch, peer: .peer(peer: EnginePeer(primaryPeer), chatPeer: chatPeer.flatMap(EnginePeer.init)), status: .none, badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { contactPeer in + return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .generalSearch, peer: .peer(peer: primaryPeer, chatPeer: chatPeer), status: .none, badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { contactPeer in if case let .peer(maybePeer, maybeChatPeer) = contactPeer, let peer = maybePeer, let chatPeer = maybeChatPeer { - interaction.peerSelected(chatPeer._asPeer(), peer._asPeer(), nil) + interaction.peerSelected(chatPeer, peer, nil) } else { interaction.peerSelected(peer, nil, nil) } @@ -509,19 +480,19 @@ public enum ChatListSearchEntry: Comparable, Identifiable { } return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .generalSearch, peer: .peer(peer: EnginePeer(peer.peer), chatPeer: EnginePeer(peer.peer)), status: .addressName(suffixString), badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in - interaction.peerSelected(peer.peer, nil, nil) + interaction.peerSelected(EnginePeer(peer.peer), nil, nil) }, contextAction: peerContextAction.flatMap { peerContextAction in return { node, gesture in - peerContextAction(peer.peer, .search(nil), node, gesture) + peerContextAction(EnginePeer(peer.peer), .search(nil), node, gesture) } }) case let .message(message, peer, readState, presentationData, _, selected, displayCustomHeader): let header = ChatListSearchItemHeader(type: .messages, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil) let selection: ChatHistoryMessageSelection = selected.flatMap { .selectable(selected: $0) } ?? .none if let tagMask = tagMask, tagMask != .photoOrVideo { - return ListMessageItem(presentationData: ChatPresentationData(theme: ChatPresentationThemeData(theme: presentationData.theme, wallpaper: .builtin(WallpaperSettings())), fontSize: presentationData.fontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: true, largeEmoji: false, chatBubbleCorners: PresentationChatBubbleCorners(mainRadius: 0.0, auxiliaryRadius: 0.0, mergeBubbleCorners: false)), context: context, chatLocation: .peer(peer.peerId), interaction: listInteraction, message: message, selection: selection, displayHeader: enableHeaders && !displayCustomHeader, customHeader: nil, hintIsLink: tagMask == .webPage, isGlobalSearchResult: true) + return ListMessageItem(presentationData: ChatPresentationData(theme: ChatPresentationThemeData(theme: presentationData.theme, wallpaper: .builtin(WallpaperSettings())), fontSize: presentationData.fontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: true, largeEmoji: false, chatBubbleCorners: PresentationChatBubbleCorners(mainRadius: 0.0, auxiliaryRadius: 0.0, mergeBubbleCorners: false)), context: context, chatLocation: .peer(peer.peerId), interaction: listInteraction, message: message._asMessage(), selection: selection, displayHeader: enableHeaders && !displayCustomHeader, customHeader: nil, hintIsLink: tagMask == .webPage, isGlobalSearchResult: true) } else { - return ChatListItem(presentationData: presentationData, context: context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: message.index), content: .peer(messages: [message], peer: peer, combinedReadState: readState, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(), embeddedState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: true, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: tagMask == nil ? header : nil, enableContextActions: false, hiddenOffset: false, interaction: interaction) + return ChatListItem(presentationData: presentationData, context: context, peerGroupId: .root, filterData: nil, index: EngineChatList.Item.Index(pinningIndex: nil, messageIndex: message.index), content: .peer(messages: [message], peer: peer, combinedReadState: readState, isRemovedFromTotalUnreadCount: false, presence: nil, hasUnseenMentions: false, draftState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: true, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: tagMask == nil ? header : nil, enableContextActions: false, hiddenOffset: false, interaction: interaction) } case let .addContact(phoneNumber, theme, strings): return ContactsAddItem(theme: theme, strings: strings, phoneNumber: phoneNumber, header: ChatListSearchItemHeader(type: .phoneNumber, theme: theme, strings: strings, actionTitle: nil, action: nil), action: { @@ -559,7 +530,7 @@ public struct ChatListSearchContainerTransition { } } -private func chatListSearchContainerPreparedRecentTransition(from fromEntries: [ChatListRecentEntry], to toEntries: [ChatListRecentEntry], context: AccountContext, presentationData: ChatListPresentationData, filter: ChatListNodePeersFilter, peerSelected: @escaping (Peer) -> Void, disabledPeerSelected: @escaping (Peer) -> Void, peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, clearRecentlySearchedPeers: @escaping () -> Void, deletePeer: @escaping (PeerId) -> Void) -> ChatListSearchContainerRecentTransition { +private func chatListSearchContainerPreparedRecentTransition(from fromEntries: [ChatListRecentEntry], to toEntries: [ChatListRecentEntry], context: AccountContext, presentationData: ChatListPresentationData, filter: ChatListNodePeersFilter, peerSelected: @escaping (EnginePeer) -> Void, disabledPeerSelected: @escaping (EnginePeer) -> Void, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, clearRecentlySearchedPeers: @escaping () -> Void, deletePeer: @escaping (EnginePeer.Id) -> Void) -> ChatListSearchContainerRecentTransition { let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries) let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) } @@ -569,7 +540,7 @@ private func chatListSearchContainerPreparedRecentTransition(from fromEntries: [ return ChatListSearchContainerRecentTransition(deletions: deletions, insertions: insertions, updates: updates) } -public func chatListSearchContainerPreparedTransition(from fromEntries: [ChatListSearchEntry], to toEntries: [ChatListSearchEntry], displayingResults: Bool, isEmpty: Bool, isLoading: Bool, animated: Bool, context: AccountContext, presentationData: PresentationData, enableHeaders: Bool, filter: ChatListNodePeersFilter, tagMask: MessageTags?, interaction: ChatListNodeInteraction, listInteraction: ListMessageItemInteraction, peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, toggleExpandLocalResults: @escaping () -> Void, toggleExpandGlobalResults: @escaping () -> Void, searchPeer: @escaping (Peer) -> Void, searchQuery: String?, searchOptions: ChatListSearchOptions?, messageContextAction: ((Message, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void)?) -> ChatListSearchContainerTransition { +public func chatListSearchContainerPreparedTransition(from fromEntries: [ChatListSearchEntry], to toEntries: [ChatListSearchEntry], displayingResults: Bool, isEmpty: Bool, isLoading: Bool, animated: Bool, context: AccountContext, presentationData: PresentationData, enableHeaders: Bool, filter: ChatListNodePeersFilter, tagMask: EngineMessage.Tags?, interaction: ChatListNodeInteraction, listInteraction: ListMessageItemInteraction, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, toggleExpandLocalResults: @escaping () -> Void, toggleExpandGlobalResults: @escaping () -> Void, searchPeer: @escaping (EnginePeer) -> Void, searchQuery: String?, searchOptions: ChatListSearchOptions?, messageContextAction: ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void)?) -> ChatListSearchContainerTransition { let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries) let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) } @@ -582,21 +553,26 @@ public func chatListSearchContainerPreparedTransition(from fromEntries: [ChatLis private struct ChatListSearchListPaneNodeState: Equatable { var expandLocalSearch: Bool = false var expandGlobalSearch: Bool = false - var deletedMessageIds = Set() + var deletedMessageIds = Set() var deletedGlobalMessageIds = Set() } -private func doesPeerMatchFilter(peer: Peer, filter: ChatListNodePeersFilter) -> Bool { +private func doesPeerMatchFilter(peer: EnginePeer, filter: ChatListNodePeersFilter) -> Bool { var enabled = true - if filter.contains(.onlyWriteable), !canSendMessagesToPeer(peer) { + if filter.contains(.onlyWriteable), !canSendMessagesToPeer(peer._asPeer()) { enabled = false } - if filter.contains(.onlyPrivateChats), !(peer is TelegramUser || peer is TelegramSecretChat) { - enabled = false + if filter.contains(.onlyPrivateChats) { + switch peer { + case .user, .secretChat: + break + default: + enabled = false + } } if filter.contains(.onlyGroups) { - if let _ = peer as? TelegramGroup { - } else if let peer = peer as? TelegramChannel, case .group = peer.info { + if case .legacyGroup = peer { + } else if case let .channel(peer) = peer, case .group = peer.info { } else { enabled = false } @@ -606,8 +582,8 @@ private func doesPeerMatchFilter(peer: Peer, filter: ChatListNodePeersFilter) -> private struct ChatListSearchMessagesResult { let query: String - let messages: [Message] - let readStates: [PeerId: CombinedPeerReadState] + let messages: [EngineMessage] + let readStates: [EnginePeer.Id: EnginePeerReadCounters] let hasMore: Bool let totalCount: Int32 let state: SearchMessagesState @@ -615,24 +591,24 @@ private struct ChatListSearchMessagesResult { private struct ChatListSearchMessagesContext { let result: ChatListSearchMessagesResult - let loadMoreIndex: MessageIndex? + let loadMoreIndex: EngineMessage.Index? } public enum ChatListSearchContextActionSource { case recentPeers case recentSearch - case search(MessageId?) + case search(EngineMessage.Id?) } public struct ChatListSearchOptions { - let peer: (PeerId, Bool, String)? + let peer: (EnginePeer.Id, Bool, String)? let date: (Int32?, Int32, String)? var isEmpty: Bool { return self.peer == nil && self.date == nil } - func withUpdatedPeer(_ peerIdIsGroupAndName: (PeerId, Bool, String)?) -> ChatListSearchOptions { + func withUpdatedPeer(_ peerIdIsGroupAndName: (EnginePeer.Id, Bool, String)?) -> ChatListSearchOptions { return ChatListSearchOptions(peer: peerIdIsGroupAndName, date: self.date) } @@ -647,8 +623,8 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { private let peersFilter: ChatListNodePeersFilter private var presentationData: PresentationData private let key: ChatListSearchPaneKey - private let tagMask: MessageTags? - private let groupId: PeerGroupId? + private let tagMask: EngineMessage.Tags? + private let groupId: EngineChatList.Group? private let navigationController: NavigationController? private let recentListNode: ListView @@ -667,7 +643,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { private var searchStateValue = ChatListSearchListPaneNodeState() private let searchStatePromise = ValuePromise() private let searchContextValue = Atomic(value: nil) - var searchCurrentMessages: [Message]? + var searchCurrentMessages: [EngineMessage]? var currentEntries: [ChatListSearchEntry]? private var deletedMessagesDisposable: Disposable? @@ -703,8 +679,8 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { return self.ready.get() } - private let selectedMessagesPromise = Promise?>(nil) - private var selectedMessages: Set? { + private let selectedMessagesPromise = Promise?>(nil) + private var selectedMessages: Set? { didSet { if self.selectedMessages != oldValue { self.selectedMessagesPromise.set(.single(self.selectedMessages)) @@ -714,7 +690,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { private var hiddenMediaDisposable: Disposable? - init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, interaction: ChatListSearchInteraction, key: ChatListSearchPaneKey, peersFilter: ChatListNodePeersFilter, groupId: PeerGroupId?, searchQuery: Signal, searchOptions: Signal, navigationController: NavigationController?) { + init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, interaction: ChatListSearchInteraction, key: ChatListSearchPaneKey, peersFilter: ChatListNodePeersFilter, groupId: EngineChatList.Group?, searchQuery: Signal, searchOptions: Signal, navigationController: NavigationController?) { self.context = context self.interaction = interaction self.key = key @@ -722,7 +698,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { self.groupId = groupId self.navigationController = navigationController - let tagMask: MessageTags? + let tagMask: EngineMessage.Tags? switch key { case .chats: tagMask = nil @@ -763,14 +739,14 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { return presentationData.strings.VoiceOver_ScrollStatus(row, count).string } - var openMediaMessageImpl: ((Message, ChatControllerInteractionOpenMessageMode) -> Void)? - var transitionNodeImpl: ((MessageId, Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?)? + var openMediaMessageImpl: ((EngineMessage, ChatControllerInteractionOpenMessageMode) -> Void)? + var transitionNodeImpl: ((EngineMessage.Id, EngineMedia) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?)? var addToTransitionSurfaceImpl: ((UIView) -> Void)? self.mediaNode = ChatListSearchMediaNode(context: self.context, contentType: .photoOrVideo, openMessage: { message, mode in - openMediaMessageImpl?(message, mode) + openMediaMessageImpl?(EngineMessage(message), mode) }, messageContextAction: { message, node, rect, gesture in - interaction.mediaMessageContextAction(message, node, rect, gesture) + interaction.mediaMessageContextAction(EngineMessage(message), node, rect, gesture) }, toggleMessageSelection: { messageId, selected in interaction.toggleMessageSelection(messageId, selected) }) @@ -843,35 +819,46 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { } let accountPeer = context.account.postbox.loadedPeerWithId(context.account.peerId) |> take(1) - let foundLocalPeers: Signal<(peers: [RenderedPeer], unread: [PeerId: (Int32, Bool)]), NoError> + let foundLocalPeers: Signal<(peers: [EngineRenderedPeer], unread: [EnginePeer.Id: (Int32, Bool)]), NoError> if let query = query { - foundLocalPeers = context.account.postbox.searchPeers(query: query.lowercased()) - |> mapToSignal { local -> Signal<([PeerView], [RenderedPeer]), NoError> in - return combineLatest(local.map { context.account.postbox.peerView(id: $0.peerId) }) |> map { views in - return (views, local) + foundLocalPeers = context.engine.contacts.searchLocalPeers(query: query.lowercased()) + |> mapToSignal { local -> Signal<([EnginePeer.Id: Optional], [EnginePeer.Id: Int], [EngineRenderedPeer]), NoError> in + return context.engine.data.subscribe( + EngineDataMap( + local.map { peer -> TelegramEngine.EngineData.Item.Peer.NotificationSettings in + return TelegramEngine.EngineData.Item.Peer.NotificationSettings(id: peer.peerId) + } + ), + EngineDataMap( + local.map { peer -> TelegramEngine.EngineData.Item.Messages.PeerUnreadCount in + return TelegramEngine.EngineData.Item.Messages.PeerUnreadCount(id: peer.peerId) + } + ) + ) + |> map { notificationSettings, unreadCounts in + return (notificationSettings, unreadCounts, local) } } - |> mapToSignal { viewsAndPeers -> Signal<(peers: [RenderedPeer], unread: [PeerId: (Int32, Bool)]), NoError> in - return context.account.postbox.unreadMessageCountsView(items: viewsAndPeers.0.map {.peer($0.peerId)}) |> map { values in - var unread: [PeerId: (Int32, Bool)] = [:] - for peerView in viewsAndPeers.0 { - var isMuted: Bool = false - if let nofiticationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings { - switch nofiticationSettings.muteState { - case .muted: - isMuted = true - default: - break - } - } - - let unreadCount = values.count(for: .peer(peerView.peerId)) - if let unreadCount = unreadCount, unreadCount > 0 { - unread[peerView.peerId] = (unreadCount, isMuted) + |> map { notificationSettings, unreadCounts, peers -> (peers: [EngineRenderedPeer], unread: [EnginePeer.Id: (Int32, Bool)]) in + + var unread: [EnginePeer.Id: (Int32, Bool)] = [:] + for peer in peers { + var isMuted: Bool = false + if let nofiticationSettings = notificationSettings[peer.peerId] { + switch nofiticationSettings?.muteState { + case .muted: + isMuted = true + default: + break } } - return (peers: viewsAndPeers.1, unread: unread) + + let unreadCount = unreadCounts[peer.peerId] + if let unreadCount = unreadCount, unreadCount > 0 { + unread[peer.peerId] = (Int32(unreadCount), isMuted) + } } + return (peers: peers, unread: unread) } } else { foundLocalPeers = .single((peers: [], unread: [:])) @@ -883,7 +870,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { foundRemotePeers = ( .single((currentRemotePeersValue.0, currentRemotePeersValue.1, true)) |> then( - context.engine.peers.searchPeers(query: query) + context.engine.contacts.searchRemotePeers(query: query) |> map { ($0.0, $0.1, false) } |> delay(0.2, queue: Queue.concurrentDefaultQueue()) ) @@ -897,14 +884,14 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { location = .peer(peerId: peerId, fromId: nil, tags: tagMask, topMsgId: nil, minDate: options.date?.0, maxDate: options.date?.1) } else { if let groupId = groupId { - location = .group(groupId: groupId, tags: tagMask, minDate: options.date?.0, maxDate: options.date?.1) + location = .group(groupId: groupId._asGroup(), tags: tagMask, minDate: options.date?.0, maxDate: options.date?.1) } else { location = .general(tags: tagMask, minDate: options.date?.0, maxDate: options.date?.1) } } } else { if let groupId = groupId { - location = .group(groupId: groupId, tags: tagMask, minDate: nil, maxDate: nil) + location = .group(groupId: groupId._asGroup(), tags: tagMask, minDate: nil, maxDate: nil) } else { location = .general(tags: tagMask, minDate: nil, maxDate: nil) } @@ -914,7 +901,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { updateSearchContext { _ in return (nil, true) } - let foundRemoteMessages: Signal<(([Message], [PeerId: CombinedPeerReadState], Int32), Bool), NoError> + let foundRemoteMessages: Signal<(([EngineMessage], [EnginePeer.Id: EnginePeerReadCounters], Int32), Bool), NoError> if peersFilter.contains(.doNotSearchMessages) { foundRemoteMessages = .single((([], [:], 0), false)) } else { @@ -924,18 +911,18 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { let searchSignal = context.engine.messages.searchMessages(location: location, query: finalQuery, state: nil, limit: 50) |> map { result, updatedState -> ChatListSearchMessagesResult in - return ChatListSearchMessagesResult(query: finalQuery, messages: result.messages.sorted(by: { $0.index > $1.index }), readStates: result.readStates, hasMore: !result.completed, totalCount: result.totalCount, state: updatedState) + return ChatListSearchMessagesResult(query: finalQuery, messages: result.messages.map({ EngineMessage($0) }).sorted(by: { $0.index > $1.index }), readStates: result.readStates.mapValues(EnginePeerReadCounters.init), hasMore: !result.completed, totalCount: result.totalCount, state: updatedState) } let loadMore = searchContext.get() - |> mapToSignal { searchContext -> Signal<(([Message], [PeerId: CombinedPeerReadState], Int32), Bool), NoError> in + |> mapToSignal { searchContext -> Signal<(([EngineMessage], [EnginePeer.Id: EnginePeerReadCounters], Int32), Bool), NoError> in if let searchContext = searchContext, searchContext.result.hasMore { if let _ = searchContext.loadMoreIndex { return context.engine.messages.searchMessages(location: location, query: finalQuery, state: searchContext.result.state, limit: 80) |> map { result, updatedState -> ChatListSearchMessagesResult in - return ChatListSearchMessagesResult(query: finalQuery, messages: result.messages.sorted(by: { $0.index > $1.index }), readStates: result.readStates, hasMore: !result.completed, totalCount: result.totalCount, state: updatedState) + return ChatListSearchMessagesResult(query: finalQuery, messages: result.messages.map({ EngineMessage($0) }).sorted(by: { $0.index > $1.index }), readStates: result.readStates.mapValues(EnginePeerReadCounters.init), hasMore: !result.completed, totalCount: result.totalCount, state: updatedState) } - |> mapToSignal { foundMessages -> Signal<(([Message], [PeerId: CombinedPeerReadState], Int32), Bool), NoError> in + |> mapToSignal { foundMessages -> Signal<(([EngineMessage], [EnginePeer.Id: EnginePeerReadCounters], Int32), Bool), NoError> in updateSearchContext { previous in let updated = ChatListSearchMessagesContext(result: foundMessages, loadMoreIndex: nil) return (updated, true) @@ -953,7 +940,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { foundRemoteMessages = .single((([], [:], 0), true)) |> then( searchSignal - |> map { foundMessages -> (([Message], [PeerId: CombinedPeerReadState], Int32), Bool) in + |> map { foundMessages -> (([EngineMessage], [EnginePeer.Id: EnginePeerReadCounters], Int32), Bool) in updateSearchContext { _ in return (ChatListSearchMessagesContext(result: foundMessages, loadMoreIndex: nil), true) } @@ -966,9 +953,12 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { let resolvedMessage = .single(nil) |> then(context.sharedContext.resolveUrl(context: context, peerId: nil, url: finalQuery, skipUrlAuth: true) - |> mapToSignal { resolvedUrl -> Signal in + |> mapToSignal { resolvedUrl -> Signal in if case let .channelMessage(_, messageId, _) = resolvedUrl { return context.engine.messages.downloadMessage(messageId: messageId) + |> map { message -> EngineMessage? in + return message.flatMap(EngineMessage.init) + } } else { return .single(nil) } @@ -982,14 +972,14 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { let _ = currentRemotePeers.swap((foundRemotePeers.0, foundRemotePeers.1)) - let filteredPeer:(Peer, Peer) -> Bool = { peer, accountPeer in + let filteredPeer: (EnginePeer, EnginePeer) -> Bool = { peer, accountPeer in guard !peersFilter.contains(.excludeSavedMessages) || peer.id != accountPeer.id else { return false } guard !peersFilter.contains(.excludeSecretChats) || peer.id.namespace != Namespaces.Peer.SecretChat else { return false } guard !peersFilter.contains(.onlyPrivateChats) || peer.id.namespace == Namespaces.Peer.CloudUser else { return false } if peersFilter.contains(.onlyGroups) { var isGroup: Bool = false - if let peer = peer as? TelegramChannel, case .group = peer.info { + if case let .channel(peer) = peer, case .group = peer.info { isGroup = true } else if peer.id.namespace == Namespaces.Peer.CloudGroup { isGroup = true @@ -1000,7 +990,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { } if peersFilter.contains(.onlyChannels) { - if let peer = peer as? TelegramChannel, case .broadcast = peer.info { + if case let .channel(peer) = peer, case .broadcast = peer.info { return true } else { return false @@ -1008,7 +998,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { } if peersFilter.contains(.excludeChannels) { - if let peer = peer as? TelegramChannel, case .broadcast = peer.info { + if case let .channel(peer) = peer, case .broadcast = peer.info { return false } } @@ -1016,11 +1006,11 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { return true } - var existingPeerIds = Set() + var existingPeerIds = Set() var totalNumberOfLocalPeers = 0 for renderedPeer in foundLocalPeers.peers { - if let peer = renderedPeer.peers[renderedPeer.peerId], peer.id != context.account.peerId, filteredPeer(peer, accountPeer) { + if let peer = renderedPeer.peers[renderedPeer.peerId], peer.id != context.account.peerId, filteredPeer(peer, EnginePeer(accountPeer)) { if !existingPeerIds.contains(peer.id) { existingPeerIds.insert(peer.id) totalNumberOfLocalPeers += 1 @@ -1028,7 +1018,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { } } for peer in foundRemotePeers.0 { - if !existingPeerIds.contains(peer.peer.id), filteredPeer(peer.peer, accountPeer) { + if !existingPeerIds.contains(peer.peer.id), filteredPeer(EnginePeer(peer.peer), EnginePeer(accountPeer)) { existingPeerIds.insert(peer.peer.id) totalNumberOfLocalPeers += 1 } @@ -1036,7 +1026,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { var totalNumberOfGlobalPeers = 0 for peer in foundRemotePeers.1 { - if !existingPeerIds.contains(peer.peer.id), filteredPeer(peer.peer, accountPeer) { + if !existingPeerIds.contains(peer.peer.id), filteredPeer(EnginePeer(peer.peer), EnginePeer(accountPeer)) { totalNumberOfGlobalPeers += 1 } } @@ -1053,9 +1043,9 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { let lowercasedQuery = finalQuery.lowercased() if lowercasedQuery.count > 1 && (presentationData.strings.DialogList_SavedMessages.lowercased().hasPrefix(lowercasedQuery) || "saved messages".hasPrefix(lowercasedQuery)) { - if !existingPeerIds.contains(accountPeer.id), filteredPeer(accountPeer, accountPeer) { + if !existingPeerIds.contains(accountPeer.id), filteredPeer(EnginePeer(accountPeer), EnginePeer(accountPeer)) { existingPeerIds.insert(accountPeer.id) - entries.append(.localPeer(accountPeer, nil, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder, localExpandType)) + entries.append(.localPeer(EnginePeer(accountPeer), nil, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder, localExpandType)) index += 1 } } @@ -1066,11 +1056,11 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { break } - if let peer = renderedPeer.peers[renderedPeer.peerId], peer.id != context.account.peerId, filteredPeer(peer, accountPeer) { + if let peer = renderedPeer.peers[renderedPeer.peerId], peer.id != context.account.peerId, filteredPeer(peer, EnginePeer(accountPeer)) { if !existingPeerIds.contains(peer.id) { existingPeerIds.insert(peer.id) - var associatedPeer: Peer? - if let associatedPeerId = peer.associatedPeerId { + var associatedPeer: EnginePeer? + if case let .secretChat(secretChat) = peer, let associatedPeerId = secretChat.associatedPeerId { associatedPeer = renderedPeer.peers[associatedPeerId] } entries.append(.localPeer(peer, associatedPeer, foundLocalPeers.unread[peer.id], index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder, localExpandType)) @@ -1085,9 +1075,9 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { break } - if !existingPeerIds.contains(peer.peer.id), filteredPeer(peer.peer, accountPeer) { + if !existingPeerIds.contains(peer.peer.id), filteredPeer(EnginePeer(peer.peer), EnginePeer(accountPeer)) { existingPeerIds.insert(peer.peer.id) - entries.append(.localPeer(peer.peer, nil, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder, localExpandType)) + entries.append(.localPeer(EnginePeer(peer.peer), nil, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder, localExpandType)) index += 1 numberOfLocalPeers += 1 } @@ -1102,7 +1092,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { break } - if !existingPeerIds.contains(peer.peer.id), filteredPeer(peer.peer, accountPeer) { + if !existingPeerIds.contains(peer.peer.id), filteredPeer(EnginePeer(peer.peer), EnginePeer(accountPeer)) { existingPeerIds.insert(peer.peer.id) entries.append(.globalPeer(peer, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder, globalExpandType)) index += 1 @@ -1112,10 +1102,10 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { } if let message = resolvedMessage { - var peer = RenderedPeer(message: message) + var peer = EngineRenderedPeer(message: message) if let group = message.peers[message.id.peerId] as? TelegramGroup, let migrationReference = group.migrationReference { if let channelPeer = message.peers[migrationReference.peerId] { - peer = RenderedPeer(peer: channelPeer) + peer = EngineRenderedPeer(peer: EnginePeer(channelPeer)) } } entries.append(.message(message, peer, nil, presentationData, 1, nil, true)) @@ -1135,10 +1125,10 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { if firstHeaderId == nil { firstHeaderId = headerId } - var peer = RenderedPeer(message: message) + var peer = EngineRenderedPeer(message: message) if let group = message.peers[message.id.peerId] as? TelegramGroup, let migrationReference = group.migrationReference { if let channelPeer = message.peers[migrationReference.peerId] { - peer = RenderedPeer(peer: channelPeer) + peer = EngineRenderedPeer(peer: EnginePeer(channelPeer)) } } entries.append(.message(message, peer, foundRemoteMessages.0.1[message.id.peerId], presentationData, foundRemoteMessages.0.2, selectionState?.contains(message.id), headerId == firstHeaderId)) @@ -1154,7 +1144,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { } } - let foundMessages = searchContext.get() |> map { searchContext -> ([Message], Int32, Bool) in + let foundMessages = searchContext.get() |> map { searchContext -> ([EngineMessage], Int32, Bool) in if let result = searchContext?.result { return (result.messages, result.totalCount, result.hasMore) } else { @@ -1178,28 +1168,29 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { } openMediaMessageImpl = { message, mode in - let _ = context.sharedContext.openChatMessage(OpenChatMessageParams(context: context, chatLocation: nil, chatLocationContextHolder: nil, message: message, standalone: false, reverseMessageGalleryOrder: true, mode: mode, navigationController: navigationController, dismissInput: { + let _ = context.sharedContext.openChatMessage(OpenChatMessageParams(context: context, chatLocation: nil, chatLocationContextHolder: nil, message: message._asMessage(), standalone: false, reverseMessageGalleryOrder: true, mode: mode, navigationController: navigationController, dismissInput: { interaction.dismissInput() }, present: { c, a in interaction.present(c, a) }, transitionNode: { messageId, media in - return transitionNodeImpl?(messageId, media) + return transitionNodeImpl?(messageId, EngineMedia(media)) }, addToTransitionSurface: { view in addToTransitionSurfaceImpl?(view) }, openUrl: { url in interaction.openUrl(url) - }, openPeer: { peer, navigation in - //self?.openPeer(peerId: peer.id, navigation: navigation) + }, openPeer: { _, _ in }, callPeer: { _, _ in }, enqueueMessage: { _ in - }, sendSticker: nil, setupTemporaryHiddenMedia: { _, _, _ in }, chatAvatarHiddenMedia: { _, _ in }, gallerySource: .custom(messages: foundMessages, messageId: message.id, loadMore: { + }, sendSticker: nil, setupTemporaryHiddenMedia: { _, _, _ in }, chatAvatarHiddenMedia: { _, _ in }, gallerySource: .custom(messages: foundMessages |> map { message, a, b in + return (message.map { $0._asMessage() }, a, b) + }, messageId: message.id, loadMore: { loadMore() }))) } transitionNodeImpl = { [weak self] messageId, media in if let strongSelf = self { - return strongSelf.mediaNode.transitionNodeForGallery(messageId: messageId, media: media) + return strongSelf.mediaNode.transitionNodeForGallery(messageId: messageId, media: media._asMedia()) } else { return nil } @@ -1224,7 +1215,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { }, messageSelected: { [weak self] peer, message, _ in interaction.dismissInput() if let strongSelf = self, let peer = message.peers[message.id.peerId] { - interaction.openMessage(peer, message.id, strongSelf.key == .chats) + interaction.openMessage(EnginePeer(peer), message.id, strongSelf.key == .chats) } self?.listNode.clearHighlightAnimated(true) }, groupSelected: { _ in @@ -1282,13 +1273,17 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { }, openPeer: { peer, navigation in }, callPeer: { _, _ in }, enqueueMessage: { _ in - }, sendSticker: nil, setupTemporaryHiddenMedia: { _, _, _ in }, chatAvatarHiddenMedia: { _, _ in }, playlistLocation: .custom(messages: foundMessages, at: message.id, loadMore: { + }, sendSticker: nil, setupTemporaryHiddenMedia: { _, _, _ in }, chatAvatarHiddenMedia: { _, _ in }, playlistLocation: .custom(messages: foundMessages |> map { message, a, b in + return (message.map { $0._asMessage() }, a, b) + }, at: message.id, loadMore: { loadMore() - }), gallerySource: .custom(messages: foundMessages, messageId: message.id, loadMore: { + }), gallerySource: .custom(messages: foundMessages |> map { message, a, b in + return (message.map { $0._asMessage() }, a, b) + }, messageId: message.id, loadMore: { loadMore() }))) }, openMessageContextMenu: { message, _, node, rect, gesture in - interaction.messageContextAction(message, node, rect, gesture) + interaction.messageContextAction(EngineMessage(message), node, rect, gesture) }, toggleMessagesSelection: { messageId, selected in if let messageId = messageId.first { interaction.toggleMessageSelection(messageId, selected) @@ -1306,7 +1301,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { }) let previousSearchItems = Atomic<[ChatListSearchEntry]?>(value: nil) - let previousSelectedMessages = Atomic?>(value: nil) + let previousSelectedMessages = Atomic?>(value: nil) let _ = (searchQuery |> deliverOnMainQueue).start(next: { [weak self, weak listInteraction, weak chatListInteraction] query in @@ -1338,7 +1333,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { var entriesAndFlags = entriesAndFlags - var peers: [Peer] = [] + var peers: [EnginePeer] = [] if let entries = entriesAndFlags?.0 { var filteredEntries: [ChatListSearchEntry] = [] for entry in entries { @@ -1387,7 +1382,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { strongSelf.currentEntries = newEntries strongSelf.enqueueTransition(transition, firstTime: firstTime) - var messages: [Message] = [] + var messages: [EngineMessage] = [] for entry in newEntries { if case let .message(message, _, _, _, _, _, _) = entry { messages.append(message) @@ -1409,12 +1404,12 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { } |> distinctUntilChanged - let previousRecentlySearchedPeerOrder = Atomic<[PeerId]>(value: []) + let previousRecentlySearchedPeerOrder = Atomic<[EnginePeer.Id]>(value: []) let fixedRecentlySearchedPeers = context.engine.peers.recentlySearchedPeers() |> map { peers -> [RecentlySearchedPeer] in var result: [RecentlySearchedPeer] = [] let _ = previousRecentlySearchedPeerOrder.modify { current in - var updated: [PeerId] = [] + var updated: [EnginePeer.Id] = [] for id in current { inner: for peer in peers { if peer.peer.peerId == id { @@ -1443,14 +1438,14 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { entries.append(.topPeers([], presentationData.theme, presentationData.strings)) } } - var peerIds = Set() + var peerIds = Set() var index = 0 loop: for searchedPeer in peers { if let peer = searchedPeer.peer.peers[searchedPeer.peer.peerId] { if peerIds.contains(peer.id) { continue loop } - if !doesPeerMatchFilter(peer: peer, filter: peersFilter) { + if !doesPeerMatchFilter(peer: EnginePeer(peer), filter: peersFilter) { continue } peerIds.insert(peer.id) @@ -1745,7 +1740,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.musicPlaybackSettings)?.get(MusicPlaybackSettings.self) ?? MusicPlaybackSettings.defaultSettings transaction.updateSharedData(ApplicationSpecificSharedDataKeys.musicPlaybackSettings, { _ in - return PreferencesEntry(settings.withUpdatedVoicePlaybackRate(rate)) + return AccountManagerPreferencesEntry(settings.withUpdatedVoicePlaybackRate(rate)) }) return rate } @@ -1826,7 +1821,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { strongSelf.interaction.dismissInput() strongSelf.interaction.present(controller, nil) } else { - let signal = strongSelf.context.sharedContext.messageFromPreloadedChatHistoryViewForLocation(id: id.messageId, location: ChatHistoryLocationInput(content: .InitialSearch(location: .id(id.messageId), count: 60, highlight: true), id: 0), context: strongSelf.context, chatLocation: .peer(id.messageId.peerId), subject: nil, chatLocationContextHolder: Atomic(value: nil), tagMask: MessageTags.music) + let signal = strongSelf.context.sharedContext.messageFromPreloadedChatHistoryViewForLocation(id: id.messageId, location: ChatHistoryLocationInput(content: .InitialSearch(location: .id(id.messageId), count: 60, highlight: true), id: 0), context: strongSelf.context, chatLocation: .peer(id.messageId.peerId), subject: nil, chatLocationContextHolder: Atomic(value: nil), tagMask: EngineMessage.Tags.music) var cancelImpl: (() -> Void)? let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } @@ -1976,11 +1971,11 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { func cancelPreviewGestures() { } - func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? { + func transitionNodeForGallery(messageId: EngineMessage.Id, media: EngineMedia) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? { var transitionNode: (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? self.listNode.forEachItemNode { itemNode in if let itemNode = itemNode as? ListMessageNode { - if let result = itemNode.transitionNode(id: messageId, media: media) { + if let result = itemNode.transitionNode(id: messageId, media: media._asMedia()) { transitionNode = result } } @@ -2328,9 +2323,9 @@ private final class ChatListSearchShimmerNode: ASDisplayNode { let chatListPresentationData = ChatListPresentationData(theme: presentationData.theme, fontSize: presentationData.chatFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: true) - let peer1 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(0)), accessHash: nil, firstName: "FirstName", lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) + let peer1: EnginePeer = .user(TelegramUser(id: EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: EnginePeer.Id.Id._internalFromInt64Value(0)), accessHash: nil, firstName: "FirstName", lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])) let timestamp1: Int32 = 100000 - var peers = SimpleDictionary() + var peers: [EnginePeer.Id: EnginePeer] = [:] peers[peer1.id] = peer1 let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _, _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in }, messageSelected: { _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in }, activateChatPreview: { _, _, gesture in @@ -2340,33 +2335,140 @@ private final class ChatListSearchShimmerNode: ASDisplayNode { let items = (0 ..< 2).compactMap { _ -> ListViewItem? in switch key { case .chats: - return ChatListItem(presentationData: chatListPresentationData, context: context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(messages: [Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: timestamp1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer1, text: "Text", attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])], peer: RenderedPeer(peer: peer1), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false))]), isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction) + let message = EngineMessage( + stableId: 0, + stableVersion: 0, + id: EngineMessage.Id(peerId: peer1.id, namespace: 0, id: 0), + globallyUniqueId: nil, + groupingKey: nil, + groupInfo: nil, + threadId: nil, + timestamp: timestamp1, + flags: [], + tags: [], + globalTags: [], + localTags: [], + forwardInfo: nil, + author: peer1, + text: "Text", + attributes: [], + media: [], + peers: peers, + associatedMessages: [:], + associatedMessageIds: [] + ) + let readState = EnginePeerReadCounters() + return ChatListItem(presentationData: chatListPresentationData, context: context, peerGroupId: .root, filterData: nil, index: EngineChatList.Item.Index(pinningIndex: 0, messageIndex: EngineMessage.Index(id: EngineMessage.Id(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(messages: [message], peer: EngineRenderedPeer(peer: peer1), combinedReadState: readState, isRemovedFromTotalUnreadCount: false, presence: nil, hasUnseenMentions: false, draftState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction) case .media: return nil case .links: - var media: [Media] = [] - media.append(TelegramMediaWebpage(webpageId: MediaId(namespace: 0, id: 0), content: .Loaded(TelegramMediaWebpageLoadedContent(url: "https://telegram.org", displayUrl: "https://telegram.org", hash: 0, type: nil, websiteName: "Telegram", title: "Telegram Telegram", text: "Telegram", embedUrl: nil, embedType: nil, embedSize: nil, duration: nil, author: nil, image: nil, file: nil, attributes: [], instantPage: nil)))) - let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: timestamp1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer1, text: "Text", attributes: [], media: media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: []) + var media: [EngineMedia] = [] + media.append(.webpage(TelegramMediaWebpage(webpageId: EngineMedia.Id(namespace: 0, id: 0), content: .Loaded(TelegramMediaWebpageLoadedContent(url: "https://telegram.org", displayUrl: "https://telegram.org", hash: 0, type: nil, websiteName: "Telegram", title: "Telegram Telegram", text: "Telegram", embedUrl: nil, embedType: nil, embedSize: nil, duration: nil, author: nil, image: nil, file: nil, attributes: [], instantPage: nil))))) + let message = EngineMessage( + stableId: 0, + stableVersion: 0, + id: EngineMessage.Id(peerId: peer1.id, namespace: 0, id: 0), + globallyUniqueId: nil, + groupingKey: nil, + groupInfo: nil, + threadId: nil, + timestamp: timestamp1, + flags: [], + tags: [], + globalTags: [], + localTags: [], + forwardInfo: nil, + author: peer1, + text: "Text", + attributes: [], + media: media, + peers: peers, + associatedMessages: [:], + associatedMessageIds: [] + ) - return ListMessageItem(presentationData: ChatPresentationData(presentationData: presentationData), context: context, chatLocation: .peer(peer1.id), interaction: ListMessageItemInteraction.default, message: message, selection: hasSelection ? .selectable(selected: false) : .none, displayHeader: false, customHeader: nil, hintIsLink: true, isGlobalSearchResult: true) + return ListMessageItem(presentationData: ChatPresentationData(presentationData: presentationData), context: context, chatLocation: .peer(peer1.id), interaction: ListMessageItemInteraction.default, message: message._asMessage(), selection: hasSelection ? .selectable(selected: false) : .none, displayHeader: false, customHeader: nil, hintIsLink: true, isGlobalSearchResult: true) case .files: - var media: [Media] = [] - media.append(TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "application/text", size: 0, attributes: [.FileName(fileName: "Text.txt")])) - let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: timestamp1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer1, text: "Text", attributes: [], media: media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: []) + var media: [EngineMedia] = [] + media.append(.file(TelegramMediaFile(fileId: EngineMedia.Id(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "application/text", size: 0, attributes: [.FileName(fileName: "Text.txt")]))) + let message = EngineMessage( + stableId: 0, + stableVersion: 0, + id: EngineMessage.Id(peerId: peer1.id, namespace: 0, id: 0), + globallyUniqueId: nil, + groupingKey: nil, + groupInfo: nil, + threadId: nil, + timestamp: timestamp1, + flags: [], + tags: [], + globalTags: [], + localTags: [], + forwardInfo: nil, + author: peer1, + text: "Text", + attributes: [], + media: media, + peers: peers, + associatedMessages: [:], + associatedMessageIds: [] + ) - return ListMessageItem(presentationData: ChatPresentationData(presentationData: presentationData), context: context, chatLocation: .peer(peer1.id), interaction: ListMessageItemInteraction.default, message: message, selection: hasSelection ? .selectable(selected: false) : .none, displayHeader: false, customHeader: nil, hintIsLink: false, isGlobalSearchResult: true) + return ListMessageItem(presentationData: ChatPresentationData(presentationData: presentationData), context: context, chatLocation: .peer(peer1.id), interaction: ListMessageItemInteraction.default, message: message._asMessage(), selection: hasSelection ? .selectable(selected: false) : .none, displayHeader: false, customHeader: nil, hintIsLink: false, isGlobalSearchResult: true) case .music: - var media: [Media] = [] - media.append(TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: [.Audio(isVoice: false, duration: 0, title: nil, performer: nil, waveform: MemoryBuffer(data: Data()))])) - let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: timestamp1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer1, text: "Text", attributes: [], media: media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: []) + var media: [EngineMedia] = [] + media.append(.file(TelegramMediaFile(fileId: EngineMedia.Id(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: [.Audio(isVoice: false, duration: 0, title: nil, performer: nil, waveform: Data())]))) + let message = EngineMessage( + stableId: 0, + stableVersion: 0, + id: EngineMessage.Id(peerId: peer1.id, namespace: 0, id: 0), + globallyUniqueId: nil, + groupingKey: nil, + groupInfo: nil, + threadId: nil, + timestamp: timestamp1, + flags: [], + tags: [], + globalTags: [], + localTags: [], + forwardInfo: nil, + author: peer1, + text: "Text", + attributes: [], + media: media, + peers: peers, + associatedMessages: [:], + associatedMessageIds: [] + ) - return ListMessageItem(presentationData: ChatPresentationData(presentationData: presentationData), context: context, chatLocation: .peer(peer1.id), interaction: ListMessageItemInteraction.default, message: message, selection: hasSelection ? .selectable(selected: false) : .none, displayHeader: false, customHeader: nil, hintIsLink: false, isGlobalSearchResult: true) + return ListMessageItem(presentationData: ChatPresentationData(presentationData: presentationData), context: context, chatLocation: .peer(peer1.id), interaction: ListMessageItemInteraction.default, message: message._asMessage(), selection: hasSelection ? .selectable(selected: false) : .none, displayHeader: false, customHeader: nil, hintIsLink: false, isGlobalSearchResult: true) case .voice: - var media: [Media] = [] - media.append(TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: [.Audio(isVoice: true, duration: 0, title: nil, performer: nil, waveform: MemoryBuffer(data: Data()))])) - let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: timestamp1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer1, text: "Text", attributes: [], media: media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: []) + var media: [EngineMedia] = [] + media.append(.file(TelegramMediaFile(fileId: EngineMedia.Id(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: [.Audio(isVoice: true, duration: 0, title: nil, performer: nil, waveform: Data())]))) + let message = EngineMessage( + stableId: 0, + stableVersion: 0, + id: EngineMessage.Id(peerId: peer1.id, namespace: 0, id: 0), + globallyUniqueId: nil, + groupingKey: nil, + groupInfo: nil, + threadId: nil, + timestamp: timestamp1, + flags: [], + tags: [], + globalTags: [], + localTags: [], + forwardInfo: nil, + author: peer1, + text: "Text", + attributes: [], + media: media, + peers: peers, + associatedMessages: [:], + associatedMessageIds: [] + ) - return ListMessageItem(presentationData: ChatPresentationData(presentationData: presentationData), context: context, chatLocation: .peer(peer1.id), interaction: ListMessageItemInteraction.default, message: message, selection: hasSelection ? .selectable(selected: false) : .none, displayHeader: false, customHeader: nil, hintIsLink: false, isGlobalSearchResult: true) + return ListMessageItem(presentationData: ChatPresentationData(presentationData: presentationData), context: context, chatLocation: .peer(peer1.id), interaction: ListMessageItemInteraction.default, message: message._asMessage(), selection: hasSelection ? .selectable(selected: false) : .none, displayHeader: false, customHeader: nil, hintIsLink: false, isGlobalSearchResult: true) } } diff --git a/submodules/ChatListUI/Sources/ChatListSearchMediaNode.swift b/submodules/ChatListUI/Sources/ChatListSearchMediaNode.swift index cad629e5b9..3000caaced 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchMediaNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchMediaNode.swift @@ -703,7 +703,7 @@ final class ChatListSearchMediaNode: ASDisplayNode, UIScrollViewDelegate { if let entries = entries { for entry in entries { if case let .message(message, _, _, _, _, _, _) = entry { - self.mediaItems.append(VisualMediaItem(message: message, index: nil)) + self.mediaItems.append(VisualMediaItem(message: message._asMessage(), index: nil)) } index += 1 } diff --git a/submodules/ChatListUI/Sources/ChatListSearchPaneContainerNode.swift b/submodules/ChatListUI/Sources/ChatListSearchPaneContainerNode.swift index 03bbd298fb..7c8e7601c1 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchPaneContainerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchPaneContainerNode.swift @@ -4,7 +4,6 @@ import AsyncDisplayKit import Display import SwiftSignalKit import TelegramPresentationData -import Postbox import TelegramCore import AccountContext import ContextUI @@ -15,12 +14,12 @@ protocol ChatListSearchPaneNode: ASDisplayNode { func update(size: CGSize, sideInset: CGFloat, bottomInset: CGFloat, visibleHeight: CGFloat, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) func scrollToTop() -> Bool func cancelPreviewGestures() - func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? + func transitionNodeForGallery(messageId: EngineMessage.Id, media: EngineMedia) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? func addToTransitionSurface(view: UIView) func updateHiddenMedia() func updateSelectedMessages(animated: Bool) func previewViewAndActionAtLocation(_ location: CGPoint) -> (UIView, CGRect, Any)? - var searchCurrentMessages: [Message]? { get } + var searchCurrentMessages: [EngineMessage]? { get } } final class ChatListSearchPaneWrapper { @@ -76,7 +75,7 @@ private final class ChatListSearchPendingPane { interaction: ChatListSearchInteraction, navigationController: NavigationController?, peersFilter: ChatListNodePeersFilter, - groupId: PeerGroupId, + groupId: EngineChatList.Group, searchQuery: Signal, searchOptions: Signal, key: ChatListSearchPaneKey, @@ -102,7 +101,7 @@ final class ChatListSearchPaneContainerNode: ASDisplayNode, UIGestureRecognizerD private let context: AccountContext private let updatedPresentationData: (initial: PresentationData, signal: Signal)? private let peersFilter: ChatListNodePeersFilter - private let groupId: PeerGroupId + private let groupId: EngineChatList.Group private let searchQuery: Signal private let searchOptions: Signal private let navigationController: NavigationController? @@ -136,7 +135,7 @@ final class ChatListSearchPaneContainerNode: ASDisplayNode, UIGestureRecognizerD private var currentAvailablePanes: [ChatListSearchPaneKey]? - init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, peersFilter: ChatListNodePeersFilter, groupId: PeerGroupId, searchQuery: Signal, searchOptions: Signal, navigationController: NavigationController?) { + init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, peersFilter: ChatListNodePeersFilter, groupId: EngineChatList.Group, searchQuery: Signal, searchOptions: Signal, navigationController: NavigationController?) { self.context = context self.updatedPresentationData = updatedPresentationData self.peersFilter = peersFilter @@ -280,11 +279,11 @@ final class ChatListSearchPaneContainerNode: ASDisplayNode, UIGestureRecognizerD self.currentPane?.node.updateHiddenMedia() } - func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? { + func transitionNodeForGallery(messageId: EngineMessage.Id, media: EngineMedia) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? { return self.currentPane?.node.transitionNodeForGallery(messageId: messageId, media: media) } - func updateSelectedMessageIds(_ selectedMessageIds: Set?, animated: Bool) { + func updateSelectedMessageIds(_ selectedMessageIds: Set?, animated: Bool) { for (_, pane) in self.currentPanes { pane.node.updateSelectedMessages(animated: animated) } @@ -497,8 +496,8 @@ final class ChatListSearchPaneContainerNode: ASDisplayNode, UIGestureRecognizerD self.currentPaneUpdated?(self.currentPaneKey, self.transitionFraction, transition) } - func allCurrentMessages() -> [MessageId: Message] { - var allMessages: [MessageId: Message] = [:] + func allCurrentMessages() -> [EngineMessage.Id: EngineMessage] { + var allMessages: [EngineMessage.Id: EngineMessage] = [:] for (_, pane) in self.currentPanes { if let messages = pane.node.searchCurrentMessages { for message in messages { diff --git a/submodules/ChatListUI/Sources/Node/ChatListItem.swift b/submodules/ChatListUI/Sources/Node/ChatListItem.swift index b761a7d3f5..64cd7f5516 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItem.swift @@ -1,7 +1,6 @@ import Foundation import UIKit import AsyncDisplayKit -import Postbox import Display import SwiftSignalKit import TelegramCore @@ -20,8 +19,23 @@ import ContextUI import ChatInterfaceState public enum ChatListItemContent { - case peer(messages: [Message], peer: RenderedPeer, combinedReadState: CombinedPeerReadState?, isRemovedFromTotalUnreadCount: Bool, presence: PeerPresence?, summaryInfo: ChatListMessageTagSummaryInfo, embeddedState: StoredPeerChatInterfaceState?, inputActivities: [(Peer, PeerInputActivity)]?, promoInfo: ChatListNodeEntryPromoInfo?, ignoreUnreadBadge: Bool, displayAsMessage: Bool, hasFailedMessages: Bool) - case groupReference(groupId: PeerGroupId, peers: [ChatListGroupReferencePeer], message: Message?, unreadState: PeerGroupUnreadCountersCombinedSummary, hiddenByDefault: Bool) + public final class DraftState: Equatable { + let text: String + + public init(text: String) { + self.text = text + } + + public static func ==(lhs: DraftState, rhs: DraftState) -> Bool { + if lhs.text != rhs.text { + return false + } + return true + } + } + + case peer(messages: [EngineMessage], peer: EngineRenderedPeer, combinedReadState: EnginePeerReadCounters?, isRemovedFromTotalUnreadCount: Bool, presence: EnginePeer.Presence?, hasUnseenMentions: Bool, draftState: DraftState?, inputActivities: [(EnginePeer, PeerInputActivity)]?, promoInfo: ChatListNodeEntryPromoInfo?, ignoreUnreadBadge: Bool, displayAsMessage: Bool, hasFailedMessages: Bool) + case groupReference(groupId: EngineChatList.Group, peers: [EngineChatList.GroupItem.Item], message: EngineMessage?, unreadCount: Int, hiddenByDefault: Bool) public var chatLocation: ChatLocation? { switch self { @@ -36,9 +50,9 @@ public enum ChatListItemContent { public class ChatListItem: ListViewItem, ChatListSearchItemNeighbour { let presentationData: ChatListPresentationData let context: AccountContext - let peerGroupId: PeerGroupId + let peerGroupId: EngineChatList.Group let filterData: ChatListItemFilterData? - let index: ChatListIndex + let index: EngineChatList.Item.Index public let content: ChatListItemContent let editing: Bool let hasActiveRevealControls: Bool @@ -59,7 +73,7 @@ public class ChatListItem: ListViewItem, ChatListSearchItemNeighbour { return self.index.pinningIndex != nil } - public init(presentationData: ChatListPresentationData, context: AccountContext, peerGroupId: PeerGroupId, filterData: ChatListItemFilterData?, index: ChatListIndex, content: ChatListItemContent, editing: Bool, hasActiveRevealControls: Bool, selected: Bool, header: ListViewItemHeader?, enableContextActions: Bool, hiddenOffset: Bool, interaction: ChatListNodeInteraction) { + public init(presentationData: ChatListPresentationData, context: AccountContext, peerGroupId: EngineChatList.Group, filterData: ChatListItemFilterData?, index: EngineChatList.Item.Index, content: ChatListItemContent, editing: Bool, hasActiveRevealControls: Bool, selected: Bool, header: ListViewItemHeader?, enableContextActions: Bool, hiddenOffset: Bool, interaction: ChatListNodeInteraction) { self.presentationData = presentationData self.peerGroupId = peerGroupId self.filterData = filterData @@ -195,7 +209,7 @@ private enum RevealOptionKey: Int32 { case hidePsa } -private func canArchivePeer(id: PeerId, accountPeerId: PeerId) -> Bool { +private func canArchivePeer(id: EnginePeer.Id, accountPeerId: EnginePeer.Id) -> Bool { if id.namespace == Namespaces.Peer.CloudUser && id.id._internalGetInt64Value() == 777000 { return false } @@ -213,10 +227,10 @@ public struct ChatListItemFilterData: Equatable { } } -private func revealOptions(strings: PresentationStrings, theme: PresentationTheme, isPinned: Bool, isMuted: Bool?, groupId: PeerGroupId, peerId: PeerId, accountPeerId: PeerId, canDelete: Bool, isEditing: Bool, filterData: ChatListItemFilterData?) -> [ItemListRevealOption] { +private func revealOptions(strings: PresentationStrings, theme: PresentationTheme, isPinned: Bool, isMuted: Bool?, groupId: EngineChatList.Group, peerId: EnginePeer.Id, accountPeerId: EnginePeer.Id, canDelete: Bool, isEditing: Bool, filterData: ChatListItemFilterData?) -> [ItemListRevealOption] { var options: [ItemListRevealOption] = [] if !isEditing { - if case .group = groupId { + if case .archive = groupId { if isPinned { options.append(ItemListRevealOption(key: RevealOptionKey.unpin.rawValue, title: strings.DialogList_Unpin, icon: unpinIcon, color: theme.list.itemDisclosureActions.constructive.fillColor, textColor: theme.list.itemDisclosureActions.constructive.foregroundColor)) } else { @@ -272,8 +286,8 @@ private func groupReferenceRevealOptions(strings: PresentationStrings, theme: Pr return options } -private func leftRevealOptions(strings: PresentationStrings, theme: PresentationTheme, isUnread: Bool, isEditing: Bool, isPinned: Bool, isSavedMessages: Bool, groupId: PeerGroupId, peer: Peer, filterData: ChatListItemFilterData?) -> [ItemListRevealOption] { - if case .group = groupId { +private func leftRevealOptions(strings: PresentationStrings, theme: PresentationTheme, isUnread: Bool, isEditing: Bool, isPinned: Bool, isSavedMessages: Bool, groupId: EngineChatList.Group, peer: EnginePeer, filterData: ChatListItemFilterData?) -> [ItemListRevealOption] { + if case .archive = groupId { return [] } var options: [ItemListRevealOption] = [] @@ -332,8 +346,8 @@ private let playIconImage = UIImage(bundleImageName: "Chat List/MiniThumbnailPla private final class ChatListMediaPreviewNode: ASDisplayNode { private let context: AccountContext - private let message: Message - private let media: Media + private let message: EngineMessage + private let media: EngineMedia private let imageNode: TransformImageNode private let playIcon: ASImageNode @@ -341,7 +355,7 @@ private final class ChatListMediaPreviewNode: ASDisplayNode { private var requestedImage: Bool = false private var disposable: Disposable? - init(context: AccountContext, message: Message, media: Media) { + init(context: AccountContext, message: EngineMessage, media: EngineMedia) { self.context = context self.message = message self.media = media @@ -366,17 +380,17 @@ private final class ChatListMediaPreviewNode: ASDisplayNode { } var dimensions = CGSize(width: 100.0, height: 100.0) - if let image = self.media as? TelegramMediaImage { + if case let .image(image) = self.media { self.playIcon.isHidden = true if let largest = largestImageRepresentation(image.representations) { dimensions = largest.dimensions.cgSize if !self.requestedImage { self.requestedImage = true - let signal = mediaGridMessagePhoto(account: self.context.account, photoReference: .message(message: MessageReference(self.message), media: image), fullRepresentationSize: CGSize(width: 36.0, height: 36.0), synchronousLoad: synchronousLoads) + let signal = mediaGridMessagePhoto(account: self.context.account, photoReference: .message(message: MessageReference(self.message._asMessage()), media: image), fullRepresentationSize: CGSize(width: 36.0, height: 36.0), synchronousLoad: synchronousLoads) self.imageNode.setSignal(signal, attemptSynchronously: synchronousLoads) } } - } else if let file = self.media as? TelegramMediaFile { + } else if case let .file(file) = self.media { if file.isAnimated { self.playIcon.isHidden = true } else { @@ -386,7 +400,7 @@ private final class ChatListMediaPreviewNode: ASDisplayNode { dimensions = mediaDimensions.cgSize if !self.requestedImage { self.requestedImage = true - let signal = mediaGridMessageVideo(postbox: self.context.account.postbox, videoReference: .message(message: MessageReference(self.message), media: file), synchronousLoad: synchronousLoads, autoFetchFullSizeThumbnail: true, useMiniThumbnailIfAvailable: true) + let signal = mediaGridMessageVideo(postbox: self.context.account.postbox, videoReference: .message(message: MessageReference(self.message._asMessage()), media: file), synchronousLoad: synchronousLoads, autoFetchFullSizeThumbnail: true, useMiniThumbnailIfAvailable: true) self.imageNode.setSignal(signal, attemptSynchronously: synchronousLoads) } } @@ -426,8 +440,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { let mutedIconNode: ASImageNode private var currentTextLeftCutout: CGFloat = 0.0 - private var currentMediaPreviewSpecs: [(message: Message, media: Media, size: CGSize)] = [] - private var mediaPreviewNodes: [MediaId: ChatListMediaPreviewNode] = [:] + private var currentMediaPreviewSpecs: [(message: EngineMessage, media: EngineMedia, size: CGSize)] = [] + private var mediaPreviewNodes: [EngineMedia.Id: ChatListMediaPreviewNode] = [:] var selectableControlNode: ItemListSelectableControlNode? var reorderControlNode: ItemListEditableReorderControlNode? @@ -477,11 +491,11 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { return nil } switch item.content { - case let .groupReference(_, _, _, unreadState, _): + case let .groupReference(_, _, _, unreadCount, _): var result = item.presentationData.strings.ChatList_ArchivedChatsTitle - let allCount = unreadState.count(countingCategory: .chats, mutedCategory: .all) + let allCount = unreadCount if allCount > 0 { - result += "\n\(item.presentationData.strings.VoiceOver_Chat_UnreadMessages(allCount))" + result += "\n\(item.presentationData.strings.VoiceOver_Chat_UnreadMessages(Int32(allCount)))" } return result case let .peer(_, peer, combinedReadState, _, _, _, _, _, _, _, _, _): @@ -492,7 +506,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { if item.context.account.peerId == chatMainPeer.id { result += item.presentationData.strings.DialogList_SavedMessages } else { - result += EnginePeer(chatMainPeer).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) + result += chatMainPeer.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) } if let combinedReadState = combinedReadState, combinedReadState.count > 0 { result += "\n\(item.presentationData.strings.VoiceOver_Chat_UnreadMessages(combinedReadState.count))" @@ -519,8 +533,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { result += item.presentationData.strings.VoiceOver_ChatList_OutgoingMessage } let (_, initialHideAuthor, messageText) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: peer, accountPeerId: item.context.account.peerId, isPeerGroup: false) - if message.flags.contains(.Incoming), !initialHideAuthor, let author = message.author, author is TelegramUser { - result += "\n\(item.presentationData.strings.VoiceOver_ChatList_MessageFrom(EnginePeer(author).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)).string)" + if message.flags.contains(.Incoming), !initialHideAuthor, let author = message.author, case .user = author { + result += "\n\(item.presentationData.strings.VoiceOver_ChatList_MessageFrom(author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)).string)" } result += "\n\(messageText)" return result @@ -529,7 +543,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { var isFirst = true for peer in peers { if let chatMainPeer = peer.peer.chatMainPeer { - let peerTitle = EnginePeer(chatMainPeer).compactDisplayTitle + let peerTitle = chatMainPeer.compactDisplayTitle if !peerTitle.isEmpty { if isFirst { isFirst = false @@ -553,8 +567,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { result += item.presentationData.strings.VoiceOver_ChatList_OutgoingMessage } let (_, initialHideAuthor, messageText) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: peer, accountPeerId: item.context.account.peerId, isPeerGroup: false) - if message.flags.contains(.Incoming), !initialHideAuthor, let author = message.author, author is TelegramUser { - result += "\n\(item.presentationData.strings.VoiceOver_ChatList_MessageFrom(EnginePeer(author).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)).string)" + if message.flags.contains(.Incoming), !initialHideAuthor, let author = message.author, case .user = author { + result += "\n\(item.presentationData.strings.VoiceOver_ChatList_MessageFrom(author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)).string)" } if !message.flags.contains(.Incoming), let combinedReadState = combinedReadState, combinedReadState.isOutgoingMessageIndexRead(message.index) { result += "\n\(item.presentationData.strings.VoiceOver_ChatList_MessageRead)" @@ -662,14 +676,14 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { let previousItem = self.item self.item = item - var peer: Peer? + var peer: EnginePeer? var displayAsMessage = false var enablePreview = true switch item.content { case let .peer(messages, peerValue, _, _, _, _, _, _, _, _, displayAsMessageValue, _): displayAsMessage = displayAsMessageValue - if displayAsMessage, let author = messages.last?.author as? TelegramUser { - peer = author + if displayAsMessage, case let .user(author) = messages.last?.author { + peer = .user(author) } else { peer = peerValue.chatMainPeer } @@ -681,7 +695,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { UIView.transition(with: self.avatarNode.view, duration: 0.3, options: [.transitionCrossDissolve], animations: { }, completion: nil) } - self.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: peer.flatMap(EnginePeer.init), overrideImage: .archivedChatsIcon(hiddenByDefault: hiddenByDefault), emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: synchronousLoads) + self.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: peer, overrideImage: .archivedChatsIcon(hiddenByDefault: hiddenByDefault), emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: synchronousLoads) } if let peer = peer { @@ -693,7 +707,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } else if peer.isDeleted { overrideImage = .deletedIcon } - self.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: EnginePeer(peer), overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: synchronousLoads, displayDimensions: CGSize(width: 60.0, height: 60.0)) + self.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: peer, overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: synchronousLoads, displayDimensions: CGSize(width: 60.0, height: 60.0)) } self.contextContainer.isGestureEnabled = enablePreview && !item.editing @@ -804,19 +818,19 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { let badgeFont = Font.with(size: floor(item.presentationData.fontSize.itemListBaseFontSize * 14.0 / 17.0), design: .regular, weight: .regular, traits: [.monospacedNumbers]) let account = item.context.account - var messages: [Message] + var messages: [EngineMessage] enum ContentPeer { - case chat(RenderedPeer) - case group([ChatListGroupReferencePeer]) + case chat(EngineRenderedPeer) + case group([EngineChatList.GroupItem.Item]) } let contentPeer: ContentPeer - let combinedReadState: CombinedPeerReadState? + let combinedReadState: EnginePeerReadCounters? let unreadCount: (count: Int32, unread: Bool, muted: Bool, mutedCount: Int32?) let isRemovedFromTotalUnreadCount: Bool - let peerPresence: PeerPresence? - let embeddedState: StoredPeerChatInterfaceState? - let summaryInfo: ChatListMessageTagSummaryInfo - let inputActivities: [(Peer, PeerInputActivity)]? + let peerPresence: EnginePeer.Presence? + let draftState: ChatListItemContent.DraftState? + let hasUnseenMentions: Bool + let inputActivities: [(EnginePeer, PeerInputActivity)]? let isPeerGroup: Bool let promoInfo: ChatListNodeEntryPromoInfo? let displayAsMessage: Bool @@ -825,7 +839,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { var groupHiddenByDefault = false switch item.content { - case let .peer(messagesValue, peerValue, combinedReadStateValue, isRemovedFromTotalUnreadCountValue, peerPresenceValue, summaryInfoValue, embeddedStateValue, inputActivitiesValue, promoInfoValue, ignoreUnreadBadge, displayAsMessageValue, _): + case let .peer(messagesValue, peerValue, combinedReadStateValue, isRemovedFromTotalUnreadCountValue, peerPresenceValue, hasUnseenMentionsValue, draftStateValue, inputActivitiesValue, promoInfoValue, ignoreUnreadBadge, displayAsMessageValue, _): messages = messagesValue contentPeer = .chat(peerValue) combinedReadState = combinedReadStateValue @@ -839,15 +853,15 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } else { isRemovedFromTotalUnreadCount = isRemovedFromTotalUnreadCountValue } - peerPresence = (peerPresenceValue as? TelegramUserPresence).flatMap { presence -> TelegramUserPresence in - TelegramUserPresence(status: presence.status, lastActivity: 0) + peerPresence = peerPresenceValue.flatMap { presence -> EnginePeer.Presence in + return EnginePeer.Presence(status: presence.status, lastActivity: 0) } - embeddedState = embeddedStateValue - summaryInfo = summaryInfoValue + draftState = draftStateValue + hasUnseenMentions = hasUnseenMentionsValue switch peerValue.peer { - case _ as TelegramUser, _ as TelegramSecretChat: - if let peerPresence = peerPresence as? TelegramUserPresence, case .present = peerPresence.status { + case .user, .secretChat: + if let peerPresence = peerPresence, case .present = peerPresence.status { inputActivities = inputActivitiesValue } else { inputActivities = nil @@ -860,7 +874,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { promoInfo = promoInfoValue displayAsMessage = displayAsMessageValue hasFailedMessages = messagesValue.last?.flags.contains(.Failed) ?? false // hasFailedMessagesValue - case let .groupReference(_, peers, messageValue, unreadState, hiddenByDefault): + case let .groupReference(_, peers, messageValue, unreadCountValue, hiddenByDefault): if let _ = messageValue, !peers.isEmpty { contentPeer = .chat(peers[0].peer) } else { @@ -873,13 +887,12 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } combinedReadState = nil isRemovedFromTotalUnreadCount = false - embeddedState = nil - summaryInfo = ChatListMessageTagSummaryInfo() + draftState = nil + hasUnseenMentions = false inputActivities = nil isPeerGroup = true groupHiddenByDefault = hiddenByDefault - let allCount = unreadState.count(countingCategory: .chats, mutedCategory: .all) - unreadCount = (allCount, allCount != 0, true, nil) + unreadCount = (Int32(unreadCountValue), unreadCountValue != 0, true, nil) peerPresence = nil promoInfo = nil displayAsMessage = false @@ -949,8 +962,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { let leftInset: CGFloat = params.leftInset + avatarLeftInset enum ContentData { - case chat(itemPeer: RenderedPeer, peer: Peer?, hideAuthor: Bool, messageText: String) - case group(peers: [ChatListGroupReferencePeer]) + case chat(itemPeer: EngineRenderedPeer, peer: EnginePeer?, hideAuthor: Bool, messageText: String) + case group(peers: [EngineChatList.GroupItem.Item]) } let contentData: ContentData @@ -977,11 +990,11 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { var inlineAuthorPrefix: String? if case .groupReference = item.content { - if let author = messages.last?.author as? TelegramUser { + if case let .user(author) = messages.last?.author { if author.id == item.context.account.peerId { inlineAuthorPrefix = item.presentationData.strings.DialogList_You } else if messages.last?.id.peerId.namespace != Namespaces.Peer.CloudUser && messages.last?.id.peerId.namespace != Namespaces.Peer.SecretChat { - inlineAuthorPrefix = EnginePeer(author).compactDisplayTitle + inlineAuthorPrefix = EnginePeer.user(author).compactDisplayTitle } } } @@ -993,17 +1006,22 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { let contentImageSize = CGSize(width: contentImageSide, height: contentImageSide) let contentImageSpacing: CGFloat = 2.0 let contentImageTrailingSpace: CGFloat = 5.0 - var contentImageSpecs: [(message: Message, media: Media, size: CGSize)] = [] + var contentImageSpecs: [(message: EngineMessage, media: EngineMedia, size: CGSize)] = [] switch contentData { case let .chat(itemPeer, _, _, text): + var isUser = false + if case .user = itemPeer.chatMainPeer { + isUser = true + } + var peerText: String? if case .groupReference = item.content { if let messagePeer = itemPeer.chatMainPeer { - peerText = EnginePeer(messagePeer).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) + peerText = messagePeer.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) } - } else if let message = messages.last, let author = message.author as? TelegramUser, let peer = itemPeer.chatMainPeer, !(peer is TelegramUser) { - if let peer = peer as? TelegramChannel, case .broadcast = peer.info { + } else if let message = messages.last, case let .user(author) = message.author, let peer = itemPeer.chatMainPeer, !isUser { + if case let .channel(peer) = peer, case .broadcast = peer.info { } else if !displayAsMessage { if let forwardInfo = message.forwardInfo, forwardInfo.flags.contains(.isImported), let authorSignature = forwardInfo.authorSignature { peerText = authorSignature @@ -1022,13 +1040,11 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { chatListText = (text, messageText) } - if inlineAuthorPrefix == nil, let embeddedState = embeddedState, embeddedState.overrideChatTimestamp != nil, let opaqueState = _internal_decodeStoredChatInterfaceState(state: embeddedState) { - let interfaceState = ChatInterfaceState.parse(opaqueState) - + if inlineAuthorPrefix == nil, let draftState = draftState { hasDraft = true authorAttributedString = NSAttributedString(string: item.presentationData.strings.DialogList_Draft, font: textFont, textColor: theme.messageDraftTextColor) - let draftText: String = interfaceState.composeInputState.inputText.string + let draftText: String = draftState.text attributedText = NSAttributedString(string: foldLineBreaks(draftText.replacingOccurrences(of: "\n\n", with: " ")), font: textFont, textColor: theme.messageTextColor) } else if let message = messages.last { @@ -1081,7 +1097,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } var displayMediaPreviews = true - if message.containsSecretMedia { + if message._asMessage().containsSecretMedia { displayMediaPreviews = false } else if let _ = message.peers[message.id.peerId] as? TelegramSecretChat { displayMediaPreviews = false @@ -1096,34 +1112,28 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { inner: for media in message.media { if let image = media as? TelegramMediaImage { if let _ = largestImageRepresentation(image.representations) { - //let imageSize = largest.dimensions.cgSize - //let fitSize = imageSize.aspectFilled(contentImageFillSize) let fitSize = contentImageSize - contentImageSpecs.append((message, image, fitSize)) + contentImageSpecs.append((message, .image(image), fitSize)) } break inner } else if let file = media as? TelegramMediaFile { if file.isVideo, !file.isInstantVideo, let _ = file.dimensions { - //let imageSize = dimensions.cgSize - //let fitSize = imageSize.aspectFilled(contentImageFillSize) let fitSize = contentImageSize - contentImageSpecs.append((message, file, fitSize)) + contentImageSpecs.append((message, .file(file), fitSize)) } break inner } else if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content { let imageTypes = ["photo", "video", "embed", "gif", "document", "telegram_album"] if let image = content.image, let type = content.type, imageTypes.contains(type) { if let _ = largestImageRepresentation(image.representations) { - //let imageSize = largest.dimensions.cgSize let fitSize = contentImageSize - contentImageSpecs.append((message, image, fitSize)) + contentImageSpecs.append((message, .image(image), fitSize)) } break inner } else if let file = content.file { if file.isVideo, !file.isInstantVideo, let _ = file.dimensions { - //let imageSize = dimensions.cgSize let fitSize = contentImageSize - contentImageSpecs.append((message, file, fitSize)) + contentImageSpecs.append((message, .file(file), fitSize)) } break inner } @@ -1137,7 +1147,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { var peerText: String? if case .groupReference = item.content { if let messagePeer = itemPeer.chatMainPeer { - peerText = EnginePeer(messagePeer).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) + peerText = messagePeer.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) } } @@ -1150,7 +1160,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { var isFirst = true for peer in peers { if let chatMainPeer = peer.peer.chatMainPeer { - let peerTitle = EnginePeer(chatMainPeer).compactDisplayTitle + let peerTitle = chatMainPeer.compactDisplayTitle if !peerTitle.isEmpty { if isFirst { isFirst = false @@ -1176,15 +1186,15 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { switch contentData { case let .chat(itemPeer, _, _, _): - if let message = messages.last, let author = message.author as? TelegramUser, displayAsMessage { - titleAttributedString = NSAttributedString(string: author.id == account.peerId ? item.presentationData.strings.DialogList_You : EnginePeer(author).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder), font: titleFont, textColor: theme.titleColor) + if let message = messages.last, case let .user(author) = message.author, displayAsMessage { + titleAttributedString = NSAttributedString(string: author.id == account.peerId ? item.presentationData.strings.DialogList_You : EnginePeer.user(author).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder), font: titleFont, textColor: theme.titleColor) } else if isPeerGroup { titleAttributedString = NSAttributedString(string: item.presentationData.strings.ChatList_ArchivedChatsTitle, font: titleFont, textColor: theme.titleColor) } else if itemPeer.chatMainPeer?.id == item.context.account.peerId { titleAttributedString = NSAttributedString(string: item.presentationData.strings.DialogList_SavedMessages, font: titleFont, textColor: theme.titleColor) } else if let id = itemPeer.chatMainPeer?.id, id.isReplies { titleAttributedString = NSAttributedString(string: item.presentationData.strings.DialogList_Replies, font: titleFont, textColor: theme.titleColor) - } else if let displayTitle = itemPeer.chatMainPeer.flatMap(EnginePeer.init)?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) { + } else if let displayTitle = itemPeer.chatMainPeer?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) { titleAttributedString = NSAttributedString(string: displayTitle, font: titleFont, textColor: item.index.messageIndex.id.peerId.namespace == Namespaces.Peer.SecretChat ? theme.secretTitleColor : theme.titleColor) } case .group: @@ -1221,7 +1231,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } if !isPeerGroup, let message = messages.last, message.author?.id == account.peerId && !hasDraft { - if message.flags.isSending && !message.isSentOrAcknowledged { + if message.flags.isSending && !message._asMessage().isSentOrAcknowledged { statusState = .clock(PresentationResourcesChatList.clockFrameImage(item.presentationData.theme), PresentationResourcesChatList.clockMinImage(item.presentationData.theme)) } else if message.id.peerId != account.peerId { if hasFailedMessages { @@ -1263,13 +1273,10 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } } } - - let tagSummaryCount = summaryInfo.tagSummaryCount ?? 0 - let actionsSummaryCount = summaryInfo.actionsSummaryCount ?? 0 - let totalMentionCount = tagSummaryCount - actionsSummaryCount + if !isPeerGroup { - if totalMentionCount > 0 { - if Namespaces.PeerGroup.archive == item.peerGroupId { + if hasUnseenMentions { + if case .archive = item.peerGroupId { currentMentionBadgeImage = PresentationResourcesChatList.badgeBackgroundInactiveMention(item.presentationData.theme, diameter: badgeDiameter) } else { currentMentionBadgeImage = PresentationResourcesChatList.badgeBackgroundMention(item.presentationData.theme, diameter: badgeDiameter) @@ -1414,20 +1421,20 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { switch item.content { case let .peer(_, renderedPeer, _, _, presence, _ ,_ ,_, _, _, displayAsMessage, _): if !displayAsMessage { - if let peer = renderedPeer.chatMainPeer as? TelegramUser, let presence = presence as? TelegramUserPresence, !isServicePeer(peer) && !peer.flags.contains(.isSupport) && peer.id != item.context.account.peerId { - let updatedPresence = TelegramUserPresence(status: presence.status, lastActivity: 0) - let relativeStatus = relativeUserPresenceStatus(EnginePeer.Presence(updatedPresence), relativeTo: timestamp) + if case let .user(peer) = renderedPeer.chatMainPeer, let presence = presence, !isServicePeer(peer) && !peer.flags.contains(.isSupport) && peer.id != item.context.account.peerId { + let updatedPresence = EnginePeer.Presence(status: presence.status, lastActivity: 0) + let relativeStatus = relativeUserPresenceStatus(updatedPresence, relativeTo: timestamp) if case .online = relativeStatus { online = true } animateOnline = true - } else if let channel = renderedPeer.peer as? TelegramChannel { + } else if case let .channel(channel) = renderedPeer.peer { onlineIsVoiceChat = true if channel.flags.contains(.hasActiveVoiceChat) && item.interaction.searchTextHighightState == nil { online = true } animateOnline = true - } else if let group = renderedPeer.peer as? TelegramGroup { + } else if case let .legacyGroup(group) = renderedPeer.peer { onlineIsVoiceChat = true if group.flags.contains(.hasActiveVoiceChat) && item.interaction.searchTextHighightState == nil { online = true @@ -1780,7 +1787,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { inputActivitiesApply?() var mediaPreviewOffset = textNodeFrame.origin.offsetBy(dx: 1.0, dy: floor((measureLayout.size.height - contentImageSize.height) / 2.0)) - var validMediaIds: [MediaId] = [] + var validMediaIds: [EngineMedia.Id] = [] for (message, media, mediaSize) in contentImageSpecs { guard let mediaId = media.id else { continue @@ -1803,7 +1810,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { previewNodeTransition.updateFrame(node: previewNode, frame: CGRect(origin: mediaPreviewOffset, size: mediaSize)) mediaPreviewOffset.x += mediaSize.width + contentImageSpacing } - var removeMediaIds: [MediaId] = [] + var removeMediaIds: [EngineMedia.Id] = [] for (mediaId, itemNode) in strongSelf.mediaPreviewNodes { if !validMediaIds.contains(mediaId) { removeMediaIds.append(mediaId) @@ -1864,8 +1871,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { let topNegativeInset: CGFloat = 0.0 strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: layoutOffset - separatorHeight - topNegativeInset), size: CGSize(width: layout.contentSize.width, height: layout.contentSize.height + separatorHeight + topNegativeInset)) - if let peerPresence = peerPresence as? TelegramUserPresence { - strongSelf.peerPresenceManager?.reset(presence: EnginePeer.Presence(TelegramUserPresence(status: peerPresence.status, lastActivity: 0)), isOnline: online) + if let peerPresence = peerPresence { + strongSelf.peerPresenceManager?.reset(presence: EnginePeer.Presence(status: peerPresence.status, lastActivity: 0), isOnline: online) } strongSelf.updateLayout(size: layout.contentSize, leftInset: params.leftInset, rightInset: params.rightInset) @@ -2057,7 +2064,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { case RevealOptionKey.pin.rawValue: switch item.content { case .peer: - let itemId: PinnedItemId = .peer(item.index.messageIndex.id.peerId) + let itemId: EngineChatList.PinnedItem.Id = .peer(item.index.messageIndex.id.peerId) item.interaction.setItemPinned(itemId, true) case .groupReference: break @@ -2065,7 +2072,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { case RevealOptionKey.unpin.rawValue: switch item.content { case .peer: - let itemId: PinnedItemId = .peer(item.index.messageIndex.id.peerId) + let itemId: EngineChatList.PinnedItem.Id = .peer(item.index.messageIndex.id.peerId) item.interaction.setItemPinned(itemId, false) case .groupReference: break diff --git a/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift b/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift index dcae9682c3..2a3e577c9f 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift @@ -1,5 +1,4 @@ import Foundation -import Postbox import TelegramCore import TelegramPresentationData import TelegramUIPreferences @@ -14,7 +13,7 @@ private enum MessageGroupType { case generic } -private func singleMessageType(message: Message) -> MessageGroupType { +private func singleMessageType(message: EngineMessage) -> MessageGroupType { for media in message.media { if let _ = media as? TelegramMediaImage { return .photos @@ -31,7 +30,7 @@ private func singleMessageType(message: Message) -> MessageGroupType { return .generic } -private func messageGroupType(messages: [Message]) -> MessageGroupType { +private func messageGroupType(messages: [EngineMessage]) -> MessageGroupType { if messages.isEmpty { return .generic } @@ -45,16 +44,16 @@ private func messageGroupType(messages: [Message]) -> MessageGroupType { return currentType } -public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, messages: [Message], chatPeer: RenderedPeer, accountPeerId: PeerId, enableMediaEmoji: Bool = true, isPeerGroup: Bool = false) -> (peer: Peer?, hideAuthor: Bool, messageText: String) { - let peer: Peer? +public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, messages: [EngineMessage], chatPeer: EngineRenderedPeer, accountPeerId: EnginePeer.Id, enableMediaEmoji: Bool = true, isPeerGroup: Bool = false) -> (peer: EnginePeer?, hideAuthor: Bool, messageText: String) { + let peer: EnginePeer? let message = messages.last var hideAuthor = false var messageText: String if let message = message { - if let messageMain = messageMainPeer(EngineMessage(message)) { - peer = messageMain._asPeer() + if let messageMain = messageMainPeer(message) { + peer = messageMain } else { peer = chatPeer.chatMainPeer } @@ -261,12 +260,12 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: } default: hideAuthor = true - if let text = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: EngineMessage(message), accountPeerId: accountPeerId, forChatList: true) { + if let text = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: true) { messageText = text } } case _ as TelegramMediaExpiredContent: - if let text = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: EngineMessage(message), accountPeerId: accountPeerId, forChatList: true) { + if let text = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: true) { messageText = text } case let poll as TelegramMediaPoll: @@ -282,21 +281,21 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: peer = chatPeer.chatMainPeer messageText = "" if chatPeer.peerId.namespace == Namespaces.Peer.SecretChat { - if let secretChat = chatPeer.peers[chatPeer.peerId] as? TelegramSecretChat { + if case let .secretChat(secretChat) = chatPeer.peers[chatPeer.peerId] { switch secretChat.embeddedState { case .active: switch secretChat.role { case .creator: - messageText = strings.DialogList_EncryptedChatStartedOutgoing(peer.flatMap(EnginePeer.init)?.compactDisplayTitle ?? "").string + messageText = strings.DialogList_EncryptedChatStartedOutgoing(peer?.compactDisplayTitle ?? "").string case .participant: - messageText = strings.DialogList_EncryptedChatStartedIncoming(peer.flatMap(EnginePeer.init)?.compactDisplayTitle ?? "").string + messageText = strings.DialogList_EncryptedChatStartedIncoming(peer?.compactDisplayTitle ?? "").string } case .terminated: messageText = strings.DialogList_EncryptionRejected case .handshake: switch secretChat.role { case .creator: - messageText = strings.DialogList_AwaitingEncryption(peer.flatMap(EnginePeer.init)?.compactDisplayTitle ?? "").string + messageText = strings.DialogList_AwaitingEncryption(peer?.compactDisplayTitle ?? "").string case .participant: messageText = strings.DialogList_EncryptionProcessing } diff --git a/submodules/ChatListUI/Sources/Node/ChatListNode.swift b/submodules/ChatListUI/Sources/Node/ChatListNode.swift index 473a96651b..f1b94746df 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNode.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNode.swift @@ -4,7 +4,6 @@ import Display import AsyncDisplayKit import SwiftSignalKit import TelegramCore -import Postbox import TelegramPresentationData import TelegramUIPreferences import AccountContext @@ -48,34 +47,34 @@ final class ChatListHighlightedLocation { public final class ChatListNodeInteraction { public enum PeerEntry { - case peerId(PeerId) - case peer(Peer) + case peerId(EnginePeer.Id) + case peer(EnginePeer) } let activateSearch: () -> Void - let peerSelected: (Peer, Peer?, ChatListNodeEntryPromoInfo?) -> Void - let disabledPeerSelected: (Peer) -> Void - let togglePeerSelected: (Peer) -> Void + let peerSelected: (EnginePeer, EnginePeer?, ChatListNodeEntryPromoInfo?) -> Void + let disabledPeerSelected: (EnginePeer) -> Void + let togglePeerSelected: (EnginePeer) -> Void let togglePeersSelection: ([PeerEntry], Bool) -> Void let additionalCategorySelected: (Int) -> Void - let messageSelected: (Peer, Message, ChatListNodeEntryPromoInfo?) -> Void - let groupSelected: (PeerGroupId) -> Void + let messageSelected: (EnginePeer, EngineMessage, ChatListNodeEntryPromoInfo?) -> Void + let groupSelected: (EngineChatList.Group) -> Void let addContact: (String) -> Void - let setPeerIdWithRevealedOptions: (PeerId?, PeerId?) -> Void - let setItemPinned: (PinnedItemId, Bool) -> Void - let setPeerMuted: (PeerId, Bool) -> Void - let deletePeer: (PeerId, Bool) -> Void - let updatePeerGrouping: (PeerId, Bool) -> Void - let togglePeerMarkedUnread: (PeerId, Bool) -> Void + let setPeerIdWithRevealedOptions: (EnginePeer.Id?, EnginePeer.Id?) -> Void + let setItemPinned: (EngineChatList.PinnedItem.Id, Bool) -> Void + let setPeerMuted: (EnginePeer.Id, Bool) -> Void + let deletePeer: (EnginePeer.Id, Bool) -> Void + let updatePeerGrouping: (EnginePeer.Id, Bool) -> Void + let togglePeerMarkedUnread: (EnginePeer.Id, Bool) -> Void let toggleArchivedFolderHiddenByDefault: () -> Void - let hidePsa: (PeerId) -> Void + let hidePsa: (EnginePeer.Id) -> Void let activateChatPreview: (ChatListItem, ASDisplayNode, ContextGesture?) -> Void let present: (ViewController) -> Void public var searchTextHighightState: String? var highlightedChatLocation: ChatListHighlightedLocation? - public init(activateSearch: @escaping () -> Void, peerSelected: @escaping (Peer, Peer?, ChatListNodeEntryPromoInfo?) -> Void, disabledPeerSelected: @escaping (Peer) -> Void, togglePeerSelected: @escaping (Peer) -> Void, togglePeersSelection: @escaping ([PeerEntry], Bool) -> Void, additionalCategorySelected: @escaping (Int) -> Void, messageSelected: @escaping (Peer, Message, ChatListNodeEntryPromoInfo?) -> Void, groupSelected: @escaping (PeerGroupId) -> Void, addContact: @escaping (String) -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, setItemPinned: @escaping (PinnedItemId, Bool) -> Void, setPeerMuted: @escaping (PeerId, Bool) -> Void, deletePeer: @escaping (PeerId, Bool) -> Void, updatePeerGrouping: @escaping (PeerId, Bool) -> Void, togglePeerMarkedUnread: @escaping (PeerId, Bool) -> Void, toggleArchivedFolderHiddenByDefault: @escaping () -> Void, hidePsa: @escaping (PeerId) -> Void, activateChatPreview: @escaping (ChatListItem, ASDisplayNode, ContextGesture?) -> Void, present: @escaping (ViewController) -> Void) { + public init(activateSearch: @escaping () -> Void, peerSelected: @escaping (EnginePeer, EnginePeer?, ChatListNodeEntryPromoInfo?) -> Void, disabledPeerSelected: @escaping (EnginePeer) -> Void, togglePeerSelected: @escaping (EnginePeer) -> Void, togglePeersSelection: @escaping ([PeerEntry], Bool) -> Void, additionalCategorySelected: @escaping (Int) -> Void, messageSelected: @escaping (EnginePeer, EngineMessage, ChatListNodeEntryPromoInfo?) -> Void, groupSelected: @escaping (EngineChatList.Group) -> Void, addContact: @escaping (String) -> Void, setPeerIdWithRevealedOptions: @escaping (EnginePeer.Id?, EnginePeer.Id?) -> Void, setItemPinned: @escaping (EngineChatList.PinnedItem.Id, Bool) -> Void, setPeerMuted: @escaping (EnginePeer.Id, Bool) -> Void, deletePeer: @escaping (EnginePeer.Id, Bool) -> Void, updatePeerGrouping: @escaping (EnginePeer.Id, Bool) -> Void, togglePeerMarkedUnread: @escaping (EnginePeer.Id, Bool) -> Void, toggleArchivedFolderHiddenByDefault: @escaping () -> Void, hidePsa: @escaping (EnginePeer.Id) -> Void, activateChatPreview: @escaping (ChatListItem, ASDisplayNode, ContextGesture?) -> Void, present: @escaping (ViewController) -> Void) { self.activateSearch = activateSearch self.peerSelected = peerSelected self.disabledPeerSelected = disabledPeerSelected @@ -99,19 +98,19 @@ public final class ChatListNodeInteraction { } public final class ChatListNodePeerInputActivities { - public let activities: [PeerId: [(Peer, PeerInputActivity)]] + public let activities: [EnginePeer.Id: [(EnginePeer, PeerInputActivity)]] - public init(activities: [PeerId: [(Peer, PeerInputActivity)]]) { + public init(activities: [EnginePeer.Id: [(EnginePeer, PeerInputActivity)]]) { self.activities = activities } } -private func areFoundPeerArraysEqual(_ lhs: [(Peer, Peer?)], _ rhs: [(Peer, Peer?)]) -> Bool { +private func areFoundPeerArraysEqual(_ lhs: [(EnginePeer, EnginePeer?)], _ rhs: [(EnginePeer, EnginePeer?)]) -> Bool { if lhs.count != rhs.count { return false } for i in 0 ..< lhs.count { - if !arePeersEqual(lhs[i].0, rhs[i].0) || !arePeersEqual(lhs[i].1, rhs[i].1) { + if lhs[i].0 != rhs[i].0 || lhs[i].1 != rhs[i].1 { return false } } @@ -121,18 +120,18 @@ private func areFoundPeerArraysEqual(_ lhs: [(Peer, Peer?)], _ rhs: [(Peer, Peer public struct ChatListNodeState: Equatable { public var presentationData: ChatListPresentationData public var editing: Bool - public var peerIdWithRevealedOptions: PeerId? - public var selectedPeerIds: Set + public var peerIdWithRevealedOptions: EnginePeer.Id? + public var selectedPeerIds: Set public var peerInputActivities: ChatListNodePeerInputActivities? - public var pendingRemovalPeerIds: Set - public var pendingClearHistoryPeerIds: Set + public var pendingRemovalPeerIds: Set + public var pendingClearHistoryPeerIds: Set public var archiveShouldBeTemporaryRevealed: Bool public var selectedAdditionalCategoryIds: Set - public var hiddenPsaPeerId: PeerId? - public var foundPeers: [(Peer, Peer?)] - public var selectedPeerMap: [PeerId: Peer] + public var hiddenPsaPeerId: EnginePeer.Id? + public var foundPeers: [(EnginePeer, EnginePeer?)] + public var selectedPeerMap: [EnginePeer.Id: EnginePeer] - public init(presentationData: ChatListPresentationData, editing: Bool, peerIdWithRevealedOptions: PeerId?, selectedPeerIds: Set, foundPeers: [(Peer, Peer?)], selectedPeerMap: [PeerId: Peer], selectedAdditionalCategoryIds: Set, peerInputActivities: ChatListNodePeerInputActivities?, pendingRemovalPeerIds: Set, pendingClearHistoryPeerIds: Set, archiveShouldBeTemporaryRevealed: Bool, hiddenPsaPeerId: PeerId?) { + public init(presentationData: ChatListPresentationData, editing: Bool, peerIdWithRevealedOptions: EnginePeer.Id?, selectedPeerIds: Set, foundPeers: [(EnginePeer, EnginePeer?)], selectedPeerMap: [EnginePeer.Id: EnginePeer], selectedAdditionalCategoryIds: Set, peerInputActivities: ChatListNodePeerInputActivities?, pendingRemovalPeerIds: Set, pendingClearHistoryPeerIds: Set, archiveShouldBeTemporaryRevealed: Bool, hiddenPsaPeerId: EnginePeer.Id?) { self.presentationData = presentationData self.editing = editing self.peerIdWithRevealedOptions = peerIdWithRevealedOptions @@ -163,7 +162,7 @@ public struct ChatListNodeState: Equatable { if areFoundPeerArraysEqual(lhs.foundPeers, rhs.foundPeers) { return false } - if arePeerDictionariesEqual(lhs.selectedPeerMap, rhs.selectedPeerMap) { + if lhs.selectedPeerMap != rhs.selectedPeerMap { return false } if lhs.selectedAdditionalCategoryIds != rhs.selectedAdditionalCategoryIds { @@ -188,7 +187,7 @@ public struct ChatListNodeState: Equatable { } } -private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: PeerGroupId, filterData: ChatListItemFilterData?, mode: ChatListNodeMode, entries: [ChatListNodeViewTransitionInsertEntry]) -> [ListViewInsertItem] { +private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: EngineChatList.Group, filterData: ChatListItemFilterData?, mode: ChatListNodeMode, entries: [ChatListNodeViewTransitionInsertEntry]) -> [ListViewInsertItem] { return entries.map { entry -> ListViewInsertItem in switch entry.entry { case .HeaderEntry: @@ -211,20 +210,47 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL nodeInteraction.additionalCategorySelected(id) } ), directionHint: entry.directionHint) - case let .PeerEntry(index, presentationData, messages, combinedReadState, isRemovedFromTotalUnreadCount, embeddedState, peer, presence, summaryInfo, editing, hasActiveRevealControls, selected, inputActivities, promoInfo, hasFailedMessages, isContact): + case let .PeerEntry(index, presentationData, messages, combinedReadState, isRemovedFromTotalUnreadCount, draftState, peer, presence, hasUnseenMentions, editing, hasActiveRevealControls, selected, inputActivities, promoInfo, hasFailedMessages, isContact): switch mode { case .chatList: - return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(presentationData: presentationData, context: context, peerGroupId: peerGroupId, filterData: filterData, index: index, content: .peer(messages: messages, peer: peer, combinedReadState: combinedReadState, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, presence: presence, summaryInfo: summaryInfo, embeddedState: embeddedState, inputActivities: inputActivities, promoInfo: promoInfo, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: hasFailedMessages), editing: editing, hasActiveRevealControls: hasActiveRevealControls, selected: selected, header: nil, enableContextActions: true, hiddenOffset: false, interaction: nodeInteraction), directionHint: entry.directionHint) + return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem( + presentationData: presentationData, + context: context, + peerGroupId: peerGroupId, + filterData: filterData, + index: index, + content: .peer( + messages: messages, + peer: peer, + combinedReadState: combinedReadState, + isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, + presence: presence, + hasUnseenMentions: hasUnseenMentions, + draftState: draftState, + inputActivities: inputActivities, + promoInfo: promoInfo, + ignoreUnreadBadge: false, + displayAsMessage: false, + hasFailedMessages: hasFailedMessages + ), + editing: editing, + hasActiveRevealControls: hasActiveRevealControls, + selected: selected, + header: nil, + enableContextActions: true, + hiddenOffset: false, + interaction: nodeInteraction + ), directionHint: entry.directionHint) case let .peers(filter, isSelecting, _, filters): let itemPeer = peer.chatMainPeer - var chatPeer: Peer? + var chatPeer: EnginePeer? if let peer = peer.peers[peer.peerId] { chatPeer = peer } var enabled = true if filter.contains(.onlyWriteable) { if let peer = peer.peers[peer.peerId] { - if !canSendMessagesToPeer(peer) { + if !canSendMessagesToPeer(peer._asPeer()) { enabled = false } } else { @@ -233,7 +259,10 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL } if filter.contains(.onlyPrivateChats) { if let peer = peer.peers[peer.peerId] { - if !(peer is TelegramUser || peer is TelegramSecretChat) { + switch peer { + case .user, .secretChat: + break + default: enabled = false } } else { @@ -242,8 +271,8 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL } if filter.contains(.onlyGroups) { if let peer = peer.peers[peer.peerId] { - if let _ = peer as? TelegramGroup { - } else if let peer = peer as? TelegramChannel, case .group = peer.info { + if case .legacyGroup = peer { + } else if case let .channel(peer) = peer, case .group = peer.info { } else { enabled = false } @@ -254,7 +283,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL if filter.contains(.onlyManageable) { if let peer = peer.peers[peer.peerId] { var canManage = false - if let peer = peer as? TelegramGroup { + if case let .legacyGroup(peer) = peer { switch peer.role { case .creator, .admin: canManage = true @@ -264,7 +293,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL } if canManage { - } else if let peer = peer as? TelegramChannel, case .group = peer.info, peer.hasPermission(.inviteMembers) { + } else if case let .channel(peer) = peer, case .group = peer.info, peer.hasPermission(.inviteMembers) { } else { enabled = false } @@ -274,7 +303,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL } if filter.contains(.excludeChannels) { if let peer = peer.peers[peer.peerId] { - if let peer = peer as? TelegramChannel, case .broadcast = peer.info { + if case let .channel(peer) = peer, case .broadcast = peer.info { enabled = false } } @@ -299,57 +328,115 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL var status: ContactsPeerItemStatus = .none if isSelecting, let itemPeer = itemPeer { - let tagSummaryCount = summaryInfo.tagSummaryCount ?? 0 - let actionsSummaryCount = summaryInfo.actionsSummaryCount ?? 0 - let totalMentionCount = tagSummaryCount - actionsSummaryCount - if let (string, multiline) = statusStringForPeerType(accountPeerId: context.account.peerId, strings: presentationData.strings, peer: itemPeer, isMuted: isRemovedFromTotalUnreadCount, isUnread: combinedReadState?.isUnread ?? false, isContact: isContact, hasUnseenMentions: totalMentionCount > 0, chatListFilters: filters) { + if let (string, multiline) = statusStringForPeerType(accountPeerId: context.account.peerId, strings: presentationData.strings, peer: itemPeer, isMuted: isRemovedFromTotalUnreadCount, isUnread: combinedReadState?.isUnread ?? false, isContact: isContact, hasUnseenMentions: hasUnseenMentions, chatListFilters: filters) { status = .custom(string: string, multiline: multiline) } else { status = .none } } - return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings), sortOrder: presentationData.nameSortOrder, displayOrder: presentationData.nameDisplayOrder, context: context, peerMode: .generalSearch, peer: .peer(peer: itemPeer.flatMap(EnginePeer.init), chatPeer: chatPeer.flatMap(EnginePeer.init)), status: status, enabled: enabled, selection: editing ? .selectable(selected: selected) : .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in - if let chatPeer = chatPeer { - if editing { - nodeInteraction.togglePeerSelected(chatPeer) - } else { - nodeInteraction.peerSelected(chatPeer, nil, nil) + return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem( + presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings), + sortOrder: presentationData.nameSortOrder, + displayOrder: presentationData.nameDisplayOrder, + context: context, + peerMode: .generalSearch, + peer: .peer(peer: itemPeer, chatPeer: chatPeer), + status: status, + enabled: enabled, + selection: editing ? .selectable(selected: selected) : .none, + editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), + index: nil, + header: header, + action: { _ in + if let chatPeer = chatPeer { + if editing { + nodeInteraction.togglePeerSelected(chatPeer) + } else { + nodeInteraction.peerSelected(chatPeer, nil, nil) + } + } + }, disabledAction: { _ in + if let chatPeer = chatPeer { + nodeInteraction.disabledPeerSelected(chatPeer) } } - }, disabledAction: { _ in - if let chatPeer = chatPeer { - nodeInteraction.disabledPeerSelected(chatPeer) - } - }), directionHint: entry.directionHint) + ), directionHint: entry.directionHint) } case let .HoleEntry(_, theme): return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListHoleItem(theme: theme), directionHint: entry.directionHint) - case let .GroupReferenceEntry(index, presentationData, groupId, peers, message, editing, unreadState, revealed, hiddenByDefault): - return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(presentationData: presentationData, context: context, peerGroupId: peerGroupId, filterData: filterData, index: index, content: .groupReference(groupId: groupId, peers: peers, message: message, unreadState: unreadState, hiddenByDefault: hiddenByDefault), editing: editing, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: true, hiddenOffset: hiddenByDefault && !revealed, interaction: nodeInteraction), directionHint: entry.directionHint) + case let .GroupReferenceEntry(index, presentationData, groupId, peers, message, editing, unreadCount, revealed, hiddenByDefault): + return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem( + presentationData: presentationData, + context: context, + peerGroupId: peerGroupId, + filterData: filterData, + index: index, + content: .groupReference( + groupId: groupId, + peers: peers, + message: message, + unreadCount: unreadCount, + hiddenByDefault: hiddenByDefault + ), + editing: editing, + hasActiveRevealControls: false, + selected: false, + header: nil, + enableContextActions: true, + hiddenOffset: hiddenByDefault && !revealed, + interaction: nodeInteraction + ), directionHint: entry.directionHint) case let .ArchiveIntro(presentationData): return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListArchiveInfoItem(theme: presentationData.theme, strings: presentationData.strings), directionHint: entry.directionHint) } } } -private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: PeerGroupId, filterData: ChatListItemFilterData?, mode: ChatListNodeMode, entries: [ChatListNodeViewTransitionUpdateEntry]) -> [ListViewUpdateItem] { +private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: EngineChatList.Group, filterData: ChatListItemFilterData?, mode: ChatListNodeMode, entries: [ChatListNodeViewTransitionUpdateEntry]) -> [ListViewUpdateItem] { return entries.map { entry -> ListViewUpdateItem in switch entry.entry { - case let .PeerEntry(index, presentationData, messages, combinedReadState, isRemovedFromTotalUnreadCount, embeddedState, peer, presence, summaryInfo, editing, hasActiveRevealControls, selected, inputActivities, promoInfo, hasFailedMessages, isContact): + case let .PeerEntry(index, presentationData, messages, combinedReadState, isRemovedFromTotalUnreadCount, draftState, peer, presence, hasUnseenMentions, editing, hasActiveRevealControls, selected, inputActivities, promoInfo, hasFailedMessages, isContact): switch mode { case .chatList: - return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(presentationData: presentationData, context: context, peerGroupId: peerGroupId, filterData: filterData, index: index, content: .peer(messages: messages, peer: peer, combinedReadState: combinedReadState, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, presence: presence, summaryInfo: summaryInfo, embeddedState: embeddedState, inputActivities: inputActivities, promoInfo: promoInfo, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: hasFailedMessages), editing: editing, hasActiveRevealControls: hasActiveRevealControls, selected: selected, header: nil, enableContextActions: true, hiddenOffset: false, interaction: nodeInteraction), directionHint: entry.directionHint) + return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem( + presentationData: presentationData, + context: context, + peerGroupId: peerGroupId, + filterData: filterData, + index: index, + content: .peer( + messages: messages, + peer: peer, + combinedReadState: combinedReadState, + isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, + presence: presence, + hasUnseenMentions: hasUnseenMentions, + draftState: draftState, + inputActivities: inputActivities, + promoInfo: promoInfo, + ignoreUnreadBadge: false, + displayAsMessage: false, + hasFailedMessages: hasFailedMessages + ), + editing: editing, + hasActiveRevealControls: hasActiveRevealControls, + selected: selected, + header: nil, + enableContextActions: true, + hiddenOffset: false, + interaction: nodeInteraction + ), directionHint: entry.directionHint) case let .peers(filter, isSelecting, _, filters): let itemPeer = peer.chatMainPeer - var chatPeer: Peer? + var chatPeer: EnginePeer? if let peer = peer.peers[peer.peerId] { chatPeer = peer } var enabled = true if filter.contains(.onlyWriteable) { if let peer = peer.peers[peer.peerId] { - if !canSendMessagesToPeer(peer) { + if !canSendMessagesToPeer(peer._asPeer()) { enabled = false } } else { @@ -357,7 +444,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL } } if filter.contains(.excludeChannels) { - if let peer = peer.chatMainPeer as? TelegramChannel, case .broadcast = peer.info { + if case let .channel(peer) = peer.chatMainPeer, case .broadcast = peer.info { enabled = false } } @@ -380,34 +467,65 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL var status: ContactsPeerItemStatus = .none if isSelecting, let itemPeer = itemPeer { - let tagSummaryCount = summaryInfo.tagSummaryCount ?? 0 - let actionsSummaryCount = summaryInfo.actionsSummaryCount ?? 0 - let totalMentionCount = tagSummaryCount - actionsSummaryCount - if let (string, multiline) = statusStringForPeerType(accountPeerId: context.account.peerId, strings: presentationData.strings, peer: itemPeer, isMuted: isRemovedFromTotalUnreadCount, isUnread: combinedReadState?.isUnread ?? false, isContact: isContact, hasUnseenMentions: totalMentionCount > 0, chatListFilters: filters) { + if let (string, multiline) = statusStringForPeerType(accountPeerId: context.account.peerId, strings: presentationData.strings, peer: itemPeer, isMuted: isRemovedFromTotalUnreadCount, isUnread: combinedReadState?.isUnread ?? false, isContact: isContact, hasUnseenMentions: hasUnseenMentions, chatListFilters: filters) { status = .custom(string: string, multiline: multiline) } else { status = .none } } - return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings), sortOrder: presentationData.nameSortOrder, displayOrder: presentationData.nameDisplayOrder, context: context, peerMode: .generalSearch, peer: .peer(peer: itemPeer.flatMap(EnginePeer.init), chatPeer: chatPeer.flatMap(EnginePeer.init)), status: status, enabled: enabled, selection: editing ? .selectable(selected: selected) : .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in - if let chatPeer = chatPeer { - if editing { - nodeInteraction.togglePeerSelected(chatPeer) - } else { - nodeInteraction.peerSelected(chatPeer, nil, nil) + return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem( + presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings), + sortOrder: presentationData.nameSortOrder, + displayOrder: presentationData.nameDisplayOrder, + context: context, + peerMode: .generalSearch, + peer: .peer(peer: itemPeer, chatPeer: chatPeer), + status: status, + enabled: enabled, + selection: editing ? .selectable(selected: selected) : .none, + editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), + index: nil, + header: header, + action: { _ in + if let chatPeer = chatPeer { + if editing { + nodeInteraction.togglePeerSelected(chatPeer) + } else { + nodeInteraction.peerSelected(chatPeer, nil, nil) + } + } + }, disabledAction: { _ in + if let chatPeer = chatPeer { + nodeInteraction.disabledPeerSelected(chatPeer) } } - }, disabledAction: { _ in - if let chatPeer = chatPeer { - nodeInteraction.disabledPeerSelected(chatPeer) - } - }), directionHint: entry.directionHint) + ), directionHint: entry.directionHint) } case let .HoleEntry(_, theme): return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListHoleItem(theme: theme), directionHint: entry.directionHint) - case let .GroupReferenceEntry(index, presentationData, groupId, peers, message, editing, unreadState, revealed, hiddenByDefault): - return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(presentationData: presentationData, context: context, peerGroupId: peerGroupId, filterData: filterData, index: index, content: .groupReference(groupId: groupId, peers: peers, message: message, unreadState: unreadState, hiddenByDefault: hiddenByDefault), editing: editing, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: true, hiddenOffset: hiddenByDefault && !revealed, interaction: nodeInteraction), directionHint: entry.directionHint) + case let .GroupReferenceEntry(index, presentationData, groupId, peers, message, editing, unreadCount, revealed, hiddenByDefault): + return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem( + presentationData: presentationData, + context: context, + peerGroupId: peerGroupId, + filterData: filterData, + index: index, + content: .groupReference( + groupId: groupId, + peers: peers, + message: message, + unreadCount: unreadCount, + hiddenByDefault: hiddenByDefault + ), + editing: editing, + hasActiveRevealControls: false, + selected: false, + header: nil, + enableContextActions: true, + hiddenOffset: hiddenByDefault && !revealed, + interaction: nodeInteraction + ), directionHint: entry.directionHint) case let .ArchiveIntro(presentationData): return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListArchiveInfoItem(theme: presentationData.theme, strings: presentationData.strings), directionHint: entry.directionHint) case .HeaderEntry: @@ -434,7 +552,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL } } -private func mappedChatListNodeViewListTransition(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: PeerGroupId, filterData: ChatListItemFilterData?, mode: ChatListNodeMode, transition: ChatListNodeViewTransition) -> ChatListNodeListViewTransition { +private func mappedChatListNodeViewListTransition(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: EngineChatList.Group, filterData: ChatListItemFilterData?, mode: ChatListNodeMode, transition: ChatListNodeViewTransition) -> ChatListNodeListViewTransition { return ChatListNodeListViewTransition(chatListView: transition.chatListView, deleteItems: transition.deleteItems, insertItems: mappedInsertEntries(context: context, nodeInteraction: nodeInteraction, peerGroupId: peerGroupId, filterData: filterData, mode: mode, entries: transition.insertEntries), updateItems: mappedUpdateEntries(context: context, nodeInteraction: nodeInteraction, peerGroupId: peerGroupId, filterData: filterData, mode: mode, entries: transition.updateEntries), options: transition.options, scrollToItem: transition.scrollToItem, stationaryItemRange: transition.stationaryItemRange, adjustScrollToFirstItem: transition.adjustScrollToFirstItem, animateCrossfade: transition.animateCrossfade) } @@ -449,7 +567,7 @@ private final class ChatListOpaqueTransactionState { public enum ChatListSelectionOption { case previous(unread: Bool) case next(unread: Bool) - case peerId(PeerId) + case peerId(EnginePeer.Id) case index(Int) } @@ -473,7 +591,7 @@ public enum ChatListNodeEmptyState: Equatable { public final class ChatListNode: ListView { private let fillPreloadItems: Bool private let context: AccountContext - private let groupId: PeerGroupId + private let groupId: EngineChatList.Group private let mode: ChatListNodeMode private let _ready = ValuePromise() @@ -488,18 +606,18 @@ public final class ChatListNode: ListView { return _contentsReady.get() } - public var peerSelected: ((Peer, Bool, Bool, ChatListNodeEntryPromoInfo?) -> Void)? - public var disabledPeerSelected: ((Peer) -> Void)? + public var peerSelected: ((EnginePeer, Bool, Bool, ChatListNodeEntryPromoInfo?) -> Void)? + public var disabledPeerSelected: ((EnginePeer) -> Void)? public var additionalCategorySelected: ((Int) -> Void)? - public var groupSelected: ((PeerGroupId) -> Void)? + public var groupSelected: ((EngineChatList.Group) -> Void)? public var addContact: ((String) -> Void)? public var activateSearch: (() -> Void)? - public var deletePeerChat: ((PeerId, Bool) -> Void)? - public var updatePeerGrouping: ((PeerId, Bool) -> Void)? + public var deletePeerChat: ((EnginePeer.Id, Bool) -> Void)? + public var updatePeerGrouping: ((EnginePeer.Id, Bool) -> Void)? public var presentAlert: ((String) -> Void)? public var present: ((ViewController) -> Void)? public var toggleArchivedFolderHiddenByDefault: (() -> Void)? - public var hidePsa: ((PeerId) -> Void)? + public var hidePsa: ((EnginePeer.Id) -> Void)? public var activateChatPreview: ((ChatListItem, ASDisplayNode, ContextGesture?) -> Void)? private var theme: PresentationTheme @@ -569,10 +687,10 @@ public final class ChatListNode: ListView { var isEmptyUpdated: ((ChatListNodeEmptyState, Bool, ContainedViewLayoutTransition) -> Void)? private var currentIsEmptyState: ChatListNodeEmptyState? - public var addedVisibleChatsWithPeerIds: (([PeerId]) -> Void)? + public var addedVisibleChatsWithPeerIds: (([EnginePeer.Id]) -> Void)? - private let currentRemovingPeerId = Atomic(value: nil) - public func setCurrentRemovingPeerId(_ peerId: PeerId?) { + private let currentRemovingPeerId = Atomic(value: nil) + public func setCurrentRemovingPeerId(_ peerId: EnginePeer.Id?) { let _ = self.currentRemovingPeerId.swap(peerId) } @@ -585,7 +703,7 @@ public final class ChatListNode: ListView { var isSelectionGestureEnabled = true - public init(context: AccountContext, groupId: PeerGroupId, chatListFilter: ChatListFilter? = nil, previewing: Bool, fillPreloadItems: Bool, mode: ChatListNodeMode, theme: PresentationTheme, fontSize: PresentationFontSize, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, disableAnimations: Bool) { + public init(context: AccountContext, groupId: EngineChatList.Group, chatListFilter: ChatListFilter? = nil, previewing: Bool, fillPreloadItems: Bool, mode: ChatListNodeMode, theme: PresentationTheme, fontSize: PresentationFontSize, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, disableAnimations: Bool) { self.context = context self.groupId = groupId self.chatListFilter = chatListFilter @@ -712,7 +830,7 @@ public final class ChatListNode: ListView { if let chatListFilter = chatListFilter { location = .filter(chatListFilter.id) } else { - location = .group(groupId) + location = .group(groupId._asGroup()) } let _ = (context.engine.peers.toggleItemPinned(location: location, itemId: itemId) |> deliverOnMainQueue).start(next: { result in @@ -785,7 +903,7 @@ public final class ChatListNode: ListView { let chatListViewUpdate = self.chatListLocation.get() |> distinctUntilChanged |> mapToSignal { location -> Signal<(ChatListNodeViewUpdate, ChatListFilter?), NoError> in - return chatListViewForLocation(groupId: groupId, location: location, account: context.account) + return chatListViewForLocation(groupId: groupId._asGroup(), location: location, account: context.account) |> map { update in return (update, location.filter) } @@ -796,10 +914,13 @@ public final class ChatListNode: ListView { let previousHideArchivedFolderByDefault = Atomic(value: nil) let currentRemovingPeerId = self.currentRemovingPeerId - let savedMessagesPeer: Signal + let savedMessagesPeer: Signal if case let .peers(filter, _, _, _) = mode, filter.contains(.onlyWriteable) { savedMessagesPeer = context.account.postbox.loadedPeerWithId(context.account.peerId) |> map(Optional.init) + |> map { peer in + return peer.flatMap(EnginePeer.init) + } } else { savedMessagesPeer = .single(nil) } @@ -812,7 +933,7 @@ public final class ChatListNode: ListView { |> distinctUntilChanged let displayArchiveIntro: Signal - if Namespaces.PeerGroup.archive == groupId { + if case .archive = groupId { displayArchiveIntro = context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.archiveIntroDismissedKey()) |> map { entry -> Bool in if let value = entry.value?.get(ApplicationSpecificVariantNotice.self) { @@ -835,7 +956,7 @@ public final class ChatListNode: ListView { displayArchiveIntro = .single(false) } - let currentPeerId: PeerId = context.account.peerId + let currentPeerId: EnginePeer.Id = context.account.peerId let chatListNodeViewTransition = combineLatest(queue: viewProcessingQueue, hideArchivedFolderByDefault, displayArchiveIntro, savedMessagesPeer, chatListViewUpdate, self.statePromise.get()) |> mapToQueue { (hideArchivedFolderByDefault, displayArchiveIntro, savedMessagesPeer, updateAndFilter, state) -> Signal in @@ -843,7 +964,7 @@ public final class ChatListNode: ListView { let previousHideArchivedFolderByDefaultValue = previousHideArchivedFolderByDefault.swap(hideArchivedFolderByDefault) - let (rawEntries, isLoading) = chatListNodeEntriesForView(update.view, state: state, savedMessagesPeer: savedMessagesPeer, foundPeers: state.foundPeers, hideArchivedFolderByDefault: hideArchivedFolderByDefault, displayArchiveIntro: displayArchiveIntro, mode: mode) + let (rawEntries, isLoading) = chatListNodeEntriesForView(EngineChatList(update.view), state: state, savedMessagesPeer: savedMessagesPeer, foundPeers: state.foundPeers, hideArchivedFolderByDefault: hideArchivedFolderByDefault, displayArchiveIntro: displayArchiveIntro, mode: mode) let entries = rawEntries.filter { entry in switch entry { case let .PeerEntry(_, _, _, _, _, _, peer, _, _, _, _, _, _, _, _, _): @@ -858,7 +979,7 @@ public final class ChatListNode: ListView { if filter.contains(.onlyGroups) { var isGroup: Bool = false - if let peer = peer.chatMainPeer as? TelegramChannel, case .group = peer.info { + if case let .channel(peer) = peer.chatMainPeer, case .group = peer.info { isGroup = true } else if peer.peerId.namespace == Namespaces.Peer.CloudGroup { isGroup = true @@ -869,7 +990,7 @@ public final class ChatListNode: ListView { } if filter.contains(.onlyChannels) { - if let peer = peer.chatMainPeer as? TelegramChannel, case .broadcast = peer.info { + if case let .channel(peer) = peer.chatMainPeer, case .broadcast = peer.info { return true } else { return false @@ -877,13 +998,13 @@ public final class ChatListNode: ListView { } if filter.contains(.excludeChannels) { - if let peer = peer.chatMainPeer as? TelegramChannel, case .broadcast = peer.info { + if case let .channel(peer) = peer.chatMainPeer, case .broadcast = peer.info { } } if filter.contains(.onlyWriteable) && filter.contains(.excludeDisabled) { if let peer = peer.peers[peer.peerId] { - if !canSendMessagesToPeer(peer) { + if !canSendMessagesToPeer(peer._asPeer()) { return false } } else { @@ -950,8 +1071,8 @@ public final class ChatListNode: ListView { if previousState.editing != state.editing { disableAnimations = false } else { - var previousPinnedChats: [PeerId] = [] - var updatedPinnedChats: [PeerId] = [] + var previousPinnedChats: [EnginePeer.Id] = [] + var updatedPinnedChats: [EnginePeer.Id] = [] var didIncludeRemovingPeerId = false var didIncludeHiddenByDefaultArchive = false @@ -1095,18 +1216,18 @@ public final class ChatListNode: ListView { self.setChatListLocation(initialLocation) let postbox = context.account.postbox - let previousPeerCache = Atomic<[PeerId: Peer]>(value: [:]) + let previousPeerCache = Atomic<[EnginePeer.Id: EnginePeer]>(value: [:]) let previousActivities = Atomic(value: nil) self.activityStatusesDisposable = (context.account.allPeerInputActivities() - |> mapToSignal { activitiesByPeerId -> Signal<[PeerId: [(Peer, PeerInputActivity)]], NoError> in + |> mapToSignal { activitiesByPeerId -> Signal<[EnginePeer.Id: [(EnginePeer, PeerInputActivity)]], NoError> in var foundAllPeers = true - var cachedResult: [PeerId: [(Peer, PeerInputActivity)]] = [:] + var cachedResult: [EnginePeer.Id: [(EnginePeer, PeerInputActivity)]] = [:] previousPeerCache.with { dict -> Void in for (chatPeerId, activities) in activitiesByPeerId { guard case .global = chatPeerId.category else { continue } - var cachedChatResult: [(Peer, PeerInputActivity)] = [] + var cachedChatResult: [(EnginePeer, PeerInputActivity)] = [] for (peerId, activity) in activities { if let peer = dict[peerId] { cachedChatResult.append((peer, activity)) @@ -1121,19 +1242,19 @@ public final class ChatListNode: ListView { if foundAllPeers { return .single(cachedResult) } else { - return postbox.transaction { transaction -> [PeerId: [(Peer, PeerInputActivity)]] in - var result: [PeerId: [(Peer, PeerInputActivity)]] = [:] - var peerCache: [PeerId: Peer] = [:] + return postbox.transaction { transaction -> [EnginePeer.Id: [(EnginePeer, PeerInputActivity)]] in + var result: [EnginePeer.Id: [(EnginePeer, PeerInputActivity)]] = [:] + var peerCache: [EnginePeer.Id: EnginePeer] = [:] for (chatPeerId, activities) in activitiesByPeerId { guard case .global = chatPeerId.category else { continue } - var chatResult: [(Peer, PeerInputActivity)] = [] + var chatResult: [(EnginePeer, PeerInputActivity)] = [] for (peerId, activity) in activities { if let peer = transaction.getPeer(peerId) { - chatResult.append((peer, activity)) - peerCache[peerId] = peer + chatResult.append((EnginePeer(peer), activity)) + peerCache[peerId] = EnginePeer(peer) } } @@ -1147,7 +1268,7 @@ public final class ChatListNode: ListView { |> map { activities -> ChatListNodePeerInputActivities? in return previousActivities.modify { current in var updated = false - let currentList: [PeerId: [(Peer, PeerInputActivity)]] = current?.activities ?? [:] + let currentList: [EnginePeer.Id: [(EnginePeer, PeerInputActivity)]] = current?.activities ?? [:] if currentList.count != activities.count { updated = true } else { @@ -1158,7 +1279,7 @@ public final class ChatListNode: ListView { break outer } else { for i in 0 ..< currentValue.count { - if !arePeersEqual(currentValue[i].0, value[i].0) { + if currentValue[i].0 != value[i].0 { updated = true break outer } @@ -1201,7 +1322,7 @@ public final class ChatListNode: ListView { let fromEntry = filteredEntries[filteredEntries.count - 1 - fromIndex] let toEntry = filteredEntries[filteredEntries.count - 1 - toIndex] - var referenceId: PinnedItemId? + var referenceId: EngineChatList.PinnedItem.Id? var beforeAll = false switch toEntry { case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, promoInfo, _, _): @@ -1219,7 +1340,7 @@ public final class ChatListNode: ListView { if let chatListFilter = chatListFilter { location = .filter(chatListFilter.id) } else { - location = .group(groupId) + location = .group(groupId._asGroup()) } let engine = strongSelf.context.engine @@ -1227,7 +1348,7 @@ public final class ChatListNode: ListView { |> mapToSignal { itemIds -> Signal in var itemIds = itemIds - var itemId: PinnedItemId? + var itemId: EngineChatList.PinnedItem.Id? switch fromEntry { case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): itemId = .peer(index.messageIndex.id.peerId) @@ -1595,7 +1716,7 @@ public final class ChatListNode: ListView { isEmptyState = .notEmpty(containsChats: containsChats) } - var insertedPeerIds: [PeerId] = [] + var insertedPeerIds: [EnginePeer.Id] = [] for item in transition.insertItems { if let item = item.item as? ChatListItem { switch item.content { @@ -1754,10 +1875,10 @@ public final class ChatListNode: ListView { self.chatListLocation.set(location) } - private func relativeUnreadChatListIndex(position: ChatListRelativePosition) -> Signal { + private func relativeUnreadChatListIndex(position: EngineChatList.RelativePosition) -> Signal { let groupId = self.groupId let postbox = self.context.account.postbox - return self.context.sharedContext.accountManager.transaction { transaction -> Signal in + return self.context.sharedContext.accountManager.transaction { transaction -> Signal in var filter = true if let inAppNotificationSettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.inAppNotificationSettings)?.get(InAppNotificationSettings.self) { switch inAppNotificationSettings.totalUnreadCountDisplayStyle { @@ -1765,14 +1886,14 @@ public final class ChatListNode: ListView { filter = true } } - return postbox.transaction { transaction -> ChatListIndex? in - return transaction.getRelativeUnreadChatListIndex(filtered: filter, position: position, groupId: groupId) + return postbox.transaction { transaction -> EngineChatList.Item.Index? in + return transaction.getRelativeUnreadChatListIndex(filtered: filter, position: position._asPosition(), groupId: groupId._asGroup()) } } |> switchToLatest } - public func scrollToEarliestUnread(earlierThan: ChatListIndex?) { + public func scrollToEarliestUnread(earlierThan: EngineChatList.Item.Index?) { let _ = (relativeUnreadChatListIndex(position: .earlier(than: earlierThan)) |> deliverOnMainQueue).start(next: { [weak self] index in guard let strongSelf = self else { return @@ -1804,9 +1925,9 @@ public final class ChatListNode: ListView { } let entryCount = chatListView.filteredEntries.count - var current: (ChatListIndex, Peer, Int)? = nil - var previous: (ChatListIndex, Peer)? = nil - var next: (ChatListIndex, Peer)? = nil + var current: (EngineChatList.Item.Index, EnginePeer, Int)? = nil + var previous: (EngineChatList.Item.Index, EnginePeer)? = nil + var next: (EngineChatList.Item.Index, EnginePeer)? = nil outer: for i in range.firstIndex ..< range.lastIndex { if i < 0 || i >= entryCount { @@ -1826,7 +1947,7 @@ public final class ChatListNode: ListView { switch option { case .previous(unread: true), .next(unread: true): - let position: ChatListRelativePosition + let position: EngineChatList.RelativePosition if let current = current { if case .previous = option { position = .earlier(than: current.0) @@ -1838,11 +1959,11 @@ public final class ChatListNode: ListView { } let postbox = self.context.account.postbox let _ = (relativeUnreadChatListIndex(position: position) - |> mapToSignal { index -> Signal<(ChatListIndex, Peer)?, NoError> in + |> mapToSignal { index -> Signal<(EngineChatList.Item.Index, EnginePeer)?, NoError> in if let index = index { - return postbox.transaction { transaction -> (ChatListIndex, Peer)? in - return transaction.getPeer(index.messageIndex.id.peerId).flatMap { peer -> (ChatListIndex, Peer)? in - (index, peer) + return postbox.transaction { transaction -> (EngineChatList.Item.Index, EnginePeer)? in + return transaction.getPeer(index.messageIndex.id.peerId).flatMap { peer -> (EngineChatList.Item.Index, EnginePeer)? in + (index, EnginePeer(peer)) } } } else { @@ -1858,7 +1979,7 @@ public final class ChatListNode: ListView { strongSelf.peerSelected?(peer, false, false, nil) }) case .previous(unread: false), .next(unread: false): - var target: (ChatListIndex, Peer)? = nil + var target: (EngineChatList.Item.Index, EnginePeer)? = nil if let current = current, entryCount > 1 { if current.2 > 0, case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _, _, _, _, _) = chatListView.filteredEntries[current.2 - 1] { next = (index, peer.peer!) @@ -1882,8 +2003,8 @@ public final class ChatListNode: ListView { self.peerSelected?(target.1, false, false, nil) } case let .peerId(peerId): - let _ = (self.context.account.postbox.transaction { transaction -> Peer? in - return transaction.getPeer(peerId) + let _ = (self.context.account.postbox.transaction { transaction -> EnginePeer? in + return transaction.getPeer(peerId).flatMap(EnginePeer.init) } |> deliverOnMainQueue).start(next: { [weak self] peer in guard let strongSelf = self, let peer = peer else { @@ -1901,14 +2022,14 @@ public final class ChatListNode: ListView { guard let self = self else { return } - let _ = (chatListViewForLocation(groupId: self.groupId, location: .initial(count: 10, filter: filter), account: self.context.account) + let _ = (chatListViewForLocation(groupId: self.groupId._asGroup(), location: .initial(count: 10, filter: filter), account: self.context.account) |> take(1) |> deliverOnMainQueue).start(next: { update in let entries = update.view.entries if entries.count > index, case let .MessageEntry(index, _, _, _, _, renderedPeer, _, _, _, _) = entries[10 - index - 1] { let location: ChatListNodeLocation = .scroll(index: index, sourceIndex: .absoluteLowerBound, scrollPosition: .center(.top), animated: true, filter: filter) self.setChatListLocation(location) - self.peerSelected?(renderedPeer.peer!, false, false, nil) + self.peerSelected?(EnginePeer(renderedPeer.peer!), false, false, nil) } }) }) @@ -1936,7 +2057,7 @@ public final class ChatListNode: ListView { } } - private func currentlyVisibleLatestChatListIndex() -> ChatListIndex? { + private func currentlyVisibleLatestChatListIndex() -> EngineChatList.Item.Index? { guard let chatListView = (self.opaqueTransactionState as? ChatListOpaqueTransactionState)?.chatListView else { return nil } @@ -1958,8 +2079,8 @@ public final class ChatListNode: ListView { return nil } - private func peerAtPoint(_ point: CGPoint) -> Peer? { - var resultPeer: Peer? + private func peerAtPoint(_ point: CGPoint) -> EnginePeer? { + var resultPeer: EnginePeer? self.forEachVisibleItemNode { itemNode in if resultPeer == nil, let itemNode = itemNode as? ListViewItemNode, itemNode.frame.contains(point) { if let itemNode = itemNode as? ChatListItemNode, let item = itemNode.item { @@ -1975,7 +2096,7 @@ public final class ChatListNode: ListView { return resultPeer } - private var selectionPanState: (selecting: Bool, initialPeerId: PeerId, toggledPeerIds: [[PeerId]])? + private var selectionPanState: (selecting: Bool, initialPeerId: EnginePeer.Id, toggledPeerIds: [[EnginePeer.Id]])? private var selectionScrollActivationTimer: SwiftSignalKit.Timer? private var selectionScrollDisplayLink: ConstantDisplayLinkAnimator? private var selectionScrollDelta: CGFloat? @@ -2024,7 +2145,7 @@ public final class ChatListNode: ListView { self.selectionPanState = (state.selecting, state.initialPeerId, []) } } else if state.toggledPeerIds.last?.first != peer.id { - var updatedToggledPeerIds: [[PeerId]] = [] + var updatedToggledPeerIds: [[EnginePeer.Id]] = [] var previouslyToggled = false for i in (0 ..< state.toggledPeerIds.count) { if let peerId = state.toggledPeerIds[i].first { @@ -2100,7 +2221,7 @@ public final class ChatListNode: ListView { } } -private func statusStringForPeerType(accountPeerId: PeerId, strings: PresentationStrings, peer: Peer, isMuted: Bool, isUnread: Bool, isContact: Bool, hasUnseenMentions: Bool, chatListFilters: [ChatListFilter]?) -> (String, Bool)? { +private func statusStringForPeerType(accountPeerId: EnginePeer.Id, strings: PresentationStrings, peer: EnginePeer, isMuted: Bool, isUnread: Bool, isContact: Bool, hasUnseenMentions: Bool, chatListFilters: [ChatListFilter]?) -> (String, Bool)? { if accountPeerId == peer.id { return nil } @@ -2109,7 +2230,7 @@ private func statusStringForPeerType(accountPeerId: PeerId, strings: Presentatio var result = "" for filter in chatListFilters { let predicate = chatListFilterPredicate(filter: filter.data) - if predicate.includes(peer: peer, groupId: .root, isRemovedFromTotalUnreadCount: isMuted, isUnread: isUnread, isContact: isContact, messageTagSummaryResult: hasUnseenMentions) { + if predicate.includes(peer: peer._asPeer(), groupId: .root, isRemovedFromTotalUnreadCount: isMuted, isUnread: isUnread, isContact: isContact, messageTagSummaryResult: hasUnseenMentions) { if !result.isEmpty { result.append(", ") } @@ -2126,7 +2247,7 @@ private func statusStringForPeerType(accountPeerId: PeerId, strings: Presentatio if peer.id.isReplies { return nil - } else if let user = peer as? TelegramUser { + } else if case let .user(user) = peer { if user.botInfo != nil || user.flags.contains(.isSupport) { return (strings.ChatList_PeerTypeBot, false) } else if isContact { @@ -2134,15 +2255,15 @@ private func statusStringForPeerType(accountPeerId: PeerId, strings: Presentatio } else { return (strings.ChatList_PeerTypeNonContact, false) } - } else if peer is TelegramSecretChat { + } else if case .secretChat = peer { if isContact { return (strings.ChatList_PeerTypeContact, false) } else { return (strings.ChatList_PeerTypeNonContact, false) } - } else if peer is TelegramGroup { + } else if case .legacyGroup = peer { return (strings.ChatList_PeerTypeGroup, false) - } else if let channel = peer as? TelegramChannel { + } else if case let .channel(channel) = peer { if case .group = channel.info { return (strings.ChatList_PeerTypeGroup, false) } else { diff --git a/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift b/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift index 4882cb291f..e4149d77f4 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift @@ -1,6 +1,5 @@ import Foundation import UIKit -import Postbox import TelegramCore import TelegramPresentationData import MergeLists @@ -10,13 +9,13 @@ enum ChatListNodeEntryId: Hashable { case Header case Hole(Int64) case PeerId(Int64) - case GroupId(PeerGroupId) + case GroupId(EngineChatList.Group) case ArchiveIntro case additionalCategory(Int) } enum ChatListNodeEntrySortIndex: Comparable { - case index(ChatListIndex) + case index(EngineChatList.Item.Index) case additionalCategory(Int) static func <(lhs: ChatListNodeEntrySortIndex, rhs: ChatListNodeEntrySortIndex) -> Bool { @@ -46,24 +45,24 @@ public enum ChatListNodeEntryPromoInfo: Equatable { enum ChatListNodeEntry: Comparable, Identifiable { case HeaderEntry - case PeerEntry(index: ChatListIndex, presentationData: ChatListPresentationData, messages: [Message], readState: CombinedPeerReadState?, isRemovedFromTotalUnreadCount: Bool, embeddedInterfaceState: StoredPeerChatInterfaceState?, peer: RenderedPeer, presence: PeerPresence?, summaryInfo: ChatListMessageTagSummaryInfo, editing: Bool, hasActiveRevealControls: Bool, selected: Bool, inputActivities: [(Peer, PeerInputActivity)]?, promoInfo: ChatListNodeEntryPromoInfo?, hasFailedMessages: Bool, isContact: Bool) - case HoleEntry(ChatListHole, theme: PresentationTheme) - case GroupReferenceEntry(index: ChatListIndex, presentationData: ChatListPresentationData, groupId: PeerGroupId, peers: [ChatListGroupReferencePeer], message: Message?, editing: Bool, unreadState: PeerGroupUnreadCountersCombinedSummary, revealed: Bool, hiddenByDefault: Bool) + case PeerEntry(index: EngineChatList.Item.Index, presentationData: ChatListPresentationData, messages: [EngineMessage], readState: EnginePeerReadCounters?, isRemovedFromTotalUnreadCount: Bool, draftState: ChatListItemContent.DraftState?, peer: EngineRenderedPeer, presence: EnginePeer.Presence?, hasUnseenMentions: Bool, editing: Bool, hasActiveRevealControls: Bool, selected: Bool, inputActivities: [(EnginePeer, PeerInputActivity)]?, promoInfo: ChatListNodeEntryPromoInfo?, hasFailedMessages: Bool, isContact: Bool) + case HoleEntry(EngineMessage.Index, theme: PresentationTheme) + case GroupReferenceEntry(index: EngineChatList.Item.Index, presentationData: ChatListPresentationData, groupId: EngineChatList.Group, peers: [EngineChatList.GroupItem.Item], message: EngineMessage?, editing: Bool, unreadCount: Int, revealed: Bool, hiddenByDefault: Bool) case ArchiveIntro(presentationData: ChatListPresentationData) case AdditionalCategory(index: Int, id: Int, title: String, image: UIImage?, appearance: ChatListNodeAdditionalCategory.Appearance, selected: Bool, presentationData: ChatListPresentationData) var sortIndex: ChatListNodeEntrySortIndex { switch self { case .HeaderEntry: - return .index(ChatListIndex.absoluteUpperBound) + return .index(EngineChatList.Item.Index.absoluteUpperBound) case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): return .index(index) - case let .HoleEntry(hole, _): - return .index(ChatListIndex(pinningIndex: nil, messageIndex: hole.index)) + case let .HoleEntry(holeIndex, _): + return .index(EngineChatList.Item.Index(pinningIndex: nil, messageIndex: holeIndex)) case let .GroupReferenceEntry(index, _, _, _, _, _, _, _, _): return .index(index) case .ArchiveIntro: - return .index(ChatListIndex.absoluteUpperBound.successor) + return .index(EngineChatList.Item.Index.absoluteUpperBound.successor) case let .AdditionalCategory(index, _, _, _, _, _, _): return .additionalCategory(index) } @@ -75,8 +74,8 @@ enum ChatListNodeEntry: Comparable, Identifiable { return .Header case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): return .PeerId(index.messageIndex.id.peerId.toInt64()) - case let .HoleEntry(hole, _): - return .Hole(Int64(hole.index.id.id)) + case let .HoleEntry(holeIndex, _): + return .Hole(Int64(holeIndex.id.id)) case let .GroupReferenceEntry(_, _, groupId, _, _, _, _, _, _): return .GroupId(groupId) case .ArchiveIntro: @@ -137,7 +136,7 @@ enum ChatListNodeEntry: Comparable, Identifiable { return false } if let lhsPeerPresence = lhsPresence, let rhsPeerPresence = rhsPresence { - if !lhsPeerPresence.isEqual(to: rhsPeerPresence) { + if lhsPeerPresence != rhsPeerPresence { return false } } else if (lhsPresence != nil) != (rhsPresence != nil) { @@ -170,7 +169,7 @@ enum ChatListNodeEntry: Comparable, Identifiable { return false } for i in 0 ..< lhsInputActivities.count { - if !arePeersEqual(lhsInputActivities[i].0, rhsInputActivities[i].0) { + if lhsInputActivities[i].0 != rhsInputActivities[i].0 { return false } if lhsInputActivities[i].1 != rhsInputActivities[i].1 { @@ -273,115 +272,149 @@ enum ChatListNodeEntry: Comparable, Identifiable { } } -private func offsetPinnedIndex(_ index: ChatListIndex, offset: UInt16) -> ChatListIndex { +private func offsetPinnedIndex(_ index: EngineChatList.Item.Index, offset: UInt16) -> EngineChatList.Item.Index { if let pinningIndex = index.pinningIndex { - return ChatListIndex(pinningIndex: pinningIndex + offset, messageIndex: index.messageIndex) + return EngineChatList.Item.Index(pinningIndex: pinningIndex + offset, messageIndex: index.messageIndex) } else { return index } } -func chatListNodeEntriesForView(_ view: ChatListView, state: ChatListNodeState, savedMessagesPeer: Peer?, foundPeers: [(Peer, Peer?)], hideArchivedFolderByDefault: Bool, displayArchiveIntro: Bool, mode: ChatListNodeMode) -> (entries: [ChatListNodeEntry], loading: Bool) { +func chatListNodeEntriesForView(_ view: EngineChatList, state: ChatListNodeState, savedMessagesPeer: EnginePeer?, foundPeers: [(EnginePeer, EnginePeer?)], hideArchivedFolderByDefault: Bool, displayArchiveIntro: Bool, mode: ChatListNodeMode) -> (entries: [ChatListNodeEntry], loading: Bool) { var result: [ChatListNodeEntry] = [] var pinnedIndexOffset: UInt16 = 0 - if view.laterIndex == nil, case .chatList = mode { + if !view.hasLater, case .chatList = mode { var groupEntryCount = 0 - for _ in view.groupEntries { + for _ in view.groupItems { groupEntryCount += 1 } pinnedIndexOffset += UInt16(groupEntryCount) } - let filteredAdditionalItemEntries = view.additionalItemEntries.filter { item -> Bool in - return item.info.peerId != state.hiddenPsaPeerId + let filteredAdditionalItemEntries = view.additionalItems.filter { item -> Bool in + return item.item.renderedPeer.peerId != state.hiddenPsaPeerId } - var foundPeerIds = Set() + var foundPeerIds = Set() for peer in foundPeers { foundPeerIds.insert(peer.0.id) } - if view.laterIndex == nil && savedMessagesPeer == nil { + if !view.hasLater && savedMessagesPeer == nil { pinnedIndexOffset += UInt16(filteredAdditionalItemEntries.count) } - var filterAfterHole = false - loop: for entry in view.entries { - switch entry { - case let .MessageEntry(index, messages, combinedReadState, isRemovedFromTotalUnreadCount, embeddedState, peer, peerPresence, summaryInfo, hasFailed, isContact): - if let savedMessagesPeer = savedMessagesPeer, savedMessagesPeer.id == index.messageIndex.id.peerId || foundPeerIds.contains(index.messageIndex.id.peerId) { - continue loop - } - if state.pendingRemovalPeerIds.contains(index.messageIndex.id.peerId) { - continue loop - } - var updatedMessages = messages - var updatedCombinedReadState = combinedReadState - if state.pendingClearHistoryPeerIds.contains(index.messageIndex.id.peerId) { - updatedMessages = [] - updatedCombinedReadState = nil - } - result.append(.PeerEntry(index: offsetPinnedIndex(index, offset: pinnedIndexOffset), presentationData: state.presentationData, messages: updatedMessages, readState: updatedCombinedReadState, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, embeddedInterfaceState: embeddedState, peer: peer, presence: peerPresence, summaryInfo: summaryInfo, editing: state.editing, hasActiveRevealControls: index.messageIndex.id.peerId == state.peerIdWithRevealedOptions, selected: state.selectedPeerIds.contains(index.messageIndex.id.peerId), inputActivities: state.peerInputActivities?.activities[index.messageIndex.id.peerId], promoInfo: nil, hasFailedMessages: hasFailed, isContact: isContact)) - case let .HoleEntry(hole): - if hole.index.timestamp == Int32.max - 1 { - //return ([.HeaderEntry], true) - } - filterAfterHole = true - result.append(.HoleEntry(hole, theme: state.presentationData.theme)) + loop: for entry in view.items { + //case let .MessageEntry(index, messages, combinedReadState, isRemovedFromTotalUnreadCount, embeddedState, peer, peerPresence, summaryInfo, hasFailed, isContact): + if let savedMessagesPeer = savedMessagesPeer, savedMessagesPeer.id == entry.index.messageIndex.id.peerId || foundPeerIds.contains(entry.index.messageIndex.id.peerId) { + continue loop } + if state.pendingRemovalPeerIds.contains(entry.index.messageIndex.id.peerId) { + continue loop + } + var updatedMessages = entry.messages + var updatedCombinedReadState = entry.readCounters + if state.pendingClearHistoryPeerIds.contains(entry.index.messageIndex.id.peerId) { + updatedMessages = [] + updatedCombinedReadState = nil + } + + var draftState: ChatListItemContent.DraftState? + if let draftText = entry.draftText { + draftState = ChatListItemContent.DraftState(text: draftText) + } + + result.append(.PeerEntry(index: offsetPinnedIndex(entry.index, offset: pinnedIndexOffset), presentationData: state.presentationData, messages: updatedMessages, readState: updatedCombinedReadState, isRemovedFromTotalUnreadCount: entry.isMuted, draftState: draftState, peer: entry.renderedPeer, presence: entry.presence, hasUnseenMentions: entry.hasUnseenMentions, editing: state.editing, hasActiveRevealControls: entry.index.messageIndex.id.peerId == state.peerIdWithRevealedOptions, selected: state.selectedPeerIds.contains(entry.index.messageIndex.id.peerId), inputActivities: state.peerInputActivities?.activities[entry.index.messageIndex.id.peerId], promoInfo: nil, hasFailedMessages: entry.hasFailed, isContact: entry.isContact)) } - if view.laterIndex == nil { + if !view.hasLater { var pinningIndex: UInt16 = UInt16(pinnedIndexOffset == 0 ? 0 : (pinnedIndexOffset - 1)) if let savedMessagesPeer = savedMessagesPeer { if !foundPeers.isEmpty { var foundPinningIndex: UInt16 = UInt16(foundPeers.count) for peer in foundPeers.reversed() { - var peers: [PeerId: Peer] = [peer.0.id: peer.0] + var peers: [EnginePeer.Id: EnginePeer] = [peer.0.id: peer.0] if let chatPeer = peer.1 { peers[chatPeer.id] = chatPeer } - let messageIndex = MessageIndex(id: MessageId(peerId: peer.0.id, namespace: 0, id: 0), timestamp: 1) - result.append(.PeerEntry(index: ChatListIndex(pinningIndex: foundPinningIndex, messageIndex: messageIndex), presentationData: state.presentationData, messages: [], readState: nil, isRemovedFromTotalUnreadCount: false, embeddedInterfaceState: nil, peer: RenderedPeer(peerId: peer.0.id, peers: SimpleDictionary(peers)), presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(), editing: state.editing, hasActiveRevealControls: false, selected: state.selectedPeerIds.contains(peer.0.id), inputActivities: nil, promoInfo: nil, hasFailedMessages: false, isContact: false)) + let messageIndex = EngineMessage.Index(id: EngineMessage.Id(peerId: peer.0.id, namespace: 0, id: 0), timestamp: 1) + result.append(.PeerEntry( + index: EngineChatList.Item.Index(pinningIndex: foundPinningIndex, messageIndex: messageIndex), + presentationData: state.presentationData, + messages: [], + readState: nil, + isRemovedFromTotalUnreadCount: false, + draftState: nil, + peer: EngineRenderedPeer(peerId: peer.0.id, peers: peers), + presence: nil, + hasUnseenMentions: false, + editing: state.editing, + hasActiveRevealControls: false, + selected: state.selectedPeerIds.contains(peer.0.id), + inputActivities: nil, + promoInfo: nil, + hasFailedMessages: false, + isContact: false + )) if foundPinningIndex != 0 { foundPinningIndex -= 1 } } } - result.append(.PeerEntry(index: ChatListIndex.absoluteUpperBound.predecessor, presentationData: state.presentationData, messages: [], readState: nil, isRemovedFromTotalUnreadCount: false, embeddedInterfaceState: nil, peer: RenderedPeer(peerId: savedMessagesPeer.id, peers: SimpleDictionary([savedMessagesPeer.id: savedMessagesPeer])), presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(), editing: state.editing, hasActiveRevealControls: false, selected: state.selectedPeerIds.contains(savedMessagesPeer.id), inputActivities: nil, promoInfo: nil, hasFailedMessages: false, isContact: false)) + result.append(.PeerEntry(index: EngineChatList.Item.Index.absoluteUpperBound.predecessor, presentationData: state.presentationData, messages: [], readState: nil, isRemovedFromTotalUnreadCount: false, draftState: nil, peer: EngineRenderedPeer(peerId: savedMessagesPeer.id, peers: [savedMessagesPeer.id: savedMessagesPeer]), presence: nil, hasUnseenMentions: false, editing: state.editing, hasActiveRevealControls: false, selected: state.selectedPeerIds.contains(savedMessagesPeer.id), inputActivities: nil, promoInfo: nil, hasFailedMessages: false, isContact: false)) } else { if !filteredAdditionalItemEntries.isEmpty { for item in filteredAdditionalItemEntries.reversed() { - guard let info = item.info as? PromoChatListItem else { - continue - } let promoInfo: ChatListNodeEntryPromoInfo - switch info.kind { + switch item.promoInfo.content { case .proxy: promoInfo = .proxy case let .psa(type, message): promoInfo = .psa(type: type, message: message) } - switch item.entry { - case let .MessageEntry(index, messages, combinedReadState, isRemovedFromTotalUnreadCount, embeddedState, peer, peerPresence, summaryInfo, hasFailed, isContact): - result.append(.PeerEntry(index: ChatListIndex(pinningIndex: pinningIndex, messageIndex: index.messageIndex), presentationData: state.presentationData, messages: messages, readState: combinedReadState, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, embeddedInterfaceState: embeddedState, peer: peer, presence: peerPresence, summaryInfo: summaryInfo, editing: state.editing, hasActiveRevealControls: index.messageIndex.id.peerId == state.peerIdWithRevealedOptions, selected: state.selectedPeerIds.contains(index.messageIndex.id.peerId), inputActivities: state.peerInputActivities?.activities[index.messageIndex.id.peerId], promoInfo: promoInfo, hasFailedMessages: hasFailed, isContact: isContact)) - if pinningIndex != 0 { - pinningIndex -= 1 - } - default: - break + let draftState = item.item.draftText.flatMap(ChatListItemContent.DraftState.init(text:)) + result.append(.PeerEntry( + index: EngineChatList.Item.Index(pinningIndex: pinningIndex, messageIndex: item.item.index.messageIndex), + presentationData: state.presentationData, + messages: item.item.messages, + readState: item.item.readCounters, + isRemovedFromTotalUnreadCount: item.item.isMuted, + draftState: draftState, + peer: item.item.renderedPeer, + presence: item.item.presence, + hasUnseenMentions: item.item.hasUnseenMentions, + editing: state.editing, + hasActiveRevealControls: item.item.index.messageIndex.id.peerId == state.peerIdWithRevealedOptions, + selected: state.selectedPeerIds.contains(item.item.index.messageIndex.id.peerId), + inputActivities: state.peerInputActivities?.activities[item.item.index.messageIndex.id.peerId], + promoInfo: promoInfo, + hasFailedMessages: item.item.hasFailed, + isContact: item.item.isContact + )) + if pinningIndex != 0 { + pinningIndex -= 1 } } } } - if view.laterIndex == nil, case .chatList = mode { - for groupReference in view.groupEntries { - let messageIndex = MessageIndex(id: MessageId(peerId: PeerId(0), namespace: 0, id: 0), timestamp: 1) - result.append(.GroupReferenceEntry(index: ChatListIndex(pinningIndex: pinningIndex, messageIndex: messageIndex), presentationData: state.presentationData, groupId: groupReference.groupId, peers: groupReference.renderedPeers, message: groupReference.message, editing: state.editing, unreadState: groupReference.unreadState, revealed: state.archiveShouldBeTemporaryRevealed, hiddenByDefault: hideArchivedFolderByDefault)) + if !view.hasLater, case .chatList = mode { + for groupReference in view.groupItems { + let messageIndex = EngineMessage.Index(id: EngineMessage.Id(peerId: EnginePeer.Id(0), namespace: 0, id: 0), timestamp: 1) + result.append(.GroupReferenceEntry( + index: EngineChatList.Item.Index(pinningIndex: pinningIndex, messageIndex: messageIndex), + presentationData: state.presentationData, + groupId: groupReference.id, + peers: groupReference.items, + message: groupReference.topMessage, + editing: state.editing, + unreadCount: groupReference.unreadCount, + revealed: state.archiveShouldBeTemporaryRevealed, + hiddenByDefault: hideArchivedFolderByDefault + )) if pinningIndex != 0 { pinningIndex -= 1 } @@ -394,7 +427,7 @@ func chatListNodeEntriesForView(_ view: ChatListView, state: ChatListNodeState, result.append(.HeaderEntry) } - if view.laterIndex == nil, case let .peers(_, _, additionalCategories, + if !view.hasLater, case let .peers(_, _, additionalCategories, _) = mode { var index = 0 for category in additionalCategories.reversed(){ @@ -403,35 +436,11 @@ func chatListNodeEntriesForView(_ view: ChatListView, state: ChatListNodeState, } } } - - var isLoading: Bool = false - - if filterAfterHole { - var seenHole = false - for i in (0 ..< result.count).reversed() { - if seenHole { - result.remove(at: i) - } else { - switch result[i] { - case .HeaderEntry: - break - case .ArchiveIntro, .AdditionalCategory, .GroupReferenceEntry: - break - case .PeerEntry: - break - case .HoleEntry: - isLoading = true - seenHole = true - result.remove(at: i) - } - } - } - } if result.count >= 1, case .HoleEntry = result[result.count - 1] { return ([.HeaderEntry], true) } else if result.count == 1, case .HoleEntry = result[0] { return ([.HeaderEntry], true) } - return (result, isLoading) + return (result, view.isLoading) } diff --git a/submodules/ChatListUI/Sources/Node/ChatListTypingNode.swift b/submodules/ChatListUI/Sources/Node/ChatListTypingNode.swift index bed127d2e5..058431d540 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListTypingNode.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListTypingNode.swift @@ -1,7 +1,6 @@ import Foundation import UIKit import AsyncDisplayKit -import Postbox import TelegramCore import Display import SwiftSignalKit @@ -20,7 +19,7 @@ final class ChatListInputActivitiesNode: ASDisplayNode { self.addSubnode(self.activityNode) } - func asyncLayout() -> (CGSize, ChatListPresentationData, UIColor, PeerId, [(Peer, PeerInputActivity)]) -> (CGSize, () -> Void) { + func asyncLayout() -> (CGSize, ChatListPresentationData, UIColor, EnginePeer.Id, [(EnginePeer, PeerInputActivity)]) -> (CGSize, () -> Void) { return { [weak self] boundingSize, presentationData, color, peerId, activities in let strings = presentationData.strings @@ -87,7 +86,7 @@ final class ChatListInputActivitiesNode: ASDisplayNode { } else { let text: String if let _ = commonKey { - let peerTitle = EnginePeer(activities[0].0).compactDisplayTitle + let peerTitle = activities[0].0.compactDisplayTitle switch activities[0].1 { case .uploadingVideo: text = strings.DialogList_SingleUploadingVideoSuffix(peerTitle).string @@ -111,7 +110,7 @@ final class ChatListInputActivitiesNode: ASDisplayNode { text = "" } } else { - text = EnginePeer(activities[0].0).compactDisplayTitle + text = activities[0].0.compactDisplayTitle } let string = NSAttributedString(string: text, font: textFont, textColor: color) @@ -137,9 +136,9 @@ final class ChatListInputActivitiesNode: ASDisplayNode { } else { let string: NSAttributedString if activities.count > 1 { - let peerTitle = EnginePeer(activities[0].0).compactDisplayTitle + let peerTitle = activities[0].0.compactDisplayTitle if activities.count == 2 { - let secondPeerTitle = EnginePeer(activities[1].0).compactDisplayTitle + let secondPeerTitle = activities[1].0.compactDisplayTitle string = NSAttributedString(string: strings.DialogList_MultipleTypingPair(peerTitle, secondPeerTitle).string, font: textFont, textColor: color) } else { string = NSAttributedString(string: strings.DialogList_MultipleTyping(peerTitle, strings.DialogList_MultipleTypingSuffix(activities.count - 1).string).string, font: textFont, textColor: color) diff --git a/submodules/ContactListUI/Sources/ContactListNode.swift b/submodules/ContactListUI/Sources/ContactListNode.swift index 840d7b4412..9531a1ad2a 100644 --- a/submodules/ContactListUI/Sources/ContactListNode.swift +++ b/submodules/ContactListUI/Sources/ContactListNode.swift @@ -1097,7 +1097,7 @@ public final class ContactListNode: ASDisplayNode { if globalSearch { foundRemoteContacts = foundRemoteContacts |> then( - context.engine.peers.searchPeers(query: query) + context.engine.contacts.searchRemotePeers(query: query) |> map { ($0.0, $0.1) } |> delay(0.2, queue: Queue.concurrentDefaultQueue()) ) diff --git a/submodules/ContactListUI/Sources/ContactsSearchContainerNode.swift b/submodules/ContactListUI/Sources/ContactsSearchContainerNode.swift index 9acad949d1..39361248d2 100644 --- a/submodules/ContactListUI/Sources/ContactsSearchContainerNode.swift +++ b/submodules/ContactListUI/Sources/ContactsSearchContainerNode.swift @@ -299,7 +299,7 @@ public final class ContactsSearchContainerNode: SearchDisplayControllerContentNo if categories.contains(.global) { foundRemoteContacts = .single(previousFoundRemoteContacts.with({ $0 })) |> then( - context.engine.peers.searchPeers(query: query) + context.engine.contacts.searchRemotePeers(query: query) |> map { ($0.0, $0.1) } |> delay(0.2, queue: Queue.concurrentDefaultQueue()) ) diff --git a/submodules/CountrySelectionUI/BUILD b/submodules/CountrySelectionUI/BUILD index e681f57857..1104b6f78c 100644 --- a/submodules/CountrySelectionUI/BUILD +++ b/submodules/CountrySelectionUI/BUILD @@ -13,7 +13,6 @@ swift_library( "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/Display:Display", - "//submodules/Postbox:Postbox", "//submodules/TelegramCore:TelegramCore", "//submodules/TelegramPresentationData:TelegramPresentationData", "//submodules/TelegramStringFormatting:TelegramStringFormatting", diff --git a/submodules/CountrySelectionUI/Sources/AuthorizationSequenceCountrySelectionController.swift b/submodules/CountrySelectionUI/Sources/AuthorizationSequenceCountrySelectionController.swift index 938e641801..383977cb28 100644 --- a/submodules/CountrySelectionUI/Sources/AuthorizationSequenceCountrySelectionController.swift +++ b/submodules/CountrySelectionUI/Sources/AuthorizationSequenceCountrySelectionController.swift @@ -3,7 +3,6 @@ import UIKit import Display import AsyncDisplayKit import SwiftSignalKit -import Postbox import TelegramPresentationData import TelegramStringFormatting import SearchBarNode diff --git a/submodules/CountrySelectionUI/Sources/AuthorizationSequenceCountrySelectionControllerNode.swift b/submodules/CountrySelectionUI/Sources/AuthorizationSequenceCountrySelectionControllerNode.swift index 5317051f0e..b8df9acdae 100644 --- a/submodules/CountrySelectionUI/Sources/AuthorizationSequenceCountrySelectionControllerNode.swift +++ b/submodules/CountrySelectionUI/Sources/AuthorizationSequenceCountrySelectionControllerNode.swift @@ -2,7 +2,6 @@ import Foundation import UIKit import AsyncDisplayKit import Display -import Postbox import TelegramCore import TelegramPresentationData import TelegramStringFormatting @@ -79,21 +78,26 @@ func localizedCountryNamesAndCodes(strings: PresentationStrings) -> [((String, S return result } -private func stringTokens(_ string: String) -> [ValueBoxKey] { +private func stringTokens(_ string: String) -> [Data] { let nsString = string.replacingOccurrences(of: ".", with: "").folding(options: .diacriticInsensitive, locale: .current).lowercased() as NSString let flag = UInt(kCFStringTokenizerUnitWord) let tokenizer = CFStringTokenizerCreate(kCFAllocatorDefault, nsString, CFRangeMake(0, nsString.length), flag, CFLocaleCopyCurrent()) var tokenType = CFStringTokenizerAdvanceToNextToken(tokenizer) - var tokens: [ValueBoxKey] = [] + var tokens: [Data] = [] - var addedTokens = Set() + var addedTokens = Set() while tokenType != [] { let currentTokenRange = CFStringTokenizerGetCurrentTokenRange(tokenizer) if currentTokenRange.location >= 0 && currentTokenRange.length != 0 { - let token = ValueBoxKey(length: currentTokenRange.length * 2) - nsString.getCharacters(token.memory.assumingMemoryBound(to: unichar.self), range: NSMakeRange(currentTokenRange.location, currentTokenRange.length)) + var token = Data(count: currentTokenRange.length * 2) + token.withUnsafeMutableBytes { bytes -> Void in + guard let baseAddress = bytes.baseAddress else { + return + } + nsString.getCharacters(baseAddress.assumingMemoryBound(to: unichar.self), range: NSMakeRange(currentTokenRange.location, currentTokenRange.length)) + } if !addedTokens.contains(token) { tokens.append(token) addedTokens.insert(token) @@ -105,13 +109,33 @@ private func stringTokens(_ string: String) -> [ValueBoxKey] { return tokens } -private func matchStringTokens(_ tokens: [ValueBoxKey], with other: [ValueBoxKey]) -> Bool { +public func isPrefix(data: Data, to otherData: Data) -> Bool { + if data.isEmpty { + return true + } else if data.count <= otherData.count { + return data.withUnsafeBytes { bytes -> Bool in + guard let bytesBaseAddress = bytes.baseAddress else { + return false + } + return otherData.withUnsafeBytes { otherBytes -> Bool in + guard let otherBytesBaseAddress = otherBytes.baseAddress else { + return false + } + return memcmp(bytesBaseAddress, otherBytesBaseAddress, bytes.count) == 0 + } + } + } else { + return false + } +} + +private func matchStringTokens(_ tokens: [Data], with other: [Data]) -> Bool { if other.isEmpty { return false } else if other.count == 1 { let otherToken = other[0] for token in tokens { - if otherToken.isPrefix(to: token) { + if isPrefix(data: otherToken, to: token) { return true } } @@ -119,7 +143,7 @@ private func matchStringTokens(_ tokens: [ValueBoxKey], with other: [ValueBoxKey for otherToken in other { var found = false for token in tokens { - if otherToken.isPrefix(to: token) { + if isPrefix(data: otherToken, to: token) { found = true break } diff --git a/submodules/HashtagSearchUI/BUILD b/submodules/HashtagSearchUI/BUILD index 5a466af616..ad68a8953b 100644 --- a/submodules/HashtagSearchUI/BUILD +++ b/submodules/HashtagSearchUI/BUILD @@ -13,7 +13,6 @@ swift_library( "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/Display:Display", - "//submodules/Postbox:Postbox", "//submodules/TelegramCore:TelegramCore", "//submodules/TelegramPresentationData:TelegramPresentationData", "//submodules/AccountContext:AccountContext", diff --git a/submodules/HashtagSearchUI/Sources/HashtagSearchController.swift b/submodules/HashtagSearchUI/Sources/HashtagSearchController.swift index 1e80d08b49..820973d3f0 100644 --- a/submodules/HashtagSearchUI/Sources/HashtagSearchController.swift +++ b/submodules/HashtagSearchUI/Sources/HashtagSearchController.swift @@ -2,7 +2,6 @@ import Foundation import UIKit import Display import TelegramCore -import Postbox import SwiftSignalKit import TelegramPresentationData import TelegramBaseController @@ -14,7 +13,7 @@ public final class HashtagSearchController: TelegramBaseController { private let queue = Queue() private let context: AccountContext - private let peer: Peer? + private let peer: EnginePeer? private let query: String private var transitionDisposable: Disposable? private let openMessageFromSearchDisposable = MetaDisposable() @@ -25,7 +24,7 @@ public final class HashtagSearchController: TelegramBaseController { return self.displayNode as! HashtagSearchControllerNode } - public init(context: AccountContext, peer: Peer?, query: String) { + public init(context: AccountContext, peer: EnginePeer?, query: String) { self.context = context self.peer = peer self.query = query @@ -45,7 +44,7 @@ public final class HashtagSearchController: TelegramBaseController { let search = context.engine.messages.searchMessages(location: location, query: query, state: nil) let foundMessages: Signal<[ChatListSearchEntry], NoError> = search |> map { result, _ in - return result.messages.map({ .message($0, RenderedPeer(message: $0), result.readStates[$0.id.peerId], chatListPresentationData, result.totalCount, nil, false) }) + return result.messages.map({ .message(EngineMessage($0), EngineRenderedPeer(message: EngineMessage($0)), result.readStates[$0.id.peerId].flatMap(EnginePeerReadCounters.init), chatListPresentationData, result.totalCount, nil, false) }) } let interaction = ChatListNodeInteraction(activateSearch: { }, peerSelected: { _, _, _ in @@ -55,7 +54,7 @@ public final class HashtagSearchController: TelegramBaseController { }, additionalCategorySelected: { _ in }, messageSelected: { [weak self] peer, message, _ in if let strongSelf = self { - strongSelf.openMessageFromSearchDisposable.set((storedMessageFromSearchPeer(account: strongSelf.context.account, peer: peer) |> deliverOnMainQueue).start(next: { actualPeerId in + strongSelf.openMessageFromSearchDisposable.set((storedMessageFromSearchPeer(account: strongSelf.context.account, peer: peer._asPeer()) |> deliverOnMainQueue).start(next: { actualPeerId in if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController { strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(actualPeerId), subject: message.id.peerId == actualPeerId ? .message(id: message.id, highlight: true, timecode: nil) : nil, keepStack: .always)) } diff --git a/submodules/HashtagSearchUI/Sources/HashtagSearchControllerNode.swift b/submodules/HashtagSearchUI/Sources/HashtagSearchControllerNode.swift index b0633b30fa..3fc8cca797 100644 --- a/submodules/HashtagSearchUI/Sources/HashtagSearchControllerNode.swift +++ b/submodules/HashtagSearchUI/Sources/HashtagSearchControllerNode.swift @@ -1,7 +1,6 @@ import Display import UIKit import AsyncDisplayKit -import Postbox import TelegramCore import TelegramPresentationData import AccountContext @@ -25,7 +24,7 @@ final class HashtagSearchControllerNode: ASDisplayNode { private var enqueuedTransitions: [(ChatListSearchContainerTransition, Bool)] = [] private var hasValidLayout = false - init(context: AccountContext, peer: Peer?, query: String, theme: PresentationTheme, strings: PresentationStrings, navigationBar: NavigationBar?, navigationController: NavigationController?) { + init(context: AccountContext, peer: EnginePeer?, query: String, theme: PresentationTheme, strings: PresentationStrings, navigationBar: NavigationBar?, navigationController: NavigationController?) { self.navigationBar = navigationBar self.context = context @@ -48,7 +47,7 @@ final class HashtagSearchControllerNode: ASDisplayNode { } else if let id = peer?.id, id.isReplies { items.append(presentationData.strings.DialogList_Replies) } else { - items.append(peer.flatMap(EnginePeer.init)?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) ?? "") + items.append(peer?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) ?? "") } items.append(strings.HashtagSearch_AllChats) self.segmentedControlNode = SegmentedControlNode(theme: SegmentedControlTheme(theme: theme), items: items.map { SegmentedControlItem(title: $0) }, selectedIndex: 0) diff --git a/submodules/PeerInfoUI/Sources/ChannelMembersSearchContainerNode.swift b/submodules/PeerInfoUI/Sources/ChannelMembersSearchContainerNode.swift index 42738eb394..9a2beaae58 100644 --- a/submodules/PeerInfoUI/Sources/ChannelMembersSearchContainerNode.swift +++ b/submodules/PeerInfoUI/Sources/ChannelMembersSearchContainerNode.swift @@ -681,7 +681,7 @@ public final class ChannelMembersSearchContainerNode: SearchDisplayControllerCon foundRemotePeers = .single(([], [])) } else { foundContacts = context.account.postbox.searchContacts(query: query.lowercased()) - foundRemotePeers = .single(([], [])) |> then(context.engine.peers.searchPeers(query: query) + foundRemotePeers = .single(([], [])) |> then(context.engine.contacts.searchRemotePeers(query: query) |> delay(0.2, queue: Queue.concurrentDefaultQueue())) } case .searchMembers, .searchBanned, .searchKicked, .searchAdmins: @@ -995,7 +995,7 @@ public final class ChannelMembersSearchContainerNode: SearchDisplayControllerCon } if mode == .banAndPromoteActions || mode == .inviteActions { - foundRemotePeers = .single(([], [])) |> then(context.engine.peers.searchPeers(query: query) + foundRemotePeers = .single(([], [])) |> then(context.engine.contacts.searchRemotePeers(query: query) |> delay(0.2, queue: Queue.concurrentDefaultQueue())) } else { foundRemotePeers = .single(([], [])) diff --git a/submodules/Postbox/Sources/MetadataTable.swift b/submodules/Postbox/Sources/MetadataTable.swift index 5aafcdba4d..56030c94ef 100644 --- a/submodules/Postbox/Sources/MetadataTable.swift +++ b/submodules/Postbox/Sources/MetadataTable.swift @@ -5,7 +5,6 @@ private enum MetadataKey: Int32 { case State = 2 case TransactionStateVersion = 3 case MasterClientId = 4 - case AccessChallenge = 5 case RemoteContactCount = 6 } @@ -107,14 +106,6 @@ final class MetadataTable: Table { self.valueBox.set(self.table, key: self.key(.MasterClientId), value: buffer) } - func accessChallengeData() -> PostboxAccessChallengeData { - if let value = self.valueBox.get(self.table, key: self.key(.AccessChallenge)) { - return PostboxAccessChallengeData(decoder: PostboxDecoder(buffer: value)) - } else { - return .none - } - } - func setRemoteContactCount(_ count: Int32) { self.cachedRemoteContactCount = count var mutableCount: Int32 = count diff --git a/submodules/Postbox/Sources/NoticeTable.swift b/submodules/Postbox/Sources/NoticeTable.swift index 5c8f7b39d0..3844ea596d 100644 --- a/submodules/Postbox/Sources/NoticeTable.swift +++ b/submodules/Postbox/Sources/NoticeTable.swift @@ -29,15 +29,19 @@ private struct CachedEntry { let entry: CodableEntry? } -final class NoticeTable: Table { +public final class NoticeTable: Table { private var cachedEntries: [NoticeEntryKey: CachedEntry] = [:] private var updatedEntryKeys = Set() - static func tableSpec(_ id: Int32) -> ValueBoxTable { + public static func tableSpec(_ id: Int32) -> ValueBoxTable { return ValueBoxTable(id: id, keyType: .binary, compactValuesOnCreation: true) } + + public override init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool) { + super.init(valueBox: valueBox, table: table, useCaches: useCaches) + } - func getAll() -> [ValueBoxKey: CodableEntry] { + public func getAll() -> [ValueBoxKey: CodableEntry] { var result: [ValueBoxKey: CodableEntry] = [:] self.valueBox.scan(self.table, values: { key, value in let object = CodableEntry(data: value.makeData()) @@ -47,7 +51,7 @@ final class NoticeTable: Table { return result } - func get(key: NoticeEntryKey) -> CodableEntry? { + public func get(key: NoticeEntryKey) -> CodableEntry? { if let cached = self.cachedEntries[key] { return cached.entry } else { @@ -62,12 +66,12 @@ final class NoticeTable: Table { } } - func set(key: NoticeEntryKey, value: CodableEntry?) { + public func set(key: NoticeEntryKey, value: CodableEntry?) { self.cachedEntries[key] = CachedEntry(entry: value) updatedEntryKeys.insert(key) } - func clear() { + public func clear() { var keys: [ValueBoxKey] = [] self.valueBox.scan(self.table, keys: { key in keys.append(key) @@ -80,11 +84,11 @@ final class NoticeTable: Table { self.cachedEntries.removeAll() } - override func clearMemoryCache() { + override public func clearMemoryCache() { assert(self.updatedEntryKeys.isEmpty) } - override func beforeCommit() { + override public func beforeCommit() { if !self.updatedEntryKeys.isEmpty { for key in self.updatedEntryKeys { if let value = self.cachedEntries[key]?.entry { diff --git a/submodules/Postbox/Sources/Postbox.swift b/submodules/Postbox/Sources/Postbox.swift index 95baf083a6..1f0f2756bd 100644 --- a/submodules/Postbox/Sources/Postbox.swift +++ b/submodules/Postbox/Sources/Postbox.swift @@ -886,15 +886,6 @@ public final class Transaction { return count } - public func legacyGetAccessChallengeData() -> PostboxAccessChallengeData { - assert(!self.disposed) - if let postbox = self.postbox { - return postbox.metadataTable.accessChallengeData() - } else { - return .none - } - } - public func enumerateMedia(lowerBound: MessageIndex?, upperBound: MessageIndex?, limit: Int) -> ([PeerId: Set], [MediaId: Media], MessageIndex?) { assert(!self.disposed) if let postbox = self.postbox { diff --git a/submodules/Postbox/Sources/PostboxLogging.swift b/submodules/Postbox/Sources/PostboxLogging.swift index fc9b696728..6daff29cfa 100644 --- a/submodules/Postbox/Sources/PostboxLogging.swift +++ b/submodules/Postbox/Sources/PostboxLogging.swift @@ -6,6 +6,6 @@ public func setPostboxLogger(_ f: @escaping (String) -> Void) { postboxLogger = f } -func postboxLog(_ what: @autoclosure () -> String) { +public func postboxLog(_ what: @autoclosure () -> String) { postboxLogger(what()) } diff --git a/submodules/Postbox/Sources/Utils/Decoder/AdaptedPostboxDecoder.swift b/submodules/Postbox/Sources/Utils/Decoder/AdaptedPostboxDecoder.swift index 41f0f6f4cc..56dbc9dec8 100644 --- a/submodules/Postbox/Sources/Utils/Decoder/AdaptedPostboxDecoder.swift +++ b/submodules/Postbox/Sources/Utils/Decoder/AdaptedPostboxDecoder.swift @@ -1,6 +1,6 @@ import Foundation -final public class AdaptedPostboxDecoder { +public final class AdaptedPostboxDecoder { enum ContentType { case object case int32Array diff --git a/submodules/SettingsUI/Sources/BubbleSettings/BubbleSettingsController.swift b/submodules/SettingsUI/Sources/BubbleSettings/BubbleSettingsController.swift index 2c1ebf9cd2..f413ba3c12 100644 --- a/submodules/SettingsUI/Sources/BubbleSettings/BubbleSettingsController.swift +++ b/submodules/SettingsUI/Sources/BubbleSettings/BubbleSettingsController.swift @@ -176,7 +176,7 @@ private final class BubbleSettingsControllerNode: ASDisplayNode, UIScrollViewDel items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message2], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode)) let waveformBase64 = "DAAOAAkACQAGAAwADwAMABAADQAPABsAGAALAA0AGAAfABoAHgATABgAGQAYABQADAAVABEAHwANAA0ACQAWABkACQAOAAwACQAfAAAAGQAVAAAAEwATAAAACAAfAAAAHAAAABwAHwAAABcAGQAAABQADgAAABQAHwAAAB8AHwAAAAwADwAAAB8AEwAAABoAFwAAAB8AFAAAAAAAHwAAAAAAHgAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAAAA=" - let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: MemoryBuffer(data: Data(base64Encoded: waveformBase64)!))] + let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: Data(base64Encoded: waveformBase64)!)] let voiceMedia = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: voiceAttributes) let message3 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [voiceMedia], peers: peers, associatedMessages: messages, associatedMessageIds: []) diff --git a/submodules/SettingsUI/Sources/Text Size/TextSizeSelectionController.swift b/submodules/SettingsUI/Sources/Text Size/TextSizeSelectionController.swift index a72209d63b..07738399e0 100644 --- a/submodules/SettingsUI/Sources/Text Size/TextSizeSelectionController.swift +++ b/submodules/SettingsUI/Sources/Text Size/TextSizeSelectionController.swift @@ -215,38 +215,136 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView }, activateChatPreview: { _, _, gesture in gesture?.cancel() }, present: { _ in }) + let chatListPresentationData = ChatListPresentationData(theme: self.presentationData.theme, fontSize: self.presentationData.listsFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: true) - - let peers = SimpleDictionary() - let messages = SimpleDictionary() - let selfPeer = TelegramUser(id: self.context.account.peerId, accessHash: nil, firstName: nil, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) - let peer1 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(1)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) - let peer2 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(2)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_2_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) - let peer3 = TelegramChannel(id: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(3)), accessHash: nil, title: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Name, username: nil, photo: [], creationDate: 0, version: 0, participationStatus: .member, info: .group(.init(flags: [])), flags: [], restrictionInfo: nil, adminRights: nil, bannedRights: nil, defaultBannedRights: nil) - let peer3Author = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(4)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_AuthorName, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) - let peer4 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(4)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) - let peer5 = TelegramChannel(id: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(5)), accessHash: nil, title: self.presentationData.strings.Appearance_ThemePreview_ChatList_5_Name, username: nil, photo: [], creationDate: 0, version: 0, participationStatus: .member, info: .broadcast(.init(flags: [])), flags: [], restrictionInfo: nil, adminRights: nil, bannedRights: nil, defaultBannedRights: nil) - let peer6 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.SecretChat, id: PeerId.Id._internalFromInt64Value(5)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_6_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) - + + func makeChatListItem( + peer: EnginePeer, + author: EnginePeer, + timestamp: Int32, + text: String, + isPinned: Bool = false, + presenceTimestamp: Int32? = nil, + hasInputActivity: Bool = false, + unreadCount: Int32 = 0 + ) -> ChatListItem { + return ChatListItem( + presentationData: chatListPresentationData, + context: self.context, + peerGroupId: .root, + filterData: nil, + index: ChatListIndex(pinningIndex: isPinned ? 0 : nil, messageIndex: MessageIndex(id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 0), timestamp: timestamp)), + content: .peer( + messages: [ + EngineMessage( + stableId: 0, + stableVersion: 0, + id: EngineMessage.Id(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 0), + globallyUniqueId: nil, + groupingKey: nil, + groupInfo: nil, + threadId: nil, + timestamp: timestamp, + flags: author.id == peer.id ? [.Incoming] : [], + tags: [], + globalTags: [], + localTags: [], + forwardInfo: nil, + author: author, + text: text, + attributes: [], + media: [], + peers: [:], + associatedMessages: [:], + associatedMessageIds: [] + ) + ], + peer: EngineRenderedPeer(peer: peer), + combinedReadState: EnginePeerReadCounters(incomingReadId: 1000, outgoingReadId: 1000, count: unreadCount, markedUnread: false), + isRemovedFromTotalUnreadCount: false, + presence: presenceTimestamp.flatMap { presenceTimestamp in + EnginePeer.Presence(status: .present(until: presenceTimestamp + 1000), lastActivity: presenceTimestamp) + }, + hasUnseenMentions: false, + draftState: nil, + inputActivities: hasInputActivity ? [(author, .typingText)] : [], + promoInfo: nil, + ignoreUnreadBadge: false, + displayAsMessage: false, + hasFailedMessages: false + ), + editing: false, + hasActiveRevealControls: false, + selected: false, + header: nil, + enableContextActions: false, + hiddenOffset: false, + interaction: interaction + ) + } + + let selfPeer: EnginePeer = .user(TelegramUser(id: self.context.account.peerId, accessHash: nil, firstName: nil, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])) + let peer1: EnginePeer = .user(TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(1)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])) + let peer2: EnginePeer = .user(TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(2)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_2_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])) + let peer3: EnginePeer = .channel(TelegramChannel(id: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(3)), accessHash: nil, title: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Name, username: nil, photo: [], creationDate: 0, version: 0, participationStatus: .member, info: .group(.init(flags: [])), flags: [], restrictionInfo: nil, adminRights: nil, bannedRights: nil, defaultBannedRights: nil)) + let peer3Author: EnginePeer = .user(TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(4)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_AuthorName, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])) + let peer4: EnginePeer = .user(TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(4)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])) + let peer5: EnginePeer = .channel(TelegramChannel(id: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(5)), accessHash: nil, title: self.presentationData.strings.Appearance_ThemePreview_ChatList_5_Name, username: nil, photo: [], creationDate: 0, version: 0, participationStatus: .member, info: .broadcast(.init(flags: [])), flags: [], restrictionInfo: nil, adminRights: nil, bannedRights: nil, defaultBannedRights: nil)) + let peer6: EnginePeer = .user(TelegramUser(id: PeerId(namespace: Namespaces.Peer.SecretChat, id: PeerId.Id._internalFromInt64Value(5)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_6_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])) + let timestamp = self.referenceTimestamp - + let timestamp1 = timestamp + 120 - items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(messages: [Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: timestamp1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: selfPeer, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])], peer: RenderedPeer(peer: peer1), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false))]), isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) - + items.append(makeChatListItem( + peer: peer1, + author: selfPeer, + timestamp: timestamp1, + text: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Text, + isPinned: true + )) + let presenceTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + 60 * 60) let timestamp2 = timestamp + 3660 - items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer2.id, namespace: 0, id: 0), timestamp: timestamp2)), content: .peer(messages: [Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer2.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: timestamp2, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer2, text: "", attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])], peer: RenderedPeer(peer: peer2), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: TelegramUserPresence(status: .present(until: presenceTimestamp), lastActivity: presenceTimestamp), summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: [(peer2, .typingText)], promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) - + items.append(makeChatListItem( + peer: peer2, + author: peer2, + timestamp: timestamp2, + text: "", + presenceTimestamp: presenceTimestamp, + hasInputActivity: true + )) + let timestamp3 = timestamp + 3200 - items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer3.id, namespace: 0, id: 0), timestamp: timestamp3)), content: .peer(messages: [Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer3.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: timestamp3, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer3Author, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])], peer: RenderedPeer(peer: peer3), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) - + items.append(makeChatListItem( + peer: peer3, + author: peer3Author, + timestamp: timestamp3, + text: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Text + )) + let timestamp4 = timestamp + 3000 - items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer4.id, namespace: 0, id: 0), timestamp: timestamp4)), content: .peer(messages: [Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: timestamp4, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer4, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])], peer: RenderedPeer(peer: peer4), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) - + items.append(makeChatListItem( + peer: peer4, + author: peer4, + timestamp: timestamp4, + text: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Text + )) + let timestamp5 = timestamp + 1000 - items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer5.id, namespace: 0, id: 0), timestamp: timestamp5)), content: .peer(messages: [Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: timestamp5, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer5, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_5_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])], peer: RenderedPeer(peer: peer5), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) - - items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer6.id, namespace: 0, id: 0), timestamp: timestamp - 360)), content: .peer(messages: [Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer6.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: timestamp - 360, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer6, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_6_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])], peer: RenderedPeer(peer: peer6), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 1, markedUnread: false))]), isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) + items.append(makeChatListItem( + peer: peer5, + author: peer5, + timestamp: timestamp5, + text: self.presentationData.strings.Appearance_ThemePreview_ChatList_5_Text + )) + + items.append(makeChatListItem( + peer: peer6, + author: peer6, + timestamp: timestamp - 360, + text: self.presentationData.strings.Appearance_ThemePreview_ChatList_6_Text, + unreadCount: 1 + )) let width: CGFloat if case .regular = layout.metrics.widthClass { @@ -321,7 +419,7 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message2], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode)) let waveformBase64 = "DAAOAAkACQAGAAwADwAMABAADQAPABsAGAALAA0AGAAfABoAHgATABgAGQAYABQADAAVABEAHwANAA0ACQAWABkACQAOAAwACQAfAAAAGQAVAAAAEwATAAAACAAfAAAAHAAAABwAHwAAABcAGQAAABQADgAAABQAHwAAAB8AHwAAAAwADwAAAB8AEwAAABoAFwAAAB8AFAAAAAAAHwAAAAAAHgAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAAAA=" - let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: MemoryBuffer(data: Data(base64Encoded: waveformBase64)!))] + let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: Data(base64Encoded: waveformBase64)!)] let voiceMedia = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: voiceAttributes) let message3 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [voiceMedia], peers: peers, associatedMessages: messages, associatedMessageIds: []) diff --git a/submodules/SettingsUI/Sources/Themes/ThemeAccentColorControllerNode.swift b/submodules/SettingsUI/Sources/Themes/ThemeAccentColorControllerNode.swift index 59f0d4fc46..85ef7f6e27 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeAccentColorControllerNode.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeAccentColorControllerNode.swift @@ -836,31 +836,116 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate gesture?.cancel() }, present: { _ in }) - let chatListPresentationData = ChatListPresentationData(theme: self.theme, fontSize: self.presentationData.listsFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: true) - - let peers = SimpleDictionary() - let messages = SimpleDictionary() - let selfPeer = TelegramUser(id: self.context.account.peerId, accessHash: nil, firstName: nil, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) - let peer1 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(1)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) - let peer2 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(2)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_2_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) - let peer3 = TelegramChannel(id: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(3)), accessHash: nil, title: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Name, username: nil, photo: [], creationDate: 0, version: 0, participationStatus: .member, info: .group(.init(flags: [])), flags: [], restrictionInfo: nil, adminRights: nil, bannedRights: nil, defaultBannedRights: nil) - let peer3Author = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(4)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_AuthorName, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) - let peer4 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.SecretChat, id: PeerId.Id._internalFromInt64Value(4)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) - + let chatListPresentationData = ChatListPresentationData(theme: self.presentationData.theme, fontSize: self.presentationData.listsFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: true) + + func makeChatListItem( + peer: EnginePeer, + author: EnginePeer, + timestamp: Int32, + text: String, + isPinned: Bool = false, + presenceTimestamp: Int32? = nil, + hasInputActivity: Bool = false, + unreadCount: Int32 = 0 + ) -> ChatListItem { + return ChatListItem( + presentationData: chatListPresentationData, + context: self.context, + peerGroupId: .root, + filterData: nil, + index: ChatListIndex(pinningIndex: isPinned ? 0 : nil, messageIndex: MessageIndex(id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 0), timestamp: timestamp)), + content: .peer( + messages: [ + EngineMessage( + stableId: 0, + stableVersion: 0, + id: EngineMessage.Id(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 0), + globallyUniqueId: nil, + groupingKey: nil, + groupInfo: nil, + threadId: nil, + timestamp: timestamp, + flags: author.id == peer.id ? [.Incoming] : [], + tags: [], + globalTags: [], + localTags: [], + forwardInfo: nil, + author: author, + text: text, + attributes: [], + media: [], + peers: [:], + associatedMessages: [:], + associatedMessageIds: [] + ) + ], + peer: EngineRenderedPeer(peer: peer), + combinedReadState: EnginePeerReadCounters(incomingReadId: 1000, outgoingReadId: 1000, count: unreadCount, markedUnread: false), + isRemovedFromTotalUnreadCount: false, + presence: presenceTimestamp.flatMap { presenceTimestamp in + EnginePeer.Presence(status: .present(until: presenceTimestamp + 1000), lastActivity: presenceTimestamp) + }, + hasUnseenMentions: false, + draftState: nil, + inputActivities: hasInputActivity ? [(author, .typingText)] : [], + promoInfo: nil, + ignoreUnreadBadge: false, + displayAsMessage: false, + hasFailedMessages: false + ), + editing: false, + hasActiveRevealControls: false, + selected: false, + header: nil, + enableContextActions: false, + hiddenOffset: false, + interaction: interaction + ) + } + + let selfPeer: EnginePeer = .user(TelegramUser(id: self.context.account.peerId, accessHash: nil, firstName: nil, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])) + let peer1: EnginePeer = .user(TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(1)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])) + let peer2: EnginePeer = .user(TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(2)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_2_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])) + let peer3: EnginePeer = .channel(TelegramChannel(id: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(3)), accessHash: nil, title: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Name, username: nil, photo: [], creationDate: 0, version: 0, participationStatus: .member, info: .group(.init(flags: [])), flags: [], restrictionInfo: nil, adminRights: nil, bannedRights: nil, defaultBannedRights: nil)) + let peer3Author: EnginePeer = .user(TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(4)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_AuthorName, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])) + let peer4: EnginePeer = .user(TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(4)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])) + let timestamp = self.referenceTimestamp - + let timestamp1 = timestamp + 120 - items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(messages: [Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: timestamp1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: selfPeer, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])], peer: RenderedPeer(peer: peer1), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false))]), isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) - + items.append(makeChatListItem( + peer: peer1, + author: selfPeer, + timestamp: timestamp1, + text: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Text + )) + let presenceTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + 60 * 60) let timestamp2 = timestamp + 3660 - items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer2.id, namespace: 0, id: 0), timestamp: timestamp2)), content: .peer(messages: [Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer2.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: timestamp2, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer2, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_2_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])], peer: RenderedPeer(peer: peer2), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 1, markedUnread: false))]), isRemovedFromTotalUnreadCount: false, presence: TelegramUserPresence(status: .present(until: presenceTimestamp), lastActivity: presenceTimestamp), summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) - + items.append(makeChatListItem( + peer: peer2, + author: peer2, + timestamp: timestamp2, + text: "", + presenceTimestamp: presenceTimestamp, + hasInputActivity: true + )) + let timestamp3 = timestamp + 3200 - items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer3.id, namespace: 0, id: 0), timestamp: timestamp3)), content: .peer(messages: [Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer3.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: timestamp3, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer3Author, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])], peer: RenderedPeer(peer: peer3), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) - + items.append(makeChatListItem( + peer: peer3, + author: peer3Author, + timestamp: timestamp3, + text: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Text + )) + let timestamp4 = timestamp + 3000 - items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer4.id, namespace: 0, id: 0), timestamp: timestamp4)), content: .peer(messages: [Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: timestamp4, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer4, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])], peer: RenderedPeer(peer: peer4), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) + items.append(makeChatListItem( + peer: peer4, + author: peer4, + timestamp: timestamp4, + text: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Text + )) let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, availableHeight: layout.size.height) if let chatNodes = self.chatNodes { @@ -934,7 +1019,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate sampleMessages.append(message5) let waveformBase64 = "DAAOAAkACQAGAAwADwAMABAADQAPABsAGAALAA0AGAAfABoAHgATABgAGQAYABQADAAVABEAHwANAA0ACQAWABkACQAOAAwACQAfAAAAGQAVAAAAEwATAAAACAAfAAAAHAAAABwAHwAAABcAGQAAABQADgAAABQAHwAAAB8AHwAAAAwADwAAAB8AEwAAABoAFwAAAB8AFAAAAAAAHwAAAAAAHgAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAAAA=" - let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: MemoryBuffer(data: Data(base64Encoded: waveformBase64)!))] + let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: Data(base64Encoded: waveformBase64)!)] let voiceMedia = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: voiceAttributes) let message6 = Message(stableId: 6, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 6), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66005, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [voiceMedia], peers: peers, associatedMessages: messages, associatedMessageIds: []) diff --git a/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift b/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift index cb1296b0e8..cfbc82bf35 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift @@ -360,41 +360,142 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate { gesture?.cancel() }, present: { _ in }) + + func makeChatListItem( + peer: EnginePeer, + author: EnginePeer, + timestamp: Int32, + text: String, + isPinned: Bool = false, + presenceTimestamp: Int32? = nil, + hasInputActivity: Bool = false, + unreadCount: Int32 = 0 + ) -> ChatListItem { + return ChatListItem( + presentationData: chatListPresentationData, + context: self.context, + peerGroupId: .root, + filterData: nil, + index: ChatListIndex(pinningIndex: isPinned ? 0 : nil, messageIndex: MessageIndex(id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 0), timestamp: timestamp)), + content: .peer( + messages: [ + EngineMessage( + stableId: 0, + stableVersion: 0, + id: EngineMessage.Id(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 0), + globallyUniqueId: nil, + groupingKey: nil, + groupInfo: nil, + threadId: nil, + timestamp: timestamp, + flags: author.id == peer.id ? [.Incoming] : [], + tags: [], + globalTags: [], + localTags: [], + forwardInfo: nil, + author: author, + text: text, + attributes: [], + media: [], + peers: [:], + associatedMessages: [:], + associatedMessageIds: [] + ) + ], + peer: EngineRenderedPeer(peer: peer), + combinedReadState: EnginePeerReadCounters(incomingReadId: 1000, outgoingReadId: 1000, count: unreadCount, markedUnread: false), + isRemovedFromTotalUnreadCount: false, + presence: presenceTimestamp.flatMap { presenceTimestamp in + EnginePeer.Presence(status: .present(until: presenceTimestamp + 1000), lastActivity: presenceTimestamp) + }, + hasUnseenMentions: false, + draftState: nil, + inputActivities: hasInputActivity ? [(author, .typingText)] : [], + promoInfo: nil, + ignoreUnreadBadge: false, + displayAsMessage: false, + hasFailedMessages: false + ), + editing: false, + hasActiveRevealControls: false, + selected: false, + header: nil, + enableContextActions: false, + hiddenOffset: false, + interaction: interaction + ) + } + let chatListPresentationData = ChatListPresentationData(theme: self.previewTheme, fontSize: self.presentationData.listsFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: true) - - let peers = SimpleDictionary() - let messages = SimpleDictionary() - let selfPeer = TelegramUser(id: self.context.account.peerId, accessHash: nil, firstName: nil, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) - let peer1 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(1)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) - let peer2 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(2)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_2_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) - let peer3 = TelegramChannel(id: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(3)), accessHash: nil, title: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Name, username: nil, photo: [], creationDate: 0, version: 0, participationStatus: .member, info: .group(.init(flags: [])), flags: [], restrictionInfo: nil, adminRights: nil, bannedRights: nil, defaultBannedRights: nil) - let peer3Author = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(4)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_AuthorName, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) - let peer4 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(4)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) - let peer5 = TelegramChannel(id: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(5)), accessHash: nil, title: self.presentationData.strings.Appearance_ThemePreview_ChatList_5_Name, username: nil, photo: [], creationDate: 0, version: 0, participationStatus: .member, info: .broadcast(.init(flags: [])), flags: [], restrictionInfo: nil, adminRights: nil, bannedRights: nil, defaultBannedRights: nil) - let peer6 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.SecretChat, id: PeerId.Id._internalFromInt64Value(5)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_6_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) - let peer7 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(6)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_7_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) + + let selfPeer: EnginePeer = .user(TelegramUser(id: self.context.account.peerId, accessHash: nil, firstName: nil, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])) + let peer1: EnginePeer = .user(TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(1)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])) + let peer2: EnginePeer = .user(TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(2)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_2_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])) + let peer3: EnginePeer = .channel(TelegramChannel(id: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(3)), accessHash: nil, title: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Name, username: nil, photo: [], creationDate: 0, version: 0, participationStatus: .member, info: .group(.init(flags: [])), flags: [], restrictionInfo: nil, adminRights: nil, bannedRights: nil, defaultBannedRights: nil)) + let peer3Author: EnginePeer = .user(TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(4)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_AuthorName, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])) + let peer4: EnginePeer = .user(TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(4)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])) + let peer5: EnginePeer = .channel(TelegramChannel(id: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(5)), accessHash: nil, title: self.presentationData.strings.Appearance_ThemePreview_ChatList_5_Name, username: nil, photo: [], creationDate: 0, version: 0, participationStatus: .member, info: .broadcast(.init(flags: [])), flags: [], restrictionInfo: nil, adminRights: nil, bannedRights: nil, defaultBannedRights: nil)) + let peer6: EnginePeer = .user(TelegramUser(id: PeerId(namespace: Namespaces.Peer.SecretChat, id: PeerId.Id._internalFromInt64Value(5)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_6_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])) + let peer7: EnginePeer = .user(TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(6)), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_7_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])) let timestamp = self.referenceTimestamp let timestamp1 = timestamp + 120 - items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(messages: [Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: timestamp1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: selfPeer, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])], peer: RenderedPeer(peer: peer1), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false))]), isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) + items.append(makeChatListItem( + peer: peer1, + author: selfPeer, + timestamp: timestamp1, + text: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Text + )) let presenceTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + 60 * 60) let timestamp2 = timestamp + 3660 - items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer2.id, namespace: 0, id: 0), timestamp: timestamp2)), content: .peer(messages: [Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer2.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: timestamp2, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer2, text: "", attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])], peer: RenderedPeer(peer: peer2), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: TelegramUserPresence(status: .present(until: presenceTimestamp), lastActivity: presenceTimestamp), summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: [(peer2, .typingText)], promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) + items.append(makeChatListItem( + peer: peer2, + author: peer2, + timestamp: timestamp2, + text: "", + presenceTimestamp: presenceTimestamp, + hasInputActivity: true + )) let timestamp3 = timestamp + 3200 - items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer3.id, namespace: 0, id: 0), timestamp: timestamp3)), content: .peer(messages: [Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer3.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: timestamp3, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer3Author, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])], peer: RenderedPeer(peer: peer3), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) + items.append(makeChatListItem( + peer: peer3, + author: peer3Author, + timestamp: timestamp3, + text: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Text + )) let timestamp4 = timestamp + 3000 - items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer4.id, namespace: 0, id: 0), timestamp: timestamp4)), content: .peer(messages: [Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: timestamp4, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer4, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])], peer: RenderedPeer(peer: peer4), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) + items.append(makeChatListItem( + peer: peer4, + author: peer4, + timestamp: timestamp4, + text: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Text + )) let timestamp5 = timestamp + 1000 - items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer5.id, namespace: 0, id: 0), timestamp: timestamp5)), content: .peer(messages: [Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: timestamp5, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer5, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_5_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])], peer: RenderedPeer(peer: peer5), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) - - items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer6.id, namespace: 0, id: 0), timestamp: timestamp - 360)), content: .peer(messages: [Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer6.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: timestamp - 360, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer6, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_6_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])], peer: RenderedPeer(peer: peer6), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 1, markedUnread: false))]), isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) - - items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer7.id, namespace: 0, id: 0), timestamp: timestamp - 420)), content: .peer(messages: [Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer7.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: timestamp - 420, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer6, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_7_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])], peer: RenderedPeer(peer: peer7), combinedReadState: nil, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)) + items.append(makeChatListItem( + peer: peer5, + author: peer5, + timestamp: timestamp5, + text: self.presentationData.strings.Appearance_ThemePreview_ChatList_5_Text + )) + + items.append(makeChatListItem( + peer: peer6, + author: peer6, + timestamp: timestamp - 360, + text: self.presentationData.strings.Appearance_ThemePreview_ChatList_6_Text + )) + + items.append(makeChatListItem( + peer: peer7, + author: peer6, + timestamp: timestamp - 420, + text: self.presentationData.strings.Appearance_ThemePreview_ChatList_7_Text + )) let width: CGFloat if case .regular = layout.metrics.widthClass { @@ -479,7 +580,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate { sampleMessages.append(message5) let waveformBase64 = "DAAOAAkACQAGAAwADwAMABAADQAPABsAGAALAA0AGAAfABoAHgATABgAGQAYABQADAAVABEAHwANAA0ACQAWABkACQAOAAwACQAfAAAAGQAVAAAAEwATAAAACAAfAAAAHAAAABwAHwAAABcAGQAAABQADgAAABQAHwAAAB8AHwAAAAwADwAAAB8AEwAAABoAFwAAAB8AFAAAAAAAHwAAAAAAHgAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAAAA=" - let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: MemoryBuffer(data: Data(base64Encoded: waveformBase64)!))] + let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: Data(base64Encoded: waveformBase64)!)] let voiceMedia = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: voiceAttributes) let message6 = Message(stableId: 6, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 6), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66005, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [voiceMedia], peers: peers, associatedMessages: messages, associatedMessageIds: []) diff --git a/submodules/ShareController/Sources/ShareSearchContainerNode.swift b/submodules/ShareController/Sources/ShareSearchContainerNode.swift index 82dc40011d..5b31153fbb 100644 --- a/submodules/ShareController/Sources/ShareSearchContainerNode.swift +++ b/submodules/ShareController/Sources/ShareSearchContainerNode.swift @@ -243,7 +243,7 @@ final class ShareSearchContainerNode: ASDisplayNode, ShareContentContainerNode { let foundLocalPeers = context.account.postbox.searchPeers(query: query.lowercased()) let foundRemotePeers: Signal<([FoundPeer], [FoundPeer], Bool), NoError> = .single(([], [], true)) |> then( - context.engine.peers.searchPeers(query: query) + context.engine.contacts.searchRemotePeers(query: query) |> delay(0.2, queue: Queue.concurrentDefaultQueue()) |> map { a, b -> ([FoundPeer], [FoundPeer], Bool) in return (a, b, false) diff --git a/submodules/ShareItems/Sources/ShareItems.swift b/submodules/ShareItems/Sources/ShareItems.swift index 851be6db77..2af74b474b 100644 --- a/submodules/ShareItems/Sources/ShareItems.swift +++ b/submodules/ShareItems/Sources/ShareItems.swift @@ -250,7 +250,7 @@ private func preparedShareItem(account: Account, to peerId: PeerId, value: [Stri waveform = MemoryBuffer(data: waveformData) } - return standaloneUploadedFile(account: account, peerId: peerId, text: "", source: .data(audioData), mimeType: mimeType, attributes: [.Audio(isVoice: isVoice, duration: Int(duration), title: title, performer: artist, waveform: waveform), .FileName(fileName: fileName)], hintFileIsLarge: audioData.count > 10 * 1024 * 1024) + return standaloneUploadedFile(account: account, peerId: peerId, text: "", source: .data(audioData), mimeType: mimeType, attributes: [.Audio(isVoice: isVoice, duration: Int(duration), title: title, performer: artist, waveform: waveform?.makeData()), .FileName(fileName: fileName)], hintFileIsLarge: audioData.count > 10 * 1024 * 1024) |> mapError { _ -> Void in return Void() } |> mapToSignal { event -> Signal in switch event { diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift index e178e3128f..d817c0d0a6 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift @@ -2488,7 +2488,7 @@ public final class VoiceChatController: ViewController { if peers.count > 1 { for peer in peers { if peer.peer.id == myPeerId { - items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_DisplayAs, textLayout: .secondLineWithValue(EnginePeer(peer.peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)), icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: peerAvatarCompleteImage(account: strongSelf.context.account, peer: peer.peer, size: avatarSize)), action: { c, _ in + items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_DisplayAs, textLayout: .secondLineWithValue(EnginePeer(peer.peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)), icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: peerAvatarCompleteImage(account: strongSelf.context.account, peer: EnginePeer(peer.peer), size: avatarSize)), action: { c, _ in guard let strongSelf = self else { return } @@ -2883,7 +2883,7 @@ public final class VoiceChatController: ViewController { let isSelected = peer.peer.id == myPeerId let extendedAvatarSize = CGSize(width: 35.0, height: 35.0) - let avatarSignal = peerAvatarCompleteImage(account: strongSelf.context.account, peer: peer.peer, size: avatarSize) + let avatarSignal = peerAvatarCompleteImage(account: strongSelf.context.account, peer: EnginePeer(peer.peer), size: avatarSize) |> map { image -> UIImage? in if isSelected, let image = image { return generateImage(extendedAvatarSize, rotatedContext: { size, context in diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatMainStageNode.swift b/submodules/TelegramCallsUI/Sources/VoiceChatMainStageNode.swift index 59e62a17f4..313994339d 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatMainStageNode.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatMainStageNode.swift @@ -732,8 +732,8 @@ final class VoiceChatMainStageNode: ASDisplayNode { let peer = peerEntry.peer let presentationData = self.context.sharedContext.currentPresentationData.with { $0 } if !arePeersEqual(previousPeerEntry?.peer, peerEntry.peer) { - self.backdropAvatarNode.setSignal(peerAvatarCompleteImage(account: self.context.account, peer: peer, size: CGSize(width: 240.0, height: 240.0), round: false, font: avatarPlaceholderFont(size: 78.0), drawLetters: false, blurred: true)) - self.avatarNode.setSignal(peerAvatarCompleteImage(account: self.context.account, peer: peer, size: CGSize(width: 180.0, height: 180.0), font: avatarPlaceholderFont(size: 78.0), fullSize: true)) + self.backdropAvatarNode.setSignal(peerAvatarCompleteImage(account: self.context.account, peer: EnginePeer(peer), size: CGSize(width: 240.0, height: 240.0), round: false, font: avatarPlaceholderFont(size: 78.0), drawLetters: false, blurred: true)) + self.avatarNode.setSignal(peerAvatarCompleteImage(account: self.context.account, peer: EnginePeer(peer), size: CGSize(width: 180.0, height: 180.0), font: avatarPlaceholderFont(size: 78.0), fullSize: true)) } var gradient: VoiceChatBlobNode.Gradient = .active diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatTileItemNode.swift b/submodules/TelegramCallsUI/Sources/VoiceChatTileItemNode.swift index 1c926dc39f..df22c4536f 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatTileItemNode.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatTileItemNode.swift @@ -930,7 +930,7 @@ private class VoiceChatTileShimmeringNode: ASDisplayNode { self.addSubnode(self.borderNode) self.borderNode.addSubnode(self.borderEffectNode) - self.backgroundNode.setSignal(peerAvatarCompleteImage(account: account, peer: peer, size: CGSize(width: 250.0, height: 250.0), round: false, font: Font.regular(16.0), drawLetters: false, fullSize: false, blurred: true)) + self.backgroundNode.setSignal(peerAvatarCompleteImage(account: account, peer: EnginePeer(peer), size: CGSize(width: 250.0, height: 250.0), round: false, font: Font.regular(16.0), drawLetters: false, fullSize: false, blurred: true)) } public override func didLoad() { diff --git a/submodules/TelegramCore/Sources/Account/AccountManager.swift b/submodules/TelegramCore/Sources/Account/AccountManager.swift index a5785e1192..2997ede7f1 100644 --- a/submodules/TelegramCore/Sources/Account/AccountManager.swift +++ b/submodules/TelegramCore/Sources/Account/AccountManager.swift @@ -404,6 +404,8 @@ public func managedCleanupAccounts(networkArguments: NetworkInitializationArgume } } +public typealias AccountManagerPreferencesEntry = PreferencesEntry + private func cleanupAccount(networkArguments: NetworkInitializationArguments, accountManager: AccountManager, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters, attributes: [TelegramAccountManagerTypes.Attribute], rootPath: String, auxiliaryMethods: AccountAuxiliaryMethods) -> Signal { let beginWithTestingEnvironment = attributes.contains(where: { attribute in if case let .environment(accountEnvironment) = attribute, case .test = accountEnvironment.environment { diff --git a/submodules/Postbox/Sources/AccessChallengeDataView.swift b/submodules/TelegramCore/Sources/AccountManager/AccessChallengeDataView.swift similarity index 97% rename from submodules/Postbox/Sources/AccessChallengeDataView.swift rename to submodules/TelegramCore/Sources/AccountManager/AccessChallengeDataView.swift index adfbb45e35..bd66377472 100644 --- a/submodules/Postbox/Sources/AccessChallengeDataView.swift +++ b/submodules/TelegramCore/Sources/AccountManager/AccessChallengeDataView.swift @@ -1,4 +1,5 @@ import Foundation +import Postbox final class MutableAccessChallengeDataView { var data: PostboxAccessChallengeData diff --git a/submodules/Postbox/Sources/AccountManagerAtomicState.swift b/submodules/TelegramCore/Sources/AccountManager/AccountManagerAtomicState.swift similarity index 100% rename from submodules/Postbox/Sources/AccountManagerAtomicState.swift rename to submodules/TelegramCore/Sources/AccountManager/AccountManagerAtomicState.swift diff --git a/submodules/Postbox/Sources/AccountManager.swift b/submodules/TelegramCore/Sources/AccountManager/AccountManagerImpl.swift similarity index 99% rename from submodules/Postbox/Sources/AccountManager.swift rename to submodules/TelegramCore/Sources/AccountManager/AccountManagerImpl.swift index 520560921a..c155557acf 100644 --- a/submodules/Postbox/Sources/AccountManager.swift +++ b/submodules/TelegramCore/Sources/AccountManager/AccountManagerImpl.swift @@ -1,5 +1,6 @@ import Foundation import SwiftSignalKit +import Postbox public protocol AccountManagerTypes { associatedtype Attribute: AccountRecordAttribute diff --git a/submodules/Postbox/Sources/AccountManagerMetadataTable.swift b/submodules/TelegramCore/Sources/AccountManager/AccountManagerMetadataTable.swift similarity index 99% rename from submodules/Postbox/Sources/AccountManagerMetadataTable.swift rename to submodules/TelegramCore/Sources/AccountManager/AccountManagerMetadataTable.swift index 591a7fb95b..8ba6facf97 100644 --- a/submodules/Postbox/Sources/AccountManagerMetadataTable.swift +++ b/submodules/TelegramCore/Sources/AccountManager/AccountManagerMetadataTable.swift @@ -1,4 +1,5 @@ import Foundation +import Postbox public struct AccessChallengeAttempts: Equatable { public let count: Int32 diff --git a/submodules/Postbox/Sources/AccountManagerRecordTable.swift b/submodules/TelegramCore/Sources/AccountManager/AccountManagerRecordTable.swift similarity index 99% rename from submodules/Postbox/Sources/AccountManagerRecordTable.swift rename to submodules/TelegramCore/Sources/AccountManager/AccountManagerRecordTable.swift index 59b79ca8de..2c2896727f 100644 --- a/submodules/Postbox/Sources/AccountManagerRecordTable.swift +++ b/submodules/TelegramCore/Sources/AccountManager/AccountManagerRecordTable.swift @@ -1,4 +1,5 @@ import Foundation +import Postbox enum AccountManagerRecordOperation { case set(id: AccountRecordId, record: AccountRecord?) diff --git a/submodules/Postbox/Sources/AccountManagerSharedDataTable.swift b/submodules/TelegramCore/Sources/AccountManager/AccountManagerSharedDataTable.swift similarity index 98% rename from submodules/Postbox/Sources/AccountManagerSharedDataTable.swift rename to submodules/TelegramCore/Sources/AccountManager/AccountManagerSharedDataTable.swift index b5dc4f7b92..58a868c3e3 100644 --- a/submodules/Postbox/Sources/AccountManagerSharedDataTable.swift +++ b/submodules/TelegramCore/Sources/AccountManager/AccountManagerSharedDataTable.swift @@ -1,4 +1,5 @@ import Foundation +import Postbox final class AccountManagerSharedDataTable: Table { diff --git a/submodules/Postbox/Sources/AccountRecord.swift b/submodules/TelegramCore/Sources/AccountManager/AccountRecord.swift similarity index 99% rename from submodules/Postbox/Sources/AccountRecord.swift rename to submodules/TelegramCore/Sources/AccountManager/AccountRecord.swift index ab8e2d3a29..4ea47f321c 100644 --- a/submodules/Postbox/Sources/AccountRecord.swift +++ b/submodules/TelegramCore/Sources/AccountManager/AccountRecord.swift @@ -1,4 +1,5 @@ import Foundation +import Postbox public protocol AccountRecordAttribute: Codable { func isEqual(to: AccountRecordAttribute) -> Bool diff --git a/submodules/Postbox/Sources/AccountRecordsView.swift b/submodules/TelegramCore/Sources/AccountManager/AccountRecordsView.swift similarity index 100% rename from submodules/Postbox/Sources/AccountRecordsView.swift rename to submodules/TelegramCore/Sources/AccountManager/AccountRecordsView.swift diff --git a/submodules/Postbox/Sources/AccountSharedData.swift b/submodules/TelegramCore/Sources/AccountManager/AccountSharedData.swift similarity index 98% rename from submodules/Postbox/Sources/AccountSharedData.swift rename to submodules/TelegramCore/Sources/AccountManager/AccountSharedData.swift index 62676e4ffa..c067fd23ac 100644 --- a/submodules/Postbox/Sources/AccountSharedData.swift +++ b/submodules/TelegramCore/Sources/AccountManager/AccountSharedData.swift @@ -1,4 +1,5 @@ import Foundation +import Postbox final class MutableAccountSharedDataView { private let keys: Set diff --git a/submodules/Postbox/Sources/NoticeEntryView.swift b/submodules/TelegramCore/Sources/AccountManager/NoticeEntryView.swift similarity index 98% rename from submodules/Postbox/Sources/NoticeEntryView.swift rename to submodules/TelegramCore/Sources/AccountManager/NoticeEntryView.swift index bdbd8ad107..af99e194d2 100644 --- a/submodules/Postbox/Sources/NoticeEntryView.swift +++ b/submodules/TelegramCore/Sources/AccountManager/NoticeEntryView.swift @@ -1,4 +1,5 @@ import Foundation +import Postbox final class MutableNoticeEntryView { private let key: NoticeEntryKey diff --git a/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaFile.swift b/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaFile.swift index 493d4e8b04..bd68db3422 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaFile.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaFile.swift @@ -100,12 +100,7 @@ func telegramMediaFileAttributesFromApiAttributes(_ attributes: [Api.DocumentAtt result.append(.Video(duration: Int(duration), size: PixelDimensions(width: w, height: h), flags: videoFlags)) case let .documentAttributeAudio(flags, duration, title, performer, waveform): let isVoice = (flags & (1 << 10)) != 0 - var waveformBuffer: MemoryBuffer? - if let waveform = waveform { - let memory = malloc(waveform.size)! - memcpy(memory, waveform.data, waveform.size) - waveformBuffer = MemoryBuffer(memory: memory, capacity: waveform.size, length: waveform.size, freeWhenDone: true) - } + let waveformBuffer: Data? = waveform?.makeData() result.append(.Audio(isVoice: isVoice, duration: Int(duration), title: title, performer: performer, waveform: waveformBuffer)) } } diff --git a/submodules/TelegramCore/Sources/PendingMessages/PendingMessageUploadedContent.swift b/submodules/TelegramCore/Sources/PendingMessages/PendingMessageUploadedContent.swift index 61cdf3b326..1dfca45b6e 100644 --- a/submodules/TelegramCore/Sources/PendingMessages/PendingMessageUploadedContent.swift +++ b/submodules/TelegramCore/Sources/PendingMessages/PendingMessageUploadedContent.swift @@ -539,7 +539,7 @@ func inputDocumentAttributesFromFileAttributes(_ fileAttributes: [TelegramMediaF var waveformBuffer: Buffer? if let waveform = waveform { flags |= Int32(1 << 2) - waveformBuffer = Buffer(data: waveform.makeData()) + waveformBuffer = Buffer(data: waveform) } attributes.append(.documentAttributeAudio(flags: flags, duration: Int32(duration), title: title, performer: performer, waveform: waveformBuffer)) } diff --git a/submodules/TelegramCore/Sources/State/ManagedSecretChatOutgoingOperations.swift b/submodules/TelegramCore/Sources/State/ManagedSecretChatOutgoingOperations.swift index 43f2a25c32..2eb72db842 100644 --- a/submodules/TelegramCore/Sources/State/ManagedSecretChatOutgoingOperations.swift +++ b/submodules/TelegramCore/Sources/State/ManagedSecretChatOutgoingOperations.swift @@ -517,7 +517,7 @@ private func decryptedAttributes46(_ attributes: [TelegramMediaFileAttribute], t var waveformBuffer: Buffer? if let waveform = waveform { flags |= Int32(1 << 2) - waveformBuffer = Buffer(data: waveform.makeData()) + waveformBuffer = Buffer(data: waveform) } result.append(.documentAttributeAudio(flags: flags, duration: Int32(duration), title: title, performer: performer, waveform: waveformBuffer)) case .HasLinkedStickers: @@ -576,7 +576,7 @@ private func decryptedAttributes73(_ attributes: [TelegramMediaFileAttribute], t var waveformBuffer: Buffer? if let waveform = waveform { flags |= Int32(1 << 2) - waveformBuffer = Buffer(data: waveform.makeData()) + waveformBuffer = Buffer(data: waveform) } result.append(.documentAttributeAudio(flags: flags, duration: Int32(duration), title: title, performer: performer, waveform: waveformBuffer)) case .HasLinkedStickers: @@ -635,7 +635,7 @@ private func decryptedAttributes101(_ attributes: [TelegramMediaFileAttribute], var waveformBuffer: Buffer? if let waveform = waveform { flags |= Int32(1 << 2) - waveformBuffer = Buffer(data: waveform.makeData()) + waveformBuffer = Buffer(data: waveform) } result.append(.documentAttributeAudio(flags: flags, duration: Int32(duration), title: title, performer: performer, waveform: waveformBuffer)) case .HasLinkedStickers: diff --git a/submodules/TelegramCore/Sources/State/ProcessSecretChatIncomingDecryptedOperations.swift b/submodules/TelegramCore/Sources/State/ProcessSecretChatIncomingDecryptedOperations.swift index 17d268279b..646feeb3dc 100644 --- a/submodules/TelegramCore/Sources/State/ProcessSecretChatIncomingDecryptedOperations.swift +++ b/submodules/TelegramCore/Sources/State/ProcessSecretChatIncomingDecryptedOperations.swift @@ -538,12 +538,7 @@ extension TelegramMediaFileAttribute { self = .Animated case let .documentAttributeAudio(flags, duration, title, performer, waveform): let isVoice = (flags & (1 << 10)) != 0 - var waveformBuffer: MemoryBuffer? - if let waveform = waveform { - let memory = malloc(waveform.size)! - memcpy(memory, waveform.data, waveform.size) - waveformBuffer = MemoryBuffer(memory: memory, capacity: waveform.size, length: waveform.size, freeWhenDone: true) - } + let waveformBuffer: Data? = waveform?.makeData() self = .Audio(isVoice: isVoice, duration: Int(duration), title: title, performer: performer, waveform: waveformBuffer) case let .documentAttributeFilename(fileName): self = .FileName(fileName: fileName) @@ -571,12 +566,7 @@ extension TelegramMediaFileAttribute { self = .Animated case let .documentAttributeAudio(flags, duration, title, performer, waveform): let isVoice = (flags & (1 << 10)) != 0 - var waveformBuffer: MemoryBuffer? - if let waveform = waveform { - let memory = malloc(waveform.size)! - memcpy(memory, waveform.data, waveform.size) - waveformBuffer = MemoryBuffer(memory: memory, capacity: waveform.size, length: waveform.size, freeWhenDone: true) - } + let waveformBuffer: Data? = waveform?.makeData() self = .Audio(isVoice: isVoice, duration: Int(duration), title: title, performer: performer, waveform: waveformBuffer) case let .documentAttributeFilename(fileName): self = .FileName(fileName: fileName) @@ -608,12 +598,7 @@ extension TelegramMediaFileAttribute { self = .Animated case let .documentAttributeAudio(flags, duration, title, performer, waveform): let isVoice = (flags & (1 << 10)) != 0 - var waveformBuffer: MemoryBuffer? - if let waveform = waveform { - let memory = malloc(waveform.size)! - memcpy(memory, waveform.data, waveform.size) - waveformBuffer = MemoryBuffer(memory: memory, capacity: waveform.size, length: waveform.size, freeWhenDone: true) - } + let waveformBuffer: Data? = waveform?.makeData() self = .Audio(isVoice: isVoice, duration: Int(duration), title: title, performer: performer, waveform: waveformBuffer) case let .documentAttributeFilename(fileName): self = .FileName(fileName: fileName) diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaFile.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaFile.swift index 9a667cf238..d0430b1b78 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaFile.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaFile.swift @@ -140,7 +140,7 @@ public enum TelegramMediaFileAttribute: PostboxCoding { case ImageSize(size: PixelDimensions) case Animated case Video(duration: Int, size: PixelDimensions, flags: TelegramMediaVideoFlags) - case Audio(isVoice: Bool, duration: Int, title: String?, performer: String?, waveform: MemoryBuffer?) + case Audio(isVoice: Bool, duration: Int, title: String?, performer: String?, waveform: Data?) case HasLinkedStickers case hintFileIsLarge case hintIsValidated @@ -160,9 +160,9 @@ public enum TelegramMediaFileAttribute: PostboxCoding { self = .Video(duration: Int(decoder.decodeInt32ForKey("du", orElse: 0)), size: PixelDimensions(width: decoder.decodeInt32ForKey("w", orElse: 0), height: decoder.decodeInt32ForKey("h", orElse: 0)), flags: TelegramMediaVideoFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0))) case typeAudio: let waveformBuffer = decoder.decodeBytesForKeyNoCopy("wf") - var waveform: MemoryBuffer? + var waveform: Data? if let waveformBuffer = waveformBuffer { - waveform = MemoryBuffer(copyOf: waveformBuffer) + waveform = waveformBuffer.makeData() } self = .Audio(isVoice: decoder.decodeInt32ForKey("iv", orElse: 0) != 0, duration: Int(decoder.decodeInt32ForKey("du", orElse: 0)), title: decoder.decodeOptionalStringForKey("ti"), performer: decoder.decodeOptionalStringForKey("pe"), waveform: waveform) case typeHasLinkedStickers: @@ -217,7 +217,7 @@ public enum TelegramMediaFileAttribute: PostboxCoding { encoder.encodeString(performer, forKey: "pe") } if let waveform = waveform { - encoder.encodeBytes(waveform, forKey: "wf") + encoder.encodeBytes(MemoryBuffer(data: waveform), forKey: "wf") } case .HasLinkedStickers: encoder.encodeInt32(typeHasLinkedStickers, forKey: "t") diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Contacts/TelegramEngineContacts.swift b/submodules/TelegramCore/Sources/TelegramEngine/Contacts/TelegramEngineContacts.swift index 172f879418..b69ef88237 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Contacts/TelegramEngineContacts.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Contacts/TelegramEngineContacts.swift @@ -40,5 +40,16 @@ public extension TelegramEngine { public func acceptAndShareContact(peerId: PeerId) -> Signal { return _internal_acceptAndShareContact(account: self.account, peerId: peerId) } + + public func searchRemotePeers(query: String) -> Signal<([FoundPeer], [FoundPeer]), NoError> { + return _internal_searchPeers(account: self.account, query: query) + } + + public func searchLocalPeers(query: String) -> Signal<[EngineRenderedPeer], NoError> { + return self.account.postbox.searchPeers(query: query) + |> map { peers in + return peers.map(EngineRenderedPeer.init) + } + } } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Data/Messages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Data/Messages.swift index fa9842ce49..6229bb1985 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Data/Messages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Data/Messages.swift @@ -13,6 +13,45 @@ public final class EngineTotalReadCounters { } } +public struct EnginePeerReadCounters: Equatable { + private let state: CombinedPeerReadState + + public init(state: CombinedPeerReadState) { + self.state = state + } + + public init() { + self.state = CombinedPeerReadState(states: []) + } + + public var count: Int32 { + return self.state.count + } + + public var markedUnread: Bool { + return self.state.markedUnread + } + + + public var isUnread: Bool { + return self.state.isUnread + } + + public func isOutgoingMessageIndexRead(_ index: EngineMessage.Index) -> Bool { + return self.state.isOutgoingMessageIndexRead(index) + } + + public func isIncomingMessageIndexRead(_ index: EngineMessage.Index) -> Bool { + return self.state.isIncomingMessageIndexRead(index) + } +} + +public extension EnginePeerReadCounters { + init(incomingReadId: EngineMessage.Id.Id, outgoingReadId: EngineMessage.Id.Id, count: Int32, markedUnread: Bool) { + self.init(state: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, .idBased(maxIncomingReadId: incomingReadId, maxOutgoingReadId: outgoingReadId, maxKnownId: max(incomingReadId, outgoingReadId), count: count, markedUnread: markedUnread))])) + } +} + public extension TelegramEngine.EngineData.Item { enum Messages { public struct Message: TelegramEngineDataItem, PostboxViewDataItem { @@ -64,6 +103,31 @@ public extension TelegramEngine.EngineData.Item { } } + public struct PeerUnreadCount: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem { + public typealias Result = Int + + fileprivate let id: EnginePeer.Id + public var mapKey: EnginePeer.Id { + return self.id + } + + var key: PostboxViewKey { + return .unreadCounts(items: [.peer(self.id)]) + } + + public init(id: EnginePeer.Id) { + self.id = id + } + + func extract(view: PostboxView) -> Int { + guard let view = view as? UnreadMessageCountsView else { + preconditionFailure() + } + + return Int(view.count(for: .peer(self.id)) ?? 0) + } + } + public struct TotalReadCounters: TelegramEngineDataItem, PostboxViewDataItem { public typealias Result = EngineTotalReadCounters diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Data/PeerSummary.swift b/submodules/TelegramCore/Sources/TelegramEngine/Data/PeerSummary.swift index 57efef204b..405e09cd03 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Data/PeerSummary.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Data/PeerSummary.swift @@ -3,10 +3,13 @@ import Postbox public extension TelegramEngine.EngineData.Item { enum Peer { - public struct Peer: TelegramEngineDataItem, PostboxViewDataItem { + public struct Peer: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem { public typealias Result = Optional fileprivate var id: EnginePeer.Id + public var mapKey: EnginePeer.Id { + return self.id + } public init(id: EnginePeer.Id) { self.id = id @@ -27,10 +30,108 @@ public extension TelegramEngine.EngineData.Item { } } + public struct RenderedPeer: TelegramEngineDataItem, PostboxViewDataItem { + public typealias Result = Optional + + fileprivate var id: EnginePeer.Id + public var mapKey: EnginePeer.Id { + return self.id + } + + public init(id: EnginePeer.Id) { + self.id = id + } + + var key: PostboxViewKey { + return .peer(peerId: self.id, components: []) + } + + func extract(view: PostboxView) -> Result { + guard let view = view as? PeerView else { + preconditionFailure() + } + var peers: [EnginePeer.Id: EnginePeer] = [:] + guard let peer = view.peers[self.id] else { + return nil + } + peers[peer.id] = EnginePeer(peer) + + if let secretChat = peer as? TelegramSecretChat { + guard let mainPeer = view.peers[secretChat.regularPeerId] else { + return nil + } + peers[mainPeer.id] = EnginePeer(mainPeer) + } + + return EngineRenderedPeer(peerId: self.id, peers: peers) + } + } + + public struct Presence: TelegramEngineDataItem, PostboxViewDataItem { + public typealias Result = Optional + + fileprivate var id: EnginePeer.Id + public var mapKey: EnginePeer.Id { + return self.id + } + + public init(id: EnginePeer.Id) { + self.id = id + } + + var key: PostboxViewKey { + return .peer(peerId: self.id, components: []) + } + + func extract(view: PostboxView) -> Result { + guard let view = view as? PeerView else { + preconditionFailure() + } + var presencePeerId = self.id + if let secretChat = view.peers[self.id] as? TelegramSecretChat { + presencePeerId = secretChat.regularPeerId + } + guard let presence = view.peerPresences[presencePeerId] else { + return nil + } + return EnginePeer.Presence(presence) + } + } + + public struct NotificationSettings: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem { + public typealias Result = Optional + + fileprivate var id: EnginePeer.Id + public var mapKey: EnginePeer.Id { + return self.id + } + + public init(id: EnginePeer.Id) { + self.id = id + } + + var key: PostboxViewKey { + return .peer(peerId: self.id, components: []) + } + + func extract(view: PostboxView) -> Result { + guard let view = view as? PeerView else { + preconditionFailure() + } + guard let notificationSettings = view.notificationSettings as? TelegramPeerNotificationSettings else { + return nil + } + return EnginePeer.NotificationSettings(notificationSettings) + } + } + public struct ParticipantCount: TelegramEngineDataItem, PostboxViewDataItem { public typealias Result = Optional fileprivate var id: EnginePeer.Id + public var mapKey: EnginePeer.Id { + return self.id + } public init(id: EnginePeer.Id) { self.id = id @@ -62,6 +163,9 @@ public extension TelegramEngine.EngineData.Item { public typealias Result = Optional fileprivate var id: EnginePeer.Id + public var mapKey: EnginePeer.Id { + return self.id + } public init(id: EnginePeer.Id) { self.id = id diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Data/TelegramEngineData.swift b/submodules/TelegramCore/Sources/TelegramEngine/Data/TelegramEngineData.swift index f28ae11346..385c2b1778 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Data/TelegramEngineData.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Data/TelegramEngineData.swift @@ -5,19 +5,62 @@ public protocol TelegramEngineDataItem { associatedtype Result } -protocol AnyPostboxViewDataItem { - var key: PostboxViewKey { get } +public protocol TelegramEngineMapKeyDataItem { + associatedtype Key: Hashable - func _extract(view: PostboxView) -> Any + var mapKey: Key { get } +} + +protocol AnyPostboxViewDataItem { + var keys: [PostboxViewKey] { get } + + func _extract(views: [PostboxViewKey: PostboxView]) -> Any } protocol PostboxViewDataItem: TelegramEngineDataItem, AnyPostboxViewDataItem { + var key: PostboxViewKey { get } + func extract(view: PostboxView) -> Result } extension PostboxViewDataItem { - func _extract(view: PostboxView) -> Any { - return self.extract(view: view) + var keys: [PostboxViewKey] { + return [self.key] + } + + func _extract(views: [PostboxViewKey: PostboxView]) -> Any { + return self.extract(view: views[self.key]!) + } +} + +public final class EngineDataMap: TelegramEngineDataItem, AnyPostboxViewDataItem { + public typealias Result = [Item.Key: Item.Result] + + private let items: [Item] + + public init(_ items: [Item]) { + self.items = items + } + + var keys: [PostboxViewKey] { + var keys = Set() + for item in self.items { + for key in (item as! AnyPostboxViewDataItem).keys { + keys.insert(key) + } + } + return Array(keys) + } + + func _extract(views: [PostboxViewKey: PostboxView]) -> Any { + var result: [Item.Key: Item.Result] = [:] + + for item in self.items { + let itemResult = (item as! AnyPostboxViewDataItem)._extract(views: views) + result[item.mapKey] = (itemResult as! Item.Result) + } + + return result } } @@ -33,15 +76,18 @@ public extension TelegramEngine { } private func _subscribe(items: [AnyPostboxViewDataItem]) -> Signal<[Any], NoError> { - return self.account.postbox.combinedView(keys: Array(Set(items.map(\.key)))) + var keys = Set() + for item in items { + for key in item.keys { + keys.insert(key) + } + } + return self.account.postbox.combinedView(keys: Array(keys)) |> map { views -> [Any] in var results: [Any] = [] for item in items { - guard let view = views.views[item.key] else { - preconditionFailure() - } - results.append(item._extract(view: view)) + results.append(item._extract(views: views.views)) } return results diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/ChatList.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/ChatList.swift index 5023bcdef8..c49756c107 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/ChatList.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/ChatList.swift @@ -6,12 +6,23 @@ public final class EngineChatList { case archive } + public typealias MessageTagSummaryInfo = ChatListMessageTagSummaryInfo + + public enum PinnedItem { + public typealias Id = PinnedItemId + } + + public enum RelativePosition { + case later(than: EngineChatList.Item.Index?) + case earlier(than: EngineChatList.Item.Index?) + } + public final class Item { public typealias Index = ChatListIndex public let index: Index public let messages: [EngineMessage] - public let readState: EngineReadState? + public let readCounters: EnginePeerReadCounters? public let isMuted: Bool public let draftText: String? public let renderedPeer: EngineRenderedPeer @@ -23,7 +34,7 @@ public final class EngineChatList { public init( index: Index, messages: [EngineMessage], - readState: EngineReadState?, + readCounters: EnginePeerReadCounters?, isMuted: Bool, draftText: String?, renderedPeer: EngineRenderedPeer, @@ -34,7 +45,7 @@ public final class EngineChatList { ) { self.index = index self.messages = messages - self.readState = readState + self.readCounters = readCounters self.isMuted = isMuted self.draftText = draftText self.renderedPeer = renderedPeer @@ -45,8 +56,8 @@ public final class EngineChatList { } } - public final class GroupItem { - public final class Item { + public final class GroupItem: Equatable { + public final class Item: Equatable { public let peer: EngineRenderedPeer public let isUnread: Bool @@ -54,6 +65,16 @@ public final class EngineChatList { self.peer = peer self.isUnread = isUnread } + + public static func ==(lhs: Item, rhs: Item) -> Bool { + if lhs.peer != rhs.peer { + return false + } + if lhs.isUnread != rhs.isUnread { + return false + } + return true + } } public let id: Group @@ -72,23 +93,71 @@ public final class EngineChatList { self.items = items self.unreadCount = unreadCount } + + public static func ==(lhs: GroupItem, rhs: GroupItem) -> Bool { + if lhs.id != rhs.id { + return false + } + if lhs.topMessage?.index != rhs.topMessage?.index { + return false + } + if lhs.topMessage?.stableVersion != rhs.topMessage?.stableVersion { + return false + } + if lhs.items != rhs.items { + return false + } + if lhs.unreadCount != rhs.unreadCount { + return false + } + return true + } + } + + public final class AdditionalItem { + public final class PromoInfo { + public enum Content { + case proxy + case psa(type: String, message: String?) + } + + public let content: Content + + public init(content: Content) { + self.content = content + } + } + + public let item: Item + public let promoInfo: PromoInfo + + public init(item: Item, promoInfo: PromoInfo) { + self.item = item + self.promoInfo = promoInfo + } } public let items: [Item] public let groupItems: [GroupItem] + public let additionalItems: [AdditionalItem] public let hasEarlier: Bool public let hasLater: Bool + public let isLoading: Bool init( items: [Item], groupItems: [GroupItem], + additionalItems: [AdditionalItem], hasEarlier: Bool, - hasLater: Bool + hasLater: Bool, + isLoading: Bool ) { self.items = items self.groupItems = groupItems + self.additionalItems = additionalItems self.hasEarlier = hasEarlier self.hasLater = hasLater + self.isLoading = isLoading } } @@ -113,16 +182,44 @@ public extension EngineChatList.Group { } } +public extension EngineChatList.RelativePosition { + init(_ position: ChatListRelativePosition) { + switch position { + case let .earlier(than): + self = .earlier(than: than) + case let .later(than): + self = .later(than: than) + } + } + + func _asPosition() -> ChatListRelativePosition { + switch self { + case let .earlier(than): + return .earlier(than: than) + case let .later(than): + return .later(than: than) + } + } +} + extension EngineChatList.Item { convenience init?(_ entry: ChatListEntry) { switch entry { - case let .MessageEntry(index, messages, readState, isRemovedFromTotalUnreadCount, _, renderedPeer, presence, summaryInfo, hasFailed, isContact): + case let .MessageEntry(index, messages, readState, isRemovedFromTotalUnreadCount, embeddedState, renderedPeer, presence, summaryInfo, hasFailed, isContact): + var draftText: String? + if let embeddedState = embeddedState, let _ = embeddedState.overrideChatTimestamp { + if let opaqueState = _internal_decodeStoredChatInterfaceState(state: embeddedState) { + if let text = opaqueState.synchronizeableInputState?.text { + draftText = text + } + } + } self.init( index: index, messages: messages.map(EngineMessage.init), - readState: readState.flatMap(EngineReadState.init), + readCounters: readState.flatMap(EnginePeerReadCounters.init), isMuted: isRemovedFromTotalUnreadCount, - draftText: nil, + draftText: draftText, renderedPeer: EngineRenderedPeer(renderedPeer), presence: presence.flatMap(EnginePeer.Presence.init), hasUnseenMentions: (summaryInfo.tagSummaryCount ?? 0) > (summaryInfo.actionsSummaryCount ?? 0), @@ -151,13 +248,56 @@ extension EngineChatList.GroupItem { } } -extension EngineChatList { +extension EngineChatList.AdditionalItem.PromoInfo { + convenience init(_ item: PromoChatListItem) { + let content: EngineChatList.AdditionalItem.PromoInfo.Content + switch item.kind { + case .proxy: + content = .proxy + case let .psa(type, message): + content = .psa(type: type, message: message) + } + + self.init(content: content) + } +} + +extension EngineChatList.AdditionalItem { + convenience init?(_ entry: ChatListAdditionalItemEntry) { + guard let item = EngineChatList.Item(entry.entry) else { + return nil + } + guard let promoInfo = (entry.info as? PromoChatListItem).flatMap(EngineChatList.AdditionalItem.PromoInfo.init) else { + return nil + } + self.init(item: item, promoInfo: promoInfo) + } +} + +public extension EngineChatList { convenience init(_ view: ChatListView) { + var isLoading = false + + var items: [EngineChatList.Item] = [] + loop: for entry in view.entries { + switch entry { + case .MessageEntry: + if let item = EngineChatList.Item(entry) { + items.append(item) + } + case .HoleEntry: + isLoading = true + break loop + } + } + self.init( - items: view.entries.compactMap(EngineChatList.Item.init), + items: items, groupItems: view.groupEntries.map(EngineChatList.GroupItem.init), + additionalItems: view.additionalItemEntries.compactMap(EngineChatList.AdditionalItem.init), hasEarlier: view.earlierIndex != nil, - hasLater: view.laterIndex != nil + hasLater: view.laterIndex != nil, + isLoading: isLoading ) } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Media.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Media.swift index a1d8d9a14f..7006a32de6 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Media.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Media.swift @@ -30,6 +30,39 @@ public enum EngineMedia { case webpage(TelegramMediaWebpage) } +public extension EngineMedia { + var id: Id? { + switch self { + case let .image(image): + return image.id + case let .file(file): + return file.id + case let .geo(geo): + return geo.id + case let .contact(contact): + return contact.id + case let .action(action): + return action.id + case let .dice(dice): + return dice.id + case let .expiredContent(expiredContent): + return expiredContent.id + case let .game(game): + return game.id + case let .invoice(invoice): + return invoice.id + case let .poll(poll): + return poll.id + case let .unsupported(unsupported): + return unsupported.id + case let .webFile(webFile): + return webFile.id + case let .webpage(webpage): + return webpage.id + } + } +} + public extension EngineMedia { init(_ media: Media) { switch media { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Message.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Message.swift index 736f36eb27..ef74b8b0d0 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Message.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Message.swift @@ -3,6 +3,13 @@ import Postbox public final class EngineMessage { public typealias Id = MessageId public typealias Index = MessageIndex + public typealias Tags = MessageTags + public typealias Attribute = MessageAttribute + public typealias GroupInfo = MessageGroupInfo + public typealias Flags = MessageFlags + public typealias GlobalTags = GlobalMessageTags + public typealias LocalTags = LocalMessageTags + public typealias ForwardInfo = MessageForwardInfo private let impl: Message @@ -23,7 +30,7 @@ public final class EngineMessage { public var groupingKey: Int64? { return self.impl.groupingKey } - public var groupInfo: MessageGroupInfo? { + public var groupInfo: GroupInfo? { return self.impl.groupInfo } public var threadId: Int64? { @@ -32,19 +39,19 @@ public final class EngineMessage { public var timestamp: Int32 { return self.impl.timestamp } - public var flags: MessageFlags { + public var flags: Flags { return self.impl.flags } - public var tags: MessageTags { + public var tags: Tags { return self.impl.tags } - public var globalTags: GlobalMessageTags { + public var globalTags: GlobalTags { return self.impl.globalTags } - public var localTags: LocalMessageTags { + public var localTags: LocalTags { return self.impl.localTags } - public var forwardInfo: MessageForwardInfo? { + public var forwardInfo: ForwardInfo? { return self.impl.forwardInfo } public var author: EnginePeer? { @@ -53,19 +60,19 @@ public final class EngineMessage { public var text: String { return self.impl.text } - public var attributes: [MessageAttribute] { + public var attributes: [Attribute] { return self.impl.attributes } public var media: [Media] { return self.impl.media } - public var peers: SimpleDictionary { + public var peers: SimpleDictionary { return self.impl.peers } - public var associatedMessages: SimpleDictionary { + public var associatedMessages: SimpleDictionary { return self.impl.associatedMessages } - public var associatedMessageIds: [MessageId] { + public var associatedMessageIds: [EngineMessage.Id] { return self.impl.associatedMessageIds } @@ -73,6 +80,62 @@ public final class EngineMessage { return self.impl.index } + public init( + stableId: UInt32, + stableVersion: UInt32, + id: EngineMessage.Id, + globallyUniqueId: Int64?, + groupingKey: Int64?, + groupInfo: EngineMessage.GroupInfo?, + threadId: Int64?, + timestamp: Int32, + flags: EngineMessage.Flags, + tags: EngineMessage.Tags, + globalTags: EngineMessage.GlobalTags, + localTags: EngineMessage.LocalTags, + forwardInfo: EngineMessage.ForwardInfo?, + author: EnginePeer?, + text: String, + attributes: [Attribute], + media: [EngineMedia], + peers: [EnginePeer.Id: EnginePeer], + associatedMessages: [EngineMessage.Id: EngineMessage], + associatedMessageIds: [EngineMessage.Id] + ) { + var mappedPeers: [PeerId: Peer] = [:] + for (id, peer) in peers { + mappedPeers[id] = peer._asPeer() + } + + var mappedAssociatedMessages: [MessageId: Message] = [:] + for (id, message) in associatedMessages { + mappedAssociatedMessages[id] = message._asMessage() + } + + self.impl = Message( + stableId: stableId, + stableVersion: stableVersion, + id: id, + globallyUniqueId: globallyUniqueId, + groupingKey: groupingKey, + groupInfo: groupInfo, + threadId: threadId, + timestamp: timestamp, + flags: flags, + tags: tags, + globalTags: globalTags, + localTags: localTags, + forwardInfo: forwardInfo, + author: author?._asPeer(), + text: text, + attributes: attributes, + media: media.map { $0._asMedia() }, + peers: SimpleDictionary(mappedPeers), + associatedMessages: SimpleDictionary(mappedAssociatedMessages), + associatedMessageIds: associatedMessageIds + ) + } + public init(_ impl: Message) { self.impl = impl } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/ReadState.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/ReadState.swift deleted file mode 100644 index d499b6071b..0000000000 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/ReadState.swift +++ /dev/null @@ -1,23 +0,0 @@ -import Postbox - -public struct EngineReadState: Equatable { - public var unreadCount: Int - public var isMarkedAsUnread: Bool - - public init(unreadCount: Int, isMarkedAsUnread: Bool) { - self.unreadCount = unreadCount - self.isMarkedAsUnread = isMarkedAsUnread - } -} - -public extension EngineReadState { - var isUnread: Bool { - return self.unreadCount != 0 || self.isMarkedAsUnread - } -} - -public extension EngineReadState { - init(_ readState: CombinedPeerReadState) { - self.init(unreadCount: Int(readState.count), isMarkedAsUnread: readState.markedUnread) - } -} diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/Peer.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/Peer.swift index 092be92c31..f96d3d290c 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/Peer.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/Peer.swift @@ -21,6 +21,41 @@ public enum EnginePeer: Equatable { } } + public struct NotificationSettings: Equatable { + public enum MuteState: Equatable { + case `default` + case unmuted + case muted(until: Int32) + } + + public enum MessageSound: Equatable { + case none + case `default` + case bundledModern(id: Int32) + case bundledClassic(id: Int32) + } + + public enum DisplayPreviews { + case `default` + case show + case hide + } + + public var muteState: MuteState + public var messageSound: MessageSound + public var displayPreviews: DisplayPreviews + + public init( + muteState: MuteState, + messageSound: MessageSound, + displayPreviews: DisplayPreviews + ) { + self.muteState = muteState + self.messageSound = messageSound + self.displayPreviews = displayPreviews + } + } + case user(TelegramUser) case legacyGroup(TelegramGroup) case channel(TelegramChannel) @@ -56,6 +91,100 @@ public enum EnginePeer: Equatable { } } +public extension EnginePeer.NotificationSettings.MuteState { + init(_ muteState: PeerMuteState) { + switch muteState { + case .default: + self = .default + case .unmuted: + self = .unmuted + case let .muted(until): + self = .muted(until: until) + } + } + + func _asMuteState() -> PeerMuteState { + switch self { + case .default: + return .default + case .unmuted: + return .unmuted + case let .muted(until): + return .muted(until: until) + } + } +} + +public extension EnginePeer.NotificationSettings.MessageSound { + init(_ messageSound: PeerMessageSound) { + switch messageSound { + case .none: + self = .none + case .default: + self = .default + case let .bundledClassic(id): + self = .bundledClassic(id: id) + case let .bundledModern(id): + self = .bundledModern(id: id) + } + } + + func _asMessageSound() -> PeerMessageSound { + switch self { + case .none: + return .none + case .default: + return .default + case let .bundledClassic(id): + return .bundledClassic(id: id) + case let .bundledModern(id): + return .bundledModern(id: id) + } + } +} + +public extension EnginePeer.NotificationSettings.DisplayPreviews { + init(_ displayPreviews: PeerNotificationDisplayPreviews) { + switch displayPreviews { + case .default: + self = .default + case .show: + self = .show + case .hide: + self = .hide + } + } + + func _asDisplayPreviews() -> PeerNotificationDisplayPreviews { + switch self { + case .default: + return .default + case .show: + return .show + case .hide: + return .hide + } + } +} + +public extension EnginePeer.NotificationSettings { + init(_ notificationSettings: TelegramPeerNotificationSettings) { + self.init( + muteState: MuteState(notificationSettings.muteState), + messageSound: MessageSound(notificationSettings.messageSound), + displayPreviews: DisplayPreviews(notificationSettings.displayPreviews) + ) + } + + func _asNotificationSettings() -> TelegramPeerNotificationSettings { + return TelegramPeerNotificationSettings( + muteState: self.muteState._asMuteState(), + messageSound: self.messageSound._asMessageSound(), + displayPreviews: self.displayPreviews._asDisplayPreviews() + ) + } +} + public extension EnginePeer.Presence { init(_ presence: PeerPresence) { if let presence = presence as? TelegramUserPresence { @@ -174,7 +303,7 @@ public extension EnginePeer { } } -public final class EngineRenderedPeer { +public final class EngineRenderedPeer: Equatable { public let peerId: EnginePeer.Id public let peers: [EnginePeer.Id: EnginePeer] @@ -223,4 +352,8 @@ public extension EngineRenderedPeer { } self.init(peerId: renderedPeer.peerId, peers: mappedPeers) } + + convenience init(message: EngineMessage) { + self.init(RenderedPeer(message: message._asMessage())) + } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift index 8a889a86b7..383837cd3f 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift @@ -98,10 +98,6 @@ public extension TelegramEngine { } } - public func searchPeers(query: String) -> Signal<([FoundPeer], [FoundPeer]), NoError> { - return _internal_searchPeers(account: self.account, query: query) - } - public func updatedRemotePeer(peer: PeerReference) -> Signal { return _internal_updatedRemotePeer(postbox: self.account.postbox, network: self.account.network, peer: peer) } diff --git a/submodules/TelegramUI/BUILD b/submodules/TelegramUI/BUILD index 0fceea4376..44b8ae8584 100644 --- a/submodules/TelegramUI/BUILD +++ b/submodules/TelegramUI/BUILD @@ -231,7 +231,6 @@ swift_library( "//Telegram:GeneratedSources", "//third-party/ZipArchive:ZipArchive", "//submodules/ChatImportUI:ChatImportUI", - "//submodules/ChatHistoryImportTasks:ChatHistoryImportTasks", "//submodules/DatePickerNode:DatePickerNode", "//submodules/ConfettiEffect:ConfettiEffect", "//submodules/Speak:Speak", diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 31277a296d..36cb6e6be9 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -57,7 +57,6 @@ import MediaResources import GalleryData import ChatInterfaceState import InviteLinksUI -import ChatHistoryImportTasks import Markdown import TelegramPermissionsUI import Speak @@ -1868,7 +1867,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let _ = (peerSignal |> deliverOnMainQueue).start(next: { peer in if let strongSelf = self { - let searchController = HashtagSearchController(context: strongSelf.context, peer: peer, query: hashtag) + let searchController = HashtagSearchController(context: strongSelf.context, peer: peer.flatMap(EnginePeer.init), query: hashtag) strongSelf.effectiveNavigationController?.pushViewController(searchController) } }) @@ -4083,22 +4082,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G strongSelf.chatTitleView?.networkState = state } }) - - /*if case let .peer(peerId) = self.chatLocation { - self.importStateDisposable = (ChatHistoryImportTasks.importState(peerId: peerId) - |> distinctUntilChanged - |> deliverOnMainQueue).start(next: { [weak self] state in - guard let strongSelf = self else { - return - } - let mappedState = state.flatMap { state -> ChatPresentationImportState in - ChatPresentationImportState(progress: state) - } - strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { - $0.updatedImportState(mappedState) - }) - }) - }*/ } required public init(coder aDecoder: NSCoder) { @@ -10770,10 +10753,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let resource = LocalFileMediaResource(fileId: randomId) strongSelf.context.account.postbox.mediaBox.storeResourceData(resource.id, data: data.compressedData) - var waveformBuffer: MemoryBuffer? - if let waveform = data.waveform { - waveformBuffer = MemoryBuffer(data: waveform) - } + let waveformBuffer: Data? = data.waveform let correlationId = Int64.random(in: 0 ..< Int64.max) var usedCorrelationId = false @@ -10882,7 +10862,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return } - let waveformBuffer = MemoryBuffer(data: recordedMediaPreview.waveform.makeBitstream()) + let waveformBuffer = recordedMediaPreview.waveform.makeBitstream() self.chatDisplayNode.setupSendActionOnViewUpdate({ [weak self] in if let strongSelf = self { @@ -12042,7 +12022,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.resolvePeerByNameDisposable?.set((resolveSignal |> deliverOnMainQueue).start(next: { [weak self] peer in if let strongSelf = self, !hashtag.isEmpty { - let searchController = HashtagSearchController(context: strongSelf.context, peer: peer, query: hashtag) + let searchController = HashtagSearchController(context: strongSelf.context, peer: peer.flatMap(EnginePeer.init), query: hashtag) strongSelf.effectiveNavigationController?.pushViewController(searchController) } })) diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift index def3923060..1f28aff460 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift @@ -1199,7 +1199,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState subActions.append(.separator) for peer in stats.peers { - let avatarSignal = peerAvatarCompleteImage(account: context.account, peer: peer._asPeer(), size: CGSize(width: 30.0, height: 30.0)) + let avatarSignal = peerAvatarCompleteImage(account: context.account, peer: peer, size: CGSize(width: 30.0, height: 30.0)) subActions.append(.action(ContextMenuActionItem(text: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), textLayout: .singleLine, icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: CGSize(width: 30.0, height: 30.0), signal: avatarSignal), action: { _, f in c.dismiss(completion: { diff --git a/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift b/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift index 5b425f7342..f85158968f 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift @@ -365,9 +365,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode { let durationString = stringForDuration(audioDuration) candidateDescriptionString = NSAttributedString(string: durationString, font: durationFont, textColor: messageTheme.fileDurationColor) if let waveform = waveform { - waveform.withDataNoCopy { data in - audioWaveform = AudioWaveform(bitstream: data, bitsPerSample: 5) - } + audioWaveform = AudioWaveform(bitstream: waveform, bitsPerSample: 5) } } else { candidateTitleString = NSAttributedString(string: title ?? (file.fileName ?? "Unknown Track"), font: titleFont, textColor: messageTheme.fileTitleColor) diff --git a/submodules/TelegramUI/Sources/ChatMessageItemView.swift b/submodules/TelegramUI/Sources/ChatMessageItemView.swift index c6b4eb8854..85a8a34068 100644 --- a/submodules/TelegramUI/Sources/ChatMessageItemView.swift +++ b/submodules/TelegramUI/Sources/ChatMessageItemView.swift @@ -206,7 +206,7 @@ final class ChatMessageAccessibilityData { if let chatPeer = message.peers[item.message.id.peerId] { let authorName = message.author.flatMap(EnginePeer.init)?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) - let (_, _, messageText) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: [message], chatPeer: RenderedPeer(peer: chatPeer), accountPeerId: item.context.account.peerId) + let (_, _, messageText) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: [EngineMessage(message)], chatPeer: EngineRenderedPeer(peer: EnginePeer(chatPeer)), accountPeerId: item.context.account.peerId) var text = messageText diff --git a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift index 06ab336719..d4d72c4192 100644 --- a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift @@ -288,7 +288,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { strongSelf.resolvePeerByNameDisposable.set((resolveSignal |> deliverOnMainQueue).start(next: { peer in if let strongSelf = self, !hashtag.isEmpty { - let searchController = HashtagSearchController(context: strongSelf.context, peer: peer, query: hashtag) + let searchController = HashtagSearchController(context: strongSelf.context, peer: peer.flatMap(EnginePeer.init), query: hashtag) strongSelf.pushController(searchController) } })) @@ -437,7 +437,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogOpen, color: .accent, action: { [weak actionSheet] in actionSheet?.dismissAnimated() if let strongSelf = self { - let searchController = HashtagSearchController(context: strongSelf.context, peer: strongSelf.peer, query: hashtag) + let searchController = HashtagSearchController(context: strongSelf.context, peer: EnginePeer(strongSelf.peer), query: hashtag) strongSelf.pushController(searchController) } }), diff --git a/submodules/TelegramUI/Sources/ChatSearchResultsContollerNode.swift b/submodules/TelegramUI/Sources/ChatSearchResultsContollerNode.swift index 781e849d67..0dc977c6ab 100644 --- a/submodules/TelegramUI/Sources/ChatSearchResultsContollerNode.swift +++ b/submodules/TelegramUI/Sources/ChatSearchResultsContollerNode.swift @@ -77,7 +77,34 @@ private enum ChatListSearchEntry: Comparable, Identifiable { public func item(context: AccountContext, interaction: ChatListNodeInteraction) -> ListViewItem { switch self { case let .message(message, peer, readState, presentationData): - return ChatListItem(presentationData: presentationData, context: context, peerGroupId: .root, filterData: nil, index: ChatListIndex(pinningIndex: nil, messageIndex: message.index), content: .peer(messages: [message], peer: peer, combinedReadState: readState, isRemovedFromTotalUnreadCount: false, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(), embeddedState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: true, displayAsMessage: true, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction) + return ChatListItem( + presentationData: presentationData, + context: context, + peerGroupId: .root, + filterData: nil, + index: EngineChatList.Item.Index(pinningIndex: nil, messageIndex: message.index), + content: .peer( + messages: [EngineMessage(message)], + peer: EngineRenderedPeer(peer), + combinedReadState: readState.flatMap(EnginePeerReadCounters.init), + isRemovedFromTotalUnreadCount: false, + presence: nil, + hasUnseenMentions: false, + draftState: nil, + inputActivities: nil, + promoInfo: nil, + ignoreUnreadBadge: true, + displayAsMessage: true, + hasFailedMessages: false + ), + editing: false, + hasActiveRevealControls: false, + selected: false, + header: nil, + enableContextActions: false, + hiddenOffset: false, + interaction: interaction + ) } } } diff --git a/submodules/TelegramUI/Sources/ContactMultiselectionControllerNode.swift b/submodules/TelegramUI/Sources/ContactMultiselectionControllerNode.swift index d3478269ec..7abd457a62 100644 --- a/submodules/TelegramUI/Sources/ContactMultiselectionControllerNode.swift +++ b/submodules/TelegramUI/Sources/ContactMultiselectionControllerNode.swift @@ -129,7 +129,7 @@ final class ContactMultiselectionControllerNode: ASDisplayNode { } case let .chats(chatsNode): chatsNode.peerSelected = { [weak self] peer, _, _, _ in - self?.openPeer?(.peer(peer: peer, isGlobal: false, participantCount: nil)) + self?.openPeer?(.peer(peer: peer._asPeer(), isGlobal: false, participantCount: nil)) } chatsNode.additionalCategorySelected = { [weak self] id in guard let strongSelf = self else { diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 5d7c16feb0..f33d67ef08 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -3330,7 +3330,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD self.resolvePeerByNameDisposable?.set((resolveSignal |> deliverOnMainQueue).start(next: { [weak self] peer in if let strongSelf = self, !hashtag.isEmpty { - let searchController = HashtagSearchController(context: strongSelf.context, peer: peer, query: hashtag) + let searchController = HashtagSearchController(context: strongSelf.context, peer: peer.flatMap(EnginePeer.init), query: hashtag) strongSelf.controller?.push(searchController) } })) @@ -4388,7 +4388,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } if let peer = selectedPeer { let avatarSize = CGSize(width: 28.0, height: 28.0) - items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_DisplayAs, textLayout: .secondLineWithValue(EnginePeer(peer.peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)), icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: peerAvatarCompleteImage(account: strongSelf.context.account, peer: peer.peer, size: avatarSize)), action: { c, f in + items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_DisplayAs, textLayout: .secondLineWithValue(EnginePeer(peer.peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)), icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: peerAvatarCompleteImage(account: strongSelf.context.account, peer: EnginePeer(peer.peer), size: avatarSize)), action: { c, f in guard let strongSelf = self else { return } @@ -4500,7 +4500,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } let avatarSize = CGSize(width: 28.0, height: 28.0) - let avatarSignal = peerAvatarCompleteImage(account: strongSelf.context.account, peer: peer.peer, size: avatarSize) + let avatarSignal = peerAvatarCompleteImage(account: strongSelf.context.account, peer: EnginePeer(peer.peer), size: avatarSize) items.append(.action(ContextMenuActionItem(text: EnginePeer(peer.peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), textLayout: subtitle.flatMap { .secondLineWithValue($0) } ?? .singleLine, icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: avatarSignal), action: { _, f in if dismissOnSelection { f(.dismissWithoutContent) @@ -6885,7 +6885,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen { let avatarSize = CGSize(width: 28.0, height: 28.0) - items.append(.action(ContextMenuActionItem(text: primary.1.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder), icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: peerAvatarCompleteImage(account: primary.0.account, peer: primary.1._asPeer(), size: avatarSize)), action: { _, f in + items.append(.action(ContextMenuActionItem(text: primary.1.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder), icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: peerAvatarCompleteImage(account: primary.0.account, peer: primary.1, size: avatarSize)), action: { _, f in f(.default) }))) @@ -6895,7 +6895,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen { for account in other { let id = account.0.account.id - items.append(.action(ContextMenuActionItem(text: account.1.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder), badge: account.2 != 0 ? ContextMenuActionBadge(value: "\(account.2)", color: .accent) : nil, icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: peerAvatarCompleteImage(account: account.0.account, peer: account.1._asPeer(), size: avatarSize)), action: { [weak self] _, f in + items.append(.action(ContextMenuActionItem(text: account.1.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder), badge: account.2 != 0 ? ContextMenuActionBadge(value: "\(account.2)", color: .accent) : nil, icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: peerAvatarCompleteImage(account: account.0.account, peer: account.1, size: avatarSize)), action: { [weak self] _, f in guard let strongSelf = self else { return } diff --git a/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift b/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift index f738c6c8a7..a3a014ab05 100644 --- a/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift +++ b/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift @@ -141,11 +141,11 @@ final class PeerSelectionControllerNode: ASDisplayNode { self.chatListNode.peerSelected = { [weak self] peer, _, _, _ in self?.chatListNode.clearHighlightAnimated(true) - self?.requestOpenPeer?(peer) + self?.requestOpenPeer?(peer._asPeer()) } self.chatListNode.disabledPeerSelected = { [weak self] peer in - self?.requestOpenDisabledPeer?(peer) + self?.requestOpenDisabledPeer?(peer._asPeer()) } self.chatListNode.contentOffsetChanged = { [weak self] offset in @@ -367,7 +367,7 @@ final class PeerSelectionControllerNode: ASDisplayNode { var selectedPeerMap: [PeerId: Peer] = [:] strongSelf.chatListNode.updateState { state in selectedPeerIds = Array(state.selectedPeerIds) - selectedPeerMap = state.selectedPeerMap + selectedPeerMap = state.selectedPeerMap.mapValues({ $0._asPeer() }) return state } if !selectedPeerIds.isEmpty { @@ -518,66 +518,84 @@ final class PeerSelectionControllerNode: ASDisplayNode { } if self.chatListNode.supernode != nil { - self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, contentNode: ChatListSearchContainerNode(context: self.context, updatedPresentationData: self.updatedPresentationData, filter: self.filter, groupId: .root, displaySearchFilters: false, openPeer: { [weak self] peer, chatPeer, _ in - guard let strongSelf = self else { - return - } - var updated = false - var count = 0 - strongSelf.chatListNode.updateState { state in - if state.editing { - updated = true - var state = state - var foundPeers = state.foundPeers - var selectedPeerMap = state.selectedPeerMap - selectedPeerMap[peer.id] = peer - if peer is TelegramSecretChat, let chatPeer = chatPeer { - selectedPeerMap[chatPeer.id] = chatPeer + self.searchDisplayController = SearchDisplayController( + presentationData: self.presentationData, + contentNode: ChatListSearchContainerNode( + context: self.context, + updatedPresentationData: self.updatedPresentationData, + filter: self.filter, + groupId: EngineChatList.Group(.root), + displaySearchFilters: false, + openPeer: { [weak self] peer, chatPeer, _ in + guard let strongSelf = self else { + return } - var exists = false - for foundPeer in foundPeers { - if peer.id == foundPeer.0.id { - exists = true - break + var updated = false + var count = 0 + strongSelf.chatListNode.updateState { state in + if state.editing { + updated = true + var state = state + var foundPeers = state.foundPeers + var selectedPeerMap = state.selectedPeerMap + selectedPeerMap[peer.id] = peer + if case .secretChat = peer, let chatPeer = chatPeer { + selectedPeerMap[chatPeer.id] = chatPeer + } + var exists = false + for foundPeer in foundPeers { + if peer.id == foundPeer.0.id { + exists = true + break + } + } + if !exists { + foundPeers.insert((peer, chatPeer), at: 0) + } + if state.selectedPeerIds.contains(peer.id) { + state.selectedPeerIds.remove(peer.id) + } else { + state.selectedPeerIds.insert(peer.id) + } + state.foundPeers = foundPeers + state.selectedPeerMap = selectedPeerMap + count = state.selectedPeerIds.count + return state + } else { + return state } } - if !exists { - foundPeers.insert((peer, chatPeer), at: 0) + if updated { + strongSelf.textInputPanelNode?.updateSendButtonEnabled(count > 0, animated: true) + strongSelf.requestDeactivateSearch?() + } else if let requestOpenPeerFromSearch = strongSelf.requestOpenPeerFromSearch { + requestOpenPeerFromSearch(peer._asPeer()) } - if state.selectedPeerIds.contains(peer.id) { - state.selectedPeerIds.remove(peer.id) - } else { - state.selectedPeerIds.insert(peer.id) + }, + openDisabledPeer: { [weak self] peer in + self?.requestOpenDisabledPeer?(peer._asPeer()) + }, + openRecentPeerOptions: { _ in + }, + openMessage: { [weak self] peer, messageId, _ in + if let requestOpenMessageFromSearch = self?.requestOpenMessageFromSearch { + requestOpenMessageFromSearch(peer._asPeer(), messageId) } - state.foundPeers = foundPeers - state.selectedPeerMap = selectedPeerMap - count = state.selectedPeerIds.count - return state - } else { - return state + }, + addContact: nil, + peerContextAction: nil, + present: { [weak self] c, a in + self?.present(c, a) + }, + presentInGlobalOverlay: { _, _ in + }, + navigationController: nil + ), cancel: { [weak self] in + if let requestDeactivateSearch = self?.requestDeactivateSearch { + requestDeactivateSearch() } } - if updated { - strongSelf.textInputPanelNode?.updateSendButtonEnabled(count > 0, animated: true) - strongSelf.requestDeactivateSearch?() - } else if let requestOpenPeerFromSearch = strongSelf.requestOpenPeerFromSearch { - requestOpenPeerFromSearch(peer) - } - }, openDisabledPeer: { [weak self] peer in - self?.requestOpenDisabledPeer?(peer) - }, openRecentPeerOptions: { _ in - }, openMessage: { [weak self] peer, messageId, _ in - if let requestOpenMessageFromSearch = self?.requestOpenMessageFromSearch { - requestOpenMessageFromSearch(peer, messageId) - } - }, addContact: nil, peerContextAction: nil, present: { [weak self] c, a in - self?.present(c, a) - }, presentInGlobalOverlay: { _, _ in - }, navigationController: nil), cancel: { [weak self] in - if let requestDeactivateSearch = self?.requestDeactivateSearch { - requestDeactivateSearch() - } - }) + ) self.searchDisplayController?.containerLayoutUpdated(containerLayout, navigationBarHeight: navigationBarHeight, transition: .immediate) self.searchDisplayController?.activate(insertSubnode: { [weak self, weak placeholderNode] subnode, isSearchBar in diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index 9b79c3e0ea..25fe6ff699 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -1118,12 +1118,12 @@ public final class SharedAccountContextImpl: SharedAccountContext { openExternalUrlImpl(context: context, urlContext: urlContext, url: url, forceExternal: forceExternal, presentationData: presentationData, navigationController: navigationController, dismissInput: dismissInput) } - public func chatAvailableMessageActions(postbox: Postbox, accountPeerId: PeerId, messageIds: Set) -> Signal { + public func chatAvailableMessageActions(postbox: Postbox, accountPeerId: EnginePeer.Id, messageIds: Set) -> Signal { return chatAvailableMessageActionsImpl(postbox: postbox, accountPeerId: accountPeerId, messageIds: messageIds) } - public func chatAvailableMessageActions(postbox: Postbox, accountPeerId: PeerId, messageIds: Set, messages: [MessageId: Message] = [:], peers: [PeerId: Peer] = [:]) -> Signal { - return chatAvailableMessageActionsImpl(postbox: postbox, accountPeerId: accountPeerId, messageIds: messageIds, messages: messages, peers: peers) + public func chatAvailableMessageActions(postbox: Postbox, accountPeerId: EnginePeer.Id, messageIds: Set, messages: [EngineMessage.Id: EngineMessage] = [:], peers: [EnginePeer.Id: EnginePeer] = [:]) -> Signal { + return chatAvailableMessageActionsImpl(postbox: postbox, accountPeerId: accountPeerId, messageIds: messageIds, messages: messages.mapValues({ $0._asMessage() }), peers: peers.mapValues({ $0._asPeer() })) } public func navigateToChatController(_ params: NavigateToChatControllerParams) { diff --git a/submodules/TelegramUI/Sources/TextLinkHandling.swift b/submodules/TelegramUI/Sources/TextLinkHandling.swift index b5aa28163e..16b27e0d1d 100644 --- a/submodules/TelegramUI/Sources/TextLinkHandling.swift +++ b/submodules/TelegramUI/Sources/TextLinkHandling.swift @@ -126,7 +126,7 @@ func handleTextLinkActionImpl(context: AccountContext, peerId: PeerId?, navigate let peerSignal = context.account.postbox.loadedPeerWithId(peerId) let _ = (peerSignal |> deliverOnMainQueue).start(next: { peer in - let searchController = HashtagSearchController(context: context, peer: peer, query: hashtag) + let searchController = HashtagSearchController(context: context, peer: EnginePeer(peer), query: hashtag) (controller.navigationController as? NavigationController)?.pushViewController(searchController) }) }