mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-08 08:31:13 +00:00
Display text selection tip in message context menu
This commit is contained in:
parent
f1f4827f95
commit
bc9b0785f1
@ -37,7 +37,7 @@ func unreadMessages(account: Account) -> Signal<[INMessage], NoError> {
|
|||||||
|> mapToSignal { view -> Signal<[INMessage], NoError> in
|
|> mapToSignal { view -> Signal<[INMessage], NoError> in
|
||||||
var signals: [Signal<[INMessage], NoError>] = []
|
var signals: [Signal<[INMessage], NoError>] = []
|
||||||
for entry in view.0.entries {
|
for entry in view.0.entries {
|
||||||
if case let .MessageEntry(index, _, readState, notificationSettings, _, _, _, _) = entry {
|
if case let .MessageEntry(index, _, readState, notificationSettings, _, _, _, _, _) = entry {
|
||||||
if index.messageIndex.id.peerId.namespace != Namespaces.Peer.CloudUser {
|
if index.messageIndex.id.peerId.namespace != Namespaces.Peer.CloudUser {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -5169,3 +5169,5 @@ Any member of this group will be able to see messages in the channel.";
|
|||||||
"AuthSessions.OtherDevices" = "The official Telegram App is available for iPhone, iPad, Android, macOS, Windows and Linux. [Learn More]()";
|
"AuthSessions.OtherDevices" = "The official Telegram App is available for iPhone, iPad, Android, macOS, Windows and Linux. [Learn More]()";
|
||||||
|
|
||||||
"AuthSessions.AddDevice.UrlLoginHint" = "This code can be used to allow someone to log in to your Telegram account.\n\nTo confirm Telegram login, please go to Settings > Devices > Scan QR and scan the code.";
|
"AuthSessions.AddDevice.UrlLoginHint" = "This code can be used to allow someone to log in to your Telegram account.\n\nTo confirm Telegram login, please go to Settings > Devices > Scan QR and scan the code.";
|
||||||
|
|
||||||
|
"ChatContextMenu.TextSelectionTip" = "Hold a word, then move cursor to select more| text to copy.";
|
||||||
|
@ -1053,7 +1053,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
|||||||
var sourceRect = selectedNode.view.superview!.convert(selectedNode.frame, to: sourceView)
|
var sourceRect = selectedNode.view.superview!.convert(selectedNode.frame, to: sourceView)
|
||||||
sourceRect.size.height -= UIScreenPixel
|
sourceRect.size.height -= UIScreenPixel
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .peer(_, peer, _, _, _, _, _, _, _, _, _):
|
case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _):
|
||||||
if peer.peerId.namespace != Namespaces.Peer.SecretChat {
|
if peer.peerId.namespace != Namespaces.Peer.SecretChat {
|
||||||
let chatController = self.context.sharedContext.makeChatController(context: self.context, chatLocation: .peer(peer.peerId), subject: nil, botStart: nil, mode: .standard(previewing: true))
|
let chatController = self.context.sharedContext.makeChatController(context: self.context, chatLocation: .peer(peer.peerId), subject: nil, botStart: nil, mode: .standard(previewing: true))
|
||||||
chatController.canReadHistory.set(false)
|
chatController.canReadHistory.set(false)
|
||||||
|
@ -444,7 +444,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
case let .message(message, peer, readState, presentationData):
|
case let .message(message, peer, readState, presentationData):
|
||||||
return ChatListItem(presentationData: presentationData, context: context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: message.index), content: .peer(message: message, peer: peer, combinedReadState: readState, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: true, displayAsMessage: false), editing: false, hasActiveRevealControls: false, selected: false, header: enableHeaders ? ChatListSearchItemHeader(type: .messages, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil) : nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
|
return ChatListItem(presentationData: presentationData, context: context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: message.index), content: .peer(message: message, peer: peer, combinedReadState: readState, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: true, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: enableHeaders ? ChatListSearchItemHeader(type: .messages, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil) : nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
|
||||||
case let .addContact(phoneNumber, theme, strings):
|
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: {
|
return ContactsAddItem(theme: theme, strings: strings, phoneNumber: phoneNumber, header: ChatListSearchItemHeader(type: .phoneNumber, theme: theme, strings: strings, actionTitle: nil, action: nil), action: {
|
||||||
interaction.addContact(phoneNumber)
|
interaction.addContact(phoneNumber)
|
||||||
@ -1213,7 +1213,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||||||
bounds = selectedItemNode.bounds
|
bounds = selectedItemNode.bounds
|
||||||
}
|
}
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .peer(message, peer, _, _, _, _, _, _, _, _, _):
|
case let .peer(message, peer, _, _, _, _, _, _, _, _, _, _):
|
||||||
return (selectedItemNode.view, bounds, message?.id ?? peer.peerId)
|
return (selectedItemNode.view, bounds, message?.id ?? peer.peerId)
|
||||||
case let .groupReference(groupId, _, _, _, _):
|
case let .groupReference(groupId, _, _, _, _):
|
||||||
return (selectedItemNode.view, bounds, groupId)
|
return (selectedItemNode.view, bounds, groupId)
|
||||||
|
@ -20,12 +20,12 @@ import ChatListSearchItemNode
|
|||||||
import ContextUI
|
import ContextUI
|
||||||
|
|
||||||
public enum ChatListItemContent {
|
public enum ChatListItemContent {
|
||||||
case peer(message: Message?, peer: RenderedPeer, combinedReadState: CombinedPeerReadState?, notificationSettings: PeerNotificationSettings?, presence: PeerPresence?, summaryInfo: ChatListMessageTagSummaryInfo, embeddedState: PeerChatListEmbeddedInterfaceState?, inputActivities: [(Peer, PeerInputActivity)]?, isAd: Bool, ignoreUnreadBadge: Bool, displayAsMessage: Bool)
|
case peer(message: Message?, peer: RenderedPeer, combinedReadState: CombinedPeerReadState?, notificationSettings: PeerNotificationSettings?, presence: PeerPresence?, summaryInfo: ChatListMessageTagSummaryInfo, embeddedState: PeerChatListEmbeddedInterfaceState?, inputActivities: [(Peer, PeerInputActivity)]?, isAd: Bool, ignoreUnreadBadge: Bool, displayAsMessage: Bool, hasFailedMessages: Bool)
|
||||||
case groupReference(groupId: PeerGroupId, peers: [ChatListGroupReferencePeer], message: Message?, unreadState: PeerGroupUnreadCountersCombinedSummary, hiddenByDefault: Bool)
|
case groupReference(groupId: PeerGroupId, peers: [ChatListGroupReferencePeer], message: Message?, unreadState: PeerGroupUnreadCountersCombinedSummary, hiddenByDefault: Bool)
|
||||||
|
|
||||||
public var chatLocation: ChatLocation? {
|
public var chatLocation: ChatLocation? {
|
||||||
switch self {
|
switch self {
|
||||||
case let .peer(_, peer, _, _, _, _, _, _, _, _, _):
|
case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _):
|
||||||
return .peer(peer.peerId)
|
return .peer(peer.peerId)
|
||||||
case .groupReference:
|
case .groupReference:
|
||||||
return nil
|
return nil
|
||||||
@ -38,7 +38,7 @@ public class ChatListItem: ListViewItem, ChatListSearchItemNeighbour {
|
|||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
let peerGroupId: PeerGroupId
|
let peerGroupId: PeerGroupId
|
||||||
let index: ChatListIndex
|
let index: ChatListIndex
|
||||||
let content: ChatListItemContent
|
public let content: ChatListItemContent
|
||||||
let editing: Bool
|
let editing: Bool
|
||||||
let hasActiveRevealControls: Bool
|
let hasActiveRevealControls: Bool
|
||||||
let selected: Bool
|
let selected: Bool
|
||||||
@ -122,7 +122,7 @@ public class ChatListItem: ListViewItem, ChatListSearchItemNeighbour {
|
|||||||
|
|
||||||
public func selected(listView: ListView) {
|
public func selected(listView: ListView) {
|
||||||
switch self.content {
|
switch self.content {
|
||||||
case let .peer(message, peer, _, _, _, _, _, _, isAd, _, _):
|
case let .peer(message, peer, _, _, _, _, _, _, isAd, _, _, _):
|
||||||
if let message = message, let peer = peer.peer {
|
if let message = message, let peer = peer.peer {
|
||||||
self.interaction.messageSelected(peer, message, isAd)
|
self.interaction.messageSelected(peer, message, isAd)
|
||||||
} else if let peer = peer.peer {
|
} else if let peer = peer.peer {
|
||||||
@ -522,7 +522,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
var displayAsMessage = false
|
var displayAsMessage = false
|
||||||
var enablePreview = true
|
var enablePreview = true
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .peer(message, peerValue, _, _, _, _, _, _, _, _, displayAsMessageValue):
|
case let .peer(message, peerValue, _, _, _, _, _, _, _, _, displayAsMessageValue, _):
|
||||||
displayAsMessage = displayAsMessageValue
|
displayAsMessage = displayAsMessageValue
|
||||||
if displayAsMessage, let author = message?.author as? TelegramUser {
|
if displayAsMessage, let author = message?.author as? TelegramUser {
|
||||||
peer = author
|
peer = author
|
||||||
@ -673,11 +673,12 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
let isPeerGroup: Bool
|
let isPeerGroup: Bool
|
||||||
let isAd: Bool
|
let isAd: Bool
|
||||||
let displayAsMessage: Bool
|
let displayAsMessage: Bool
|
||||||
|
let hasFailedMessages: Bool
|
||||||
|
|
||||||
var groupHiddenByDefault = false
|
var groupHiddenByDefault = false
|
||||||
|
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .peer(messageValue, peerValue, combinedReadStateValue, notificationSettingsValue, peerPresenceValue, summaryInfoValue, embeddedStateValue, inputActivitiesValue, isAdValue, ignoreUnreadBadge, displayAsMessageValue):
|
case let .peer(messageValue, peerValue, combinedReadStateValue, notificationSettingsValue, peerPresenceValue, summaryInfoValue, embeddedStateValue, inputActivitiesValue, isAdValue, ignoreUnreadBadge, displayAsMessageValue, hasFailedMessagesValue):
|
||||||
message = messageValue
|
message = messageValue
|
||||||
contentPeer = .chat(peerValue)
|
contentPeer = .chat(peerValue)
|
||||||
combinedReadState = combinedReadStateValue
|
combinedReadState = combinedReadStateValue
|
||||||
@ -698,6 +699,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
isPeerGroup = false
|
isPeerGroup = false
|
||||||
isAd = isAdValue
|
isAd = isAdValue
|
||||||
displayAsMessage = displayAsMessageValue
|
displayAsMessage = displayAsMessageValue
|
||||||
|
hasFailedMessages = hasFailedMessagesValue
|
||||||
case let .groupReference(_, peers, messageValue, unreadState, hiddenByDefault):
|
case let .groupReference(_, peers, messageValue, unreadState, hiddenByDefault):
|
||||||
if let _ = messageValue, !peers.isEmpty {
|
if let _ = messageValue, !peers.isEmpty {
|
||||||
contentPeer = .chat(peers[0].peer)
|
contentPeer = .chat(peers[0].peer)
|
||||||
@ -717,6 +719,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
peerPresence = nil
|
peerPresence = nil
|
||||||
isAd = false
|
isAd = false
|
||||||
displayAsMessage = false
|
displayAsMessage = false
|
||||||
|
hasFailedMessages = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if let messageValue = message {
|
if let messageValue = message {
|
||||||
@ -975,7 +978,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
if message.flags.isSending && !message.isSentOrAcknowledged {
|
if message.flags.isSending && !message.isSentOrAcknowledged {
|
||||||
statusState = .clock(PresentationResourcesChatList.clockFrameImage(item.presentationData.theme), PresentationResourcesChatList.clockMinImage(item.presentationData.theme))
|
statusState = .clock(PresentationResourcesChatList.clockFrameImage(item.presentationData.theme), PresentationResourcesChatList.clockMinImage(item.presentationData.theme))
|
||||||
} else if message.id.peerId != account.peerId {
|
} else if message.id.peerId != account.peerId {
|
||||||
if message.flags.contains(.Failed) {
|
if hasFailedMessages {
|
||||||
statusState = .failed(item.presentationData.theme.chatList.failedFillColor, item.presentationData.theme.chatList.failedForegroundColor)
|
statusState = .failed(item.presentationData.theme.chatList.failedFillColor, item.presentationData.theme.chatList.failedForegroundColor)
|
||||||
} else {
|
} else {
|
||||||
if let combinedReadState = combinedReadState, combinedReadState.isOutgoingMessageIndexRead(message.index) {
|
if let combinedReadState = combinedReadState, combinedReadState.isOutgoingMessageIndexRead(message.index) {
|
||||||
@ -1061,7 +1064,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
var credibilityIconOffset: CGFloat = 0.0
|
var credibilityIconOffset: CGFloat = 0.0
|
||||||
if displayAsMessage {
|
if displayAsMessage {
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .peer(message, _, _, _, _, _, _, _, _, _, _):
|
case let .peer(message, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
if let peer = message?.author {
|
if let peer = message?.author {
|
||||||
if peer.isScam {
|
if peer.isScam {
|
||||||
currentCredibilityIconImage = PresentationResourcesChatList.scamIcon(item.presentationData.theme, type: .regular)
|
currentCredibilityIconImage = PresentationResourcesChatList.scamIcon(item.presentationData.theme, type: .regular)
|
||||||
@ -1153,7 +1156,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
let peerRevealOptions: [ItemListRevealOption]
|
let peerRevealOptions: [ItemListRevealOption]
|
||||||
let peerLeftRevealOptions: [ItemListRevealOption]
|
let peerLeftRevealOptions: [ItemListRevealOption]
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .peer(_, renderedPeer, _, _, presence, _ ,_ ,_, _, _, displayAsMessage):
|
case let .peer(_, renderedPeer, _, _, presence, _ ,_ ,_, _, _, displayAsMessage, _):
|
||||||
if !displayAsMessage, let peer = renderedPeer.peer as? TelegramUser, let presence = presence as? TelegramUserPresence, !isServicePeer(peer) && !peer.flags.contains(.isSupport) && peer.id != item.context.account.peerId {
|
if !displayAsMessage, let peer = renderedPeer.peer as? TelegramUser, let presence = presence as? TelegramUserPresence, !isServicePeer(peer) && !peer.flags.contains(.isSupport) && peer.id != item.context.account.peerId {
|
||||||
let relativeStatus = relativeUserPresenceStatus(presence, relativeTo: timestamp)
|
let relativeStatus = relativeUserPresenceStatus(presence, relativeTo: timestamp)
|
||||||
if case .online = relativeStatus {
|
if case .online = relativeStatus {
|
||||||
|
@ -141,10 +141,10 @@ public struct ChatListNodeState: Equatable {
|
|||||||
private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: PeerGroupId, mode: ChatListNodeMode, entries: [ChatListNodeViewTransitionInsertEntry]) -> [ListViewInsertItem] {
|
private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: PeerGroupId, mode: ChatListNodeMode, entries: [ChatListNodeViewTransitionInsertEntry]) -> [ListViewInsertItem] {
|
||||||
return entries.map { entry -> ListViewInsertItem in
|
return entries.map { entry -> ListViewInsertItem in
|
||||||
switch entry.entry {
|
switch entry.entry {
|
||||||
case let .PeerEntry(index, presentationData, message, combinedReadState, notificationSettings, embeddedState, peer, presence, summaryInfo, editing, hasActiveRevealControls, selected, inputActivities, isAd):
|
case let .PeerEntry(index, presentationData, message, combinedReadState, notificationSettings, embeddedState, peer, presence, summaryInfo, editing, hasActiveRevealControls, selected, inputActivities, isAd, hasFailedMessages):
|
||||||
switch mode {
|
switch mode {
|
||||||
case .chatList:
|
case .chatList:
|
||||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(presentationData: presentationData, context: context, peerGroupId: peerGroupId, index: index, content: .peer(message: message, peer: peer, combinedReadState: combinedReadState, notificationSettings: notificationSettings, presence: presence, summaryInfo: summaryInfo, embeddedState: embeddedState, inputActivities: inputActivities, isAd: isAd, ignoreUnreadBadge: false, displayAsMessage: false), 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, index: index, content: .peer(message: message, peer: peer, combinedReadState: combinedReadState, notificationSettings: notificationSettings, presence: presence, summaryInfo: summaryInfo, embeddedState: embeddedState, inputActivities: inputActivities, isAd: isAd, 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):
|
case let .peers(filter):
|
||||||
let itemPeer = peer.chatMainPeer
|
let itemPeer = peer.chatMainPeer
|
||||||
var chatPeer: Peer?
|
var chatPeer: Peer?
|
||||||
@ -222,10 +222,10 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: PeerGroupId, mode: ChatListNodeMode, entries: [ChatListNodeViewTransitionUpdateEntry]) -> [ListViewUpdateItem] {
|
private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: PeerGroupId, mode: ChatListNodeMode, entries: [ChatListNodeViewTransitionUpdateEntry]) -> [ListViewUpdateItem] {
|
||||||
return entries.map { entry -> ListViewUpdateItem in
|
return entries.map { entry -> ListViewUpdateItem in
|
||||||
switch entry.entry {
|
switch entry.entry {
|
||||||
case let .PeerEntry(index, presentationData, message, combinedReadState, notificationSettings, embeddedState, peer, presence, summaryInfo, editing, hasActiveRevealControls, selected, inputActivities, isAd):
|
case let .PeerEntry(index, presentationData, message, combinedReadState, notificationSettings, embeddedState, peer, presence, summaryInfo, editing, hasActiveRevealControls, selected, inputActivities, isAd, hasFailedMessages):
|
||||||
switch mode {
|
switch mode {
|
||||||
case .chatList:
|
case .chatList:
|
||||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(presentationData: presentationData, context: context, peerGroupId: peerGroupId, index: index, content: .peer(message: message, peer: peer, combinedReadState: combinedReadState, notificationSettings: notificationSettings, presence: presence, summaryInfo: summaryInfo, embeddedState: embeddedState, inputActivities: inputActivities, isAd: isAd, ignoreUnreadBadge: false, displayAsMessage: false), 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, index: index, content: .peer(message: message, peer: peer, combinedReadState: combinedReadState, notificationSettings: notificationSettings, presence: presence, summaryInfo: summaryInfo, embeddedState: embeddedState, inputActivities: inputActivities, isAd: isAd, 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):
|
case let .peers(filter):
|
||||||
let itemPeer = peer.chatMainPeer
|
let itemPeer = peer.chatMainPeer
|
||||||
var chatPeer: Peer?
|
var chatPeer: Peer?
|
||||||
@ -549,7 +549,7 @@ public final class ChatListNode: ListView {
|
|||||||
let (rawEntries, isLoading) = chatListNodeEntriesForView(update.view, state: state, savedMessagesPeer: savedMessagesPeer, hideArchivedFolderByDefault: hideArchivedFolderByDefault, displayArchiveIntro: displayArchiveIntro, mode: mode)
|
let (rawEntries, isLoading) = chatListNodeEntriesForView(update.view, state: state, savedMessagesPeer: savedMessagesPeer, hideArchivedFolderByDefault: hideArchivedFolderByDefault, displayArchiveIntro: displayArchiveIntro, mode: mode)
|
||||||
let entries = rawEntries.filter { entry in
|
let entries = rawEntries.filter { entry in
|
||||||
switch entry {
|
switch entry {
|
||||||
case let .PeerEntry(_, _, _, _, _, _, peer, _, _, _, _, _, _, _):
|
case let .PeerEntry(_, _, _, _, _, _, peer, _, _, _, _, _, _, _, _):
|
||||||
switch mode {
|
switch mode {
|
||||||
case .chatList:
|
case .chatList:
|
||||||
return true
|
return true
|
||||||
@ -654,7 +654,7 @@ public final class ChatListNode: ListView {
|
|||||||
var didIncludeHiddenByDefaultArchive = false
|
var didIncludeHiddenByDefaultArchive = false
|
||||||
if let previous = previousView {
|
if let previous = previousView {
|
||||||
for entry in previous.filteredEntries {
|
for entry in previous.filteredEntries {
|
||||||
if case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _) = entry {
|
if case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _) = entry {
|
||||||
if index.pinningIndex != nil {
|
if index.pinningIndex != nil {
|
||||||
previousPinnedChats.append(index.messageIndex.id.peerId)
|
previousPinnedChats.append(index.messageIndex.id.peerId)
|
||||||
}
|
}
|
||||||
@ -670,11 +670,11 @@ public final class ChatListNode: ListView {
|
|||||||
var doesIncludeArchive = false
|
var doesIncludeArchive = false
|
||||||
var doesIncludeHiddenByDefaultArchive = false
|
var doesIncludeHiddenByDefaultArchive = false
|
||||||
for entry in processedView.filteredEntries {
|
for entry in processedView.filteredEntries {
|
||||||
if case let .PeerEntry(index, _, _, _, _, _, _, _, _ , _, _, _, _, _) = entry {
|
if case let .PeerEntry(peerEntry) = entry {
|
||||||
if index.pinningIndex != nil {
|
if peerEntry.index.pinningIndex != nil {
|
||||||
updatedPinnedChats.append(index.messageIndex.id.peerId)
|
updatedPinnedChats.append(peerEntry.index.messageIndex.id.peerId)
|
||||||
}
|
}
|
||||||
if index.messageIndex.id.peerId == removingPeerId {
|
if peerEntry.index.messageIndex.id.peerId == removingPeerId {
|
||||||
doesIncludeRemovingPeerId = true
|
doesIncludeRemovingPeerId = true
|
||||||
}
|
}
|
||||||
} else if case let .GroupReferenceEntry(entry) = entry {
|
} else if case let .GroupReferenceEntry(entry) = entry {
|
||||||
@ -749,7 +749,7 @@ public final class ChatListNode: ListView {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
switch chatListView.filteredEntries[entryCount - i - 1] {
|
switch chatListView.filteredEntries[entryCount - i - 1] {
|
||||||
case let .PeerEntry(_, _, _, readState, notificationSettings, _, _, _, _, _, _, _, _, _):
|
case let .PeerEntry(_, _, _, readState, notificationSettings, _, _, _, _, _, _, _, _, _, _):
|
||||||
if let readState = readState {
|
if let readState = readState {
|
||||||
let count = readState.count
|
let count = readState.count
|
||||||
rawUnreadCount += count
|
rawUnreadCount += count
|
||||||
@ -895,7 +895,7 @@ public final class ChatListNode: ListView {
|
|||||||
var referenceId: PinnedItemId?
|
var referenceId: PinnedItemId?
|
||||||
var beforeAll = false
|
var beforeAll = false
|
||||||
switch toEntry {
|
switch toEntry {
|
||||||
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, isAd):
|
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, isAd, _):
|
||||||
if isAd {
|
if isAd {
|
||||||
beforeAll = true
|
beforeAll = true
|
||||||
} else {
|
} else {
|
||||||
@ -913,7 +913,7 @@ public final class ChatListNode: ListView {
|
|||||||
|
|
||||||
var itemId: PinnedItemId?
|
var itemId: PinnedItemId?
|
||||||
switch fromEntry {
|
switch fromEntry {
|
||||||
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
itemId = .peer(index.messageIndex.id.peerId)
|
itemId = .peer(index.messageIndex.id.peerId)
|
||||||
/*case let .GroupReferenceEntry(_, _, groupId, _, _, _, _):
|
/*case let .GroupReferenceEntry(_, _, groupId, _, _, _, _):
|
||||||
itemId = .group(groupId)*/
|
itemId = .group(groupId)*/
|
||||||
@ -1338,7 +1338,7 @@ public final class ChatListNode: ListView {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
switch chatListView.filteredEntries[entryCount - i - 1] {
|
switch chatListView.filteredEntries[entryCount - i - 1] {
|
||||||
case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _, _, _):
|
case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _, _, _, _):
|
||||||
if interaction.highlightedChatLocation?.location == ChatLocation.peer(peer.peerId) {
|
if interaction.highlightedChatLocation?.location == ChatLocation.peer(peer.peerId) {
|
||||||
current = (index, peer.peerId, entryCount - i - 1)
|
current = (index, peer.peerId, entryCount - i - 1)
|
||||||
break outer
|
break outer
|
||||||
@ -1371,10 +1371,10 @@ public final class ChatListNode: ListView {
|
|||||||
case .previous(unread: false), .next(unread: false):
|
case .previous(unread: false), .next(unread: false):
|
||||||
var target: (ChatListIndex, PeerId)? = nil
|
var target: (ChatListIndex, PeerId)? = nil
|
||||||
if let current = current, entryCount > 1 {
|
if let current = current, entryCount > 1 {
|
||||||
if current.2 > 0, case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _, _, _) = chatListView.filteredEntries[current.2 - 1] {
|
if current.2 > 0, case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _, _, _, _) = chatListView.filteredEntries[current.2 - 1] {
|
||||||
next = (index, peer.peerId)
|
next = (index, peer.peerId)
|
||||||
}
|
}
|
||||||
if current.2 <= entryCount - 2, case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _, _, _) = chatListView.filteredEntries[current.2 + 1] {
|
if current.2 <= entryCount - 2, case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _, _, _, _) = chatListView.filteredEntries[current.2 + 1] {
|
||||||
previous = (index, peer.peerId)
|
previous = (index, peer.peerId)
|
||||||
}
|
}
|
||||||
if case .previous = option {
|
if case .previous = option {
|
||||||
@ -1383,7 +1383,7 @@ public final class ChatListNode: ListView {
|
|||||||
target = next
|
target = next
|
||||||
}
|
}
|
||||||
} else if entryCount > 0 {
|
} else if entryCount > 0 {
|
||||||
if case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _, _, _) = chatListView.filteredEntries[entryCount - 1] {
|
if case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _, _, _, _) = chatListView.filteredEntries[entryCount - 1] {
|
||||||
target = (index, peer.peerId)
|
target = (index, peer.peerId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1402,7 +1402,7 @@ public final class ChatListNode: ListView {
|
|||||||
|> take(1)
|
|> take(1)
|
||||||
|> deliverOnMainQueue).start(next: { update in
|
|> deliverOnMainQueue).start(next: { update in
|
||||||
let entries = update.view.entries
|
let entries = update.view.entries
|
||||||
if entries.count > index, case let .MessageEntry(index, _, _, _, _, renderedPeer, _, _) = entries[10 - index - 1] {
|
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)
|
let location: ChatListNodeLocation = .scroll(index: index, sourceIndex: .absoluteLowerBound, scrollPosition: .center(.top), animated: true)
|
||||||
self.setChatListLocation(location)
|
self.setChatListLocation(location)
|
||||||
self.peerSelected?(renderedPeer.peerId, false, false)
|
self.peerSelected?(renderedPeer.peerId, false, false)
|
||||||
@ -1445,7 +1445,7 @@ public final class ChatListNode: ListView {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
switch chatListView.filteredEntries[entryCount - i - 1] {
|
switch chatListView.filteredEntries[entryCount - i - 1] {
|
||||||
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
return index
|
return index
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
|
@ -13,14 +13,14 @@ enum ChatListNodeEntryId: Hashable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum ChatListNodeEntry: Comparable, Identifiable {
|
enum ChatListNodeEntry: Comparable, Identifiable {
|
||||||
case PeerEntry(index: ChatListIndex, presentationData: ChatListPresentationData, message: Message?, readState: CombinedPeerReadState?, notificationSettings: PeerNotificationSettings?, embeddedInterfaceState: PeerChatListEmbeddedInterfaceState?, peer: RenderedPeer, presence: PeerPresence?, summaryInfo: ChatListMessageTagSummaryInfo, editing: Bool, hasActiveRevealControls: Bool, selected: Bool, inputActivities: [(Peer, PeerInputActivity)]?, isAd: Bool)
|
case PeerEntry(index: ChatListIndex, presentationData: ChatListPresentationData, message: Message?, readState: CombinedPeerReadState?, notificationSettings: PeerNotificationSettings?, embeddedInterfaceState: PeerChatListEmbeddedInterfaceState?, peer: RenderedPeer, presence: PeerPresence?, summaryInfo: ChatListMessageTagSummaryInfo, editing: Bool, hasActiveRevealControls: Bool, selected: Bool, inputActivities: [(Peer, PeerInputActivity)]?, isAd: Bool, hasFailedMessages: Bool)
|
||||||
case HoleEntry(ChatListHole, theme: PresentationTheme)
|
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 GroupReferenceEntry(index: ChatListIndex, presentationData: ChatListPresentationData, groupId: PeerGroupId, peers: [ChatListGroupReferencePeer], message: Message?, editing: Bool, unreadState: PeerGroupUnreadCountersCombinedSummary, revealed: Bool, hiddenByDefault: Bool)
|
||||||
case ArchiveIntro(presentationData: ChatListPresentationData)
|
case ArchiveIntro(presentationData: ChatListPresentationData)
|
||||||
|
|
||||||
var sortIndex: ChatListIndex {
|
var sortIndex: ChatListIndex {
|
||||||
switch self {
|
switch self {
|
||||||
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
return index
|
return index
|
||||||
case let .HoleEntry(hole, _):
|
case let .HoleEntry(hole, _):
|
||||||
return ChatListIndex(pinningIndex: nil, messageIndex: hole.index)
|
return ChatListIndex(pinningIndex: nil, messageIndex: hole.index)
|
||||||
@ -33,7 +33,7 @@ enum ChatListNodeEntry: Comparable, Identifiable {
|
|||||||
|
|
||||||
var stableId: ChatListNodeEntryId {
|
var stableId: ChatListNodeEntryId {
|
||||||
switch self {
|
switch self {
|
||||||
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
return .PeerId(index.messageIndex.id.peerId.toInt64())
|
return .PeerId(index.messageIndex.id.peerId.toInt64())
|
||||||
case let .HoleEntry(hole, _):
|
case let .HoleEntry(hole, _):
|
||||||
return .Hole(Int64(hole.index.id.id))
|
return .Hole(Int64(hole.index.id.id))
|
||||||
@ -50,9 +50,9 @@ enum ChatListNodeEntry: Comparable, Identifiable {
|
|||||||
|
|
||||||
static func ==(lhs: ChatListNodeEntry, rhs: ChatListNodeEntry) -> Bool {
|
static func ==(lhs: ChatListNodeEntry, rhs: ChatListNodeEntry) -> Bool {
|
||||||
switch lhs {
|
switch lhs {
|
||||||
case let .PeerEntry(lhsIndex, lhsPresentationData, lhsMessage, lhsUnreadCount, lhsNotificationSettings, lhsEmbeddedState, lhsPeer, lhsPresence, lhsSummaryInfo, lhsEditing, lhsHasRevealControls, lhsSelected, lhsInputActivities, lhsAd):
|
case let .PeerEntry(lhsIndex, lhsPresentationData, lhsMessage, lhsUnreadCount, lhsNotificationSettings, lhsEmbeddedState, lhsPeer, lhsPresence, lhsSummaryInfo, lhsEditing, lhsHasRevealControls, lhsSelected, lhsInputActivities, lhsAd, lhsHasFailedMessages):
|
||||||
switch rhs {
|
switch rhs {
|
||||||
case let .PeerEntry(rhsIndex, rhsPresentationData, rhsMessage, rhsUnreadCount, rhsNotificationSettings, rhsEmbeddedState, rhsPeer, rhsPresence, rhsSummaryInfo, rhsEditing, rhsHasRevealControls, rhsSelected, rhsInputActivities, rhsAd):
|
case let .PeerEntry(rhsIndex, rhsPresentationData, rhsMessage, rhsUnreadCount, rhsNotificationSettings, rhsEmbeddedState, rhsPeer, rhsPresence, rhsSummaryInfo, rhsEditing, rhsHasRevealControls, rhsSelected, rhsInputActivities, rhsAd, rhsHasFailedMessages):
|
||||||
if lhsIndex != rhsIndex {
|
if lhsIndex != rhsIndex {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -119,7 +119,9 @@ enum ChatListNodeEntry: Comparable, Identifiable {
|
|||||||
if lhsAd != rhsAd {
|
if lhsAd != rhsAd {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhsHasFailedMessages != rhsHasFailedMessages {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
@ -203,7 +205,7 @@ func chatListNodeEntriesForView(_ view: ChatListView, state: ChatListNodeState,
|
|||||||
}
|
}
|
||||||
loop: for entry in view.entries {
|
loop: for entry in view.entries {
|
||||||
switch entry {
|
switch entry {
|
||||||
case let .MessageEntry(index, message, combinedReadState, notificationSettings, embeddedState, peer, peerPresence, summaryInfo):
|
case let .MessageEntry(index, message, combinedReadState, notificationSettings, embeddedState, peer, peerPresence, summaryInfo, hasFailed):
|
||||||
if let savedMessagesPeer = savedMessagesPeer, savedMessagesPeer.id == index.messageIndex.id.peerId {
|
if let savedMessagesPeer = savedMessagesPeer, savedMessagesPeer.id == index.messageIndex.id.peerId {
|
||||||
continue loop
|
continue loop
|
||||||
}
|
}
|
||||||
@ -216,7 +218,7 @@ func chatListNodeEntriesForView(_ view: ChatListView, state: ChatListNodeState,
|
|||||||
updatedMessage = nil
|
updatedMessage = nil
|
||||||
updatedCombinedReadState = nil
|
updatedCombinedReadState = nil
|
||||||
}
|
}
|
||||||
result.append(.PeerEntry(index: offsetPinnedIndex(index, offset: pinnedIndexOffset), presentationData: state.presentationData, message: updatedMessage, readState: updatedCombinedReadState, notificationSettings: notificationSettings, 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], isAd: false))
|
result.append(.PeerEntry(index: offsetPinnedIndex(index, offset: pinnedIndexOffset), presentationData: state.presentationData, message: updatedMessage, readState: updatedCombinedReadState, notificationSettings: notificationSettings, 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], isAd: false, hasFailedMessages: hasFailed))
|
||||||
case let .HoleEntry(hole):
|
case let .HoleEntry(hole):
|
||||||
if hole.index.timestamp == Int32.max - 1 {
|
if hole.index.timestamp == Int32.max - 1 {
|
||||||
return ([], true)
|
return ([], true)
|
||||||
@ -228,13 +230,13 @@ func chatListNodeEntriesForView(_ view: ChatListView, state: ChatListNodeState,
|
|||||||
var pinningIndex: UInt16 = UInt16(pinnedIndexOffset == 0 ? 0 : (pinnedIndexOffset - 1))
|
var pinningIndex: UInt16 = UInt16(pinnedIndexOffset == 0 ? 0 : (pinnedIndexOffset - 1))
|
||||||
|
|
||||||
if let savedMessagesPeer = savedMessagesPeer {
|
if let savedMessagesPeer = savedMessagesPeer {
|
||||||
result.append(.PeerEntry(index: ChatListIndex.absoluteUpperBound.predecessor, presentationData: state.presentationData, message: nil, readState: nil, notificationSettings: nil, embeddedInterfaceState: nil, peer: RenderedPeer(peerId: savedMessagesPeer.id, peers: SimpleDictionary([savedMessagesPeer.id: savedMessagesPeer])), presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(), editing: state.editing, hasActiveRevealControls: false, selected: false, inputActivities: nil, isAd: false))
|
result.append(.PeerEntry(index: ChatListIndex.absoluteUpperBound.predecessor, presentationData: state.presentationData, message: nil, readState: nil, notificationSettings: nil, embeddedInterfaceState: nil, peer: RenderedPeer(peerId: savedMessagesPeer.id, peers: SimpleDictionary([savedMessagesPeer.id: savedMessagesPeer])), presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(), editing: state.editing, hasActiveRevealControls: false, selected: false, inputActivities: nil, isAd: false, hasFailedMessages: false))
|
||||||
} else {
|
} else {
|
||||||
if !view.additionalItemEntries.isEmpty {
|
if !view.additionalItemEntries.isEmpty {
|
||||||
for entry in view.additionalItemEntries.reversed() {
|
for entry in view.additionalItemEntries.reversed() {
|
||||||
switch entry {
|
switch entry {
|
||||||
case let .MessageEntry(index, message, combinedReadState, notificationSettings, embeddedState, peer, peerPresence, summaryInfo):
|
case let .MessageEntry(index, message, combinedReadState, notificationSettings, embeddedState, peer, peerPresence, summaryInfo, hasFailed):
|
||||||
result.append(.PeerEntry(index: ChatListIndex(pinningIndex: pinningIndex, messageIndex: index.messageIndex), presentationData: state.presentationData, message: message, readState: combinedReadState, notificationSettings: notificationSettings, 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], isAd: true))
|
result.append(.PeerEntry(index: ChatListIndex(pinningIndex: pinningIndex, messageIndex: index.messageIndex), presentationData: state.presentationData, message: message, readState: combinedReadState, notificationSettings: notificationSettings, 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], isAd: true, hasFailedMessages: hasFailed))
|
||||||
if pinningIndex != 0 {
|
if pinningIndex != 0 {
|
||||||
pinningIndex -= 1
|
pinningIndex -= 1
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ static_library(
|
|||||||
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
||||||
"//submodules/TextSelectionNode:TextSelectionNode",
|
"//submodules/TextSelectionNode:TextSelectionNode",
|
||||||
"//submodules/ReactionSelectionNode:ReactionSelectionNode",
|
"//submodules/ReactionSelectionNode:ReactionSelectionNode",
|
||||||
|
"//submodules/AppBundle:AppBundle",
|
||||||
],
|
],
|
||||||
frameworks = [
|
frameworks = [
|
||||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||||
|
@ -2,6 +2,8 @@ import Foundation
|
|||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
import Display
|
import Display
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
|
import TextSelectionNode
|
||||||
|
import AppBundle
|
||||||
|
|
||||||
private final class ContextActionsSelectionGestureRecognizer: UIPanGestureRecognizer {
|
private final class ContextActionsSelectionGestureRecognizer: UIPanGestureRecognizer {
|
||||||
var updateLocation: ((CGPoint, Bool) -> Void)?
|
var updateLocation: ((CGPoint, Bool) -> Void)?
|
||||||
@ -38,7 +40,7 @@ private enum ContextItemNode {
|
|||||||
case separator(ASDisplayNode)
|
case separator(ASDisplayNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
final class ContextActionsContainerNode: ASDisplayNode {
|
private final class InnerActionsContainerNode: ASDisplayNode {
|
||||||
private let presentationData: PresentationData
|
private let presentationData: PresentationData
|
||||||
private var effectView: UIVisualEffectView?
|
private var effectView: UIVisualEffectView?
|
||||||
private var itemNodes: [ContextItemNode]
|
private var itemNodes: [ContextItemNode]
|
||||||
@ -242,3 +244,179 @@ final class ContextActionsContainerNode: ASDisplayNode {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final class InnerTextSelectionTipContainerNode: ASDisplayNode {
|
||||||
|
private let presentationData: PresentationData
|
||||||
|
private var effectView: UIVisualEffectView?
|
||||||
|
private let textNode: TextNode
|
||||||
|
private var textSelectionNode: TextSelectionNode?
|
||||||
|
private let iconNode: ASImageNode
|
||||||
|
|
||||||
|
private let text: String
|
||||||
|
private let targetSelectionIndex: Int
|
||||||
|
|
||||||
|
init(presentationData: PresentationData) {
|
||||||
|
self.presentationData = presentationData
|
||||||
|
self.textNode = TextNode()
|
||||||
|
|
||||||
|
var rawText = self.presentationData.strings.ChatContextMenu_TextSelectionTip
|
||||||
|
if let range = rawText.range(of: "|") {
|
||||||
|
rawText.removeSubrange(range)
|
||||||
|
self.text = rawText
|
||||||
|
self.targetSelectionIndex = NSRange(range, in: rawText).lowerBound
|
||||||
|
} else {
|
||||||
|
self.text = rawText
|
||||||
|
self.targetSelectionIndex = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
self.iconNode = ASImageNode()
|
||||||
|
self.iconNode.displaysAsynchronously = false
|
||||||
|
self.iconNode.displayWithoutProcessing = true
|
||||||
|
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Tip"), color: presentationData.theme.contextMenu.primaryColor)
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
self.clipsToBounds = true
|
||||||
|
self.cornerRadius = 14.0
|
||||||
|
|
||||||
|
self.backgroundColor = presentationData.theme.contextMenu.backgroundColor
|
||||||
|
|
||||||
|
let textSelectionNode = TextSelectionNode(theme: TextSelectionTheme(selection: presentationData.theme.contextMenu.primaryColor.withAlphaComponent(0.15), knob: presentationData.theme.contextMenu.primaryColor, knobDiameter: 8.0), strings: presentationData.strings, textNode: self.textNode, updateIsActive: { _ in
|
||||||
|
}, present: { _, _ in
|
||||||
|
}, rootNode: self, performAction: { _, _ in
|
||||||
|
})
|
||||||
|
self.textSelectionNode = textSelectionNode
|
||||||
|
|
||||||
|
self.addSubnode(self.textNode)
|
||||||
|
self.addSubnode(self.iconNode)
|
||||||
|
|
||||||
|
self.textSelectionNode.flatMap(self.addSubnode)
|
||||||
|
|
||||||
|
self.addSubnode(textSelectionNode.highlightAreaNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateLayout(widthClass: ContainerViewLayoutSizeClass, width: CGFloat, transition: ContainedViewLayoutTransition) -> CGSize {
|
||||||
|
switch widthClass {
|
||||||
|
case .compact:
|
||||||
|
if let effectView = self.effectView {
|
||||||
|
self.effectView = nil
|
||||||
|
effectView.removeFromSuperview()
|
||||||
|
}
|
||||||
|
case .regular:
|
||||||
|
if self.effectView == nil {
|
||||||
|
let effectView: UIVisualEffectView
|
||||||
|
if #available(iOS 13.0, *) {
|
||||||
|
if self.presentationData.theme.overallDarkAppearance {
|
||||||
|
effectView = UIVisualEffectView(effect: UIBlurEffect(style: .systemMaterialDark))
|
||||||
|
} else {
|
||||||
|
effectView = UIVisualEffectView(effect: UIBlurEffect(style: .systemMaterialLight))
|
||||||
|
}
|
||||||
|
} else if #available(iOS 10.0, *) {
|
||||||
|
effectView = UIVisualEffectView(effect: UIBlurEffect(style: .regular))
|
||||||
|
} else {
|
||||||
|
effectView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
|
||||||
|
}
|
||||||
|
self.effectView = effectView
|
||||||
|
self.view.insertSubview(effectView, at: 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let verticalInset: CGFloat = 10.0
|
||||||
|
let horizontalInset: CGFloat = 16.0
|
||||||
|
let standardIconWidth: CGFloat = 32.0
|
||||||
|
let iconSideInset: CGFloat = 12.0
|
||||||
|
|
||||||
|
let textFont = Font.regular(floor(presentationData.fontSize.baseDisplaySize * 14.0 / 17.0))
|
||||||
|
|
||||||
|
let iconSize = self.iconNode.image?.size ?? CGSize(width: 16.0, height: 16.0)
|
||||||
|
|
||||||
|
let makeTextLayout = TextNode.asyncLayout(self.textNode)
|
||||||
|
let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: self.text, font: textFont, textColor: self.presentationData.theme.contextMenu.primaryColor), backgroundColor: nil, minimumNumberOfLines: 0, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: width - horizontalInset * 2.0 - iconSize.width - 8.0, height: .greatestFiniteMagnitude), alignment: .left, lineSpacing: 0.0, cutout: nil, insets: UIEdgeInsets(), lineColor: nil, textShadowColor: nil, textStroke: nil))
|
||||||
|
let _ = textApply()
|
||||||
|
|
||||||
|
let textFrame = CGRect(origin: CGPoint(x: horizontalInset, y: verticalInset), size: textLayout.size)
|
||||||
|
transition.updateFrame(node: self.textNode, frame: textFrame)
|
||||||
|
|
||||||
|
let size = CGSize(width: width, height: textLayout.size.height + verticalInset * 2.0)
|
||||||
|
|
||||||
|
let iconFrame = CGRect(origin: CGPoint(x: size.width - standardIconWidth - iconSideInset + floor((standardIconWidth - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize)
|
||||||
|
transition.updateFrame(node: self.iconNode, frame: iconFrame)
|
||||||
|
|
||||||
|
if let textSelectionNode = self.textSelectionNode {
|
||||||
|
transition.updateFrame(node: textSelectionNode, frame: textFrame)
|
||||||
|
textSelectionNode.highlightAreaNode.frame = textFrame
|
||||||
|
}
|
||||||
|
|
||||||
|
if let effectView = self.effectView {
|
||||||
|
transition.updateFrame(view: effectView, frame: CGRect(origin: CGPoint(), size: size))
|
||||||
|
}
|
||||||
|
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateTheme(presentationData: PresentationData) {
|
||||||
|
self.backgroundColor = presentationData.theme.contextMenu.backgroundColor
|
||||||
|
}
|
||||||
|
|
||||||
|
func animateIn() {
|
||||||
|
if let textSelectionNode = self.textSelectionNode {
|
||||||
|
textSelectionNode.pretendInitiateSelection()
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.5, execute: { [weak self] in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strongSelf.textSelectionNode?.pretendExtendSelection(to: strongSelf.targetSelectionIndex)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final class ContextActionsContainerNode: ASDisplayNode {
|
||||||
|
private let actionsNode: InnerActionsContainerNode
|
||||||
|
private let textSelectionTipNode: InnerTextSelectionTipContainerNode?
|
||||||
|
|
||||||
|
init(presentationData: PresentationData, items: [ContextMenuItem], getController: @escaping () -> ContextController?, actionSelected: @escaping (ContextMenuActionResult) -> Void, feedbackTap: @escaping () -> Void, displayTextSelectionTip: Bool) {
|
||||||
|
self.actionsNode = InnerActionsContainerNode(presentationData: presentationData, items: items, getController: getController, actionSelected: actionSelected, feedbackTap: feedbackTap)
|
||||||
|
if displayTextSelectionTip {
|
||||||
|
let textSelectionTipNode = InnerTextSelectionTipContainerNode(presentationData: presentationData)
|
||||||
|
textSelectionTipNode.isUserInteractionEnabled = false
|
||||||
|
self.textSelectionTipNode = textSelectionTipNode
|
||||||
|
} else {
|
||||||
|
self.textSelectionTipNode = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
self.addSubnode(self.actionsNode)
|
||||||
|
self.textSelectionTipNode.flatMap(self.addSubnode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateLayout(widthClass: ContainerViewLayoutSizeClass, constrainedWidth: CGFloat, transition: ContainedViewLayoutTransition) -> CGSize {
|
||||||
|
let actionsSize = self.actionsNode.updateLayout(widthClass: widthClass, constrainedWidth: constrainedWidth, transition: transition)
|
||||||
|
|
||||||
|
var contentSize = actionsSize
|
||||||
|
transition.updateFrame(node: self.actionsNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: actionsSize))
|
||||||
|
|
||||||
|
if let textSelectionTipNode = self.textSelectionTipNode {
|
||||||
|
contentSize.height += 8.0
|
||||||
|
let textSelectionTipSize = textSelectionTipNode.updateLayout(widthClass: widthClass, width: actionsSize.width, transition: transition)
|
||||||
|
transition.updateFrame(node: textSelectionTipNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentSize.height), size: textSelectionTipSize))
|
||||||
|
contentSize.height += textSelectionTipSize.height
|
||||||
|
}
|
||||||
|
|
||||||
|
return contentSize
|
||||||
|
}
|
||||||
|
|
||||||
|
func actionNode(at point: CGPoint) -> ContextActionNode? {
|
||||||
|
return self.actionsNode.actionNode(at: self.view.convert(point, to: self.actionsNode.view))
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateTheme(presentationData: PresentationData) {
|
||||||
|
self.actionsNode.updateTheme(presentationData: presentationData)
|
||||||
|
self.textSelectionTipNode?.updateTheme(presentationData: presentationData)
|
||||||
|
}
|
||||||
|
|
||||||
|
func animateIn() {
|
||||||
|
self.textSelectionTipNode?.animateIn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -69,6 +69,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
private let attemptTransitionControllerIntoNavigation: () -> Void
|
private let attemptTransitionControllerIntoNavigation: () -> Void
|
||||||
private let getController: () -> ContextController?
|
private let getController: () -> ContextController?
|
||||||
private weak var gesture: ContextGesture?
|
private weak var gesture: ContextGesture?
|
||||||
|
private var displayTextSelectionTip: Bool
|
||||||
|
|
||||||
private var didSetItemsReady = false
|
private var didSetItemsReady = false
|
||||||
let itemsReady = Promise<Bool>()
|
let itemsReady = Promise<Bool>()
|
||||||
@ -107,7 +108,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
|
|
||||||
private let itemsDisposable = MetaDisposable()
|
private let itemsDisposable = MetaDisposable()
|
||||||
|
|
||||||
init(account: Account, controller: ContextController, presentationData: PresentationData, source: ContextContentSource, items: Signal<[ContextMenuItem], NoError>, reactionItems: [ReactionContextItem], beginDismiss: @escaping (ContextMenuActionResult) -> Void, recognizer: TapLongTapOrDoubleTapGestureRecognizer?, gesture: ContextGesture?, reactionSelected: @escaping (String) -> Void, beganAnimatingOut: @escaping () -> Void, attemptTransitionControllerIntoNavigation: @escaping () -> Void) {
|
init(account: Account, controller: ContextController, presentationData: PresentationData, source: ContextContentSource, items: Signal<[ContextMenuItem], NoError>, reactionItems: [ReactionContextItem], beginDismiss: @escaping (ContextMenuActionResult) -> Void, recognizer: TapLongTapOrDoubleTapGestureRecognizer?, gesture: ContextGesture?, reactionSelected: @escaping (String) -> Void, beganAnimatingOut: @escaping () -> Void, attemptTransitionControllerIntoNavigation: @escaping () -> Void, displayTextSelectionTip: Bool) {
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
self.source = source
|
self.source = source
|
||||||
self.items = items
|
self.items = items
|
||||||
@ -116,6 +117,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
self.beganAnimatingOut = beganAnimatingOut
|
self.beganAnimatingOut = beganAnimatingOut
|
||||||
self.attemptTransitionControllerIntoNavigation = attemptTransitionControllerIntoNavigation
|
self.attemptTransitionControllerIntoNavigation = attemptTransitionControllerIntoNavigation
|
||||||
self.gesture = gesture
|
self.gesture = gesture
|
||||||
|
self.displayTextSelectionTip = displayTextSelectionTip
|
||||||
|
|
||||||
self.getController = { [weak controller] in
|
self.getController = { [weak controller] in
|
||||||
return controller
|
return controller
|
||||||
@ -163,7 +165,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
beginDismiss(result)
|
beginDismiss(result)
|
||||||
}, feedbackTap: {
|
}, feedbackTap: {
|
||||||
feedbackTap?()
|
feedbackTap?()
|
||||||
})
|
}, displayTextSelectionTip: self.displayTextSelectionTip)
|
||||||
|
|
||||||
if !reactionItems.isEmpty {
|
if !reactionItems.isEmpty {
|
||||||
let reactionContextNode = ReactionContextNode(account: account, theme: presentationData.theme, items: reactionItems)
|
let reactionContextNode = ReactionContextNode(account: account, theme: presentationData.theme, items: reactionItems)
|
||||||
@ -528,6 +530,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
}, completion: { [weak self] in
|
}, completion: { [weak self] in
|
||||||
self?.didCompleteAnimationIn = true
|
self?.didCompleteAnimationIn = true
|
||||||
self?.hapticFeedback.prepareTap()
|
self?.hapticFeedback.prepareTap()
|
||||||
|
self?.actionsContainerNode.animateIn()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -535,6 +538,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
self.effectView.effect = makeCustomZoomBlurEffect()
|
self.effectView.effect = makeCustomZoomBlurEffect()
|
||||||
}, completion: { [weak self] _ in
|
}, completion: { [weak self] _ in
|
||||||
self?.didCompleteAnimationIn = true
|
self?.didCompleteAnimationIn = true
|
||||||
|
self?.actionsContainerNode.animateIn()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -970,7 +974,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
self?.beginDismiss(result)
|
self?.beginDismiss(result)
|
||||||
}, feedbackTap: { [weak self] in
|
}, feedbackTap: { [weak self] in
|
||||||
self?.hapticFeedback.tap()
|
self?.hapticFeedback.tap()
|
||||||
})
|
}, displayTextSelectionTip: self.displayTextSelectionTip)
|
||||||
self.scrollNode.insertSubnode(self.actionsContainerNode, aboveSubnode: previousActionsContainerNode)
|
self.scrollNode.insertSubnode(self.actionsContainerNode, aboveSubnode: previousActionsContainerNode)
|
||||||
|
|
||||||
if let layout = self.validLayout {
|
if let layout = self.validLayout {
|
||||||
@ -982,6 +986,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
|
|
||||||
if !self.didSetItemsReady {
|
if !self.didSetItemsReady {
|
||||||
self.didSetItemsReady = true
|
self.didSetItemsReady = true
|
||||||
|
self.displayTextSelectionTip = false
|
||||||
self.itemsReady.set(.single(true))
|
self.itemsReady.set(.single(true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1374,6 +1379,7 @@ public final class ContextController: ViewController, StandalonePresentableContr
|
|||||||
|
|
||||||
private weak var recognizer: TapLongTapOrDoubleTapGestureRecognizer?
|
private weak var recognizer: TapLongTapOrDoubleTapGestureRecognizer?
|
||||||
private weak var gesture: ContextGesture?
|
private weak var gesture: ContextGesture?
|
||||||
|
private let displayTextSelectionTip: Bool
|
||||||
|
|
||||||
private var animatedDidAppear = false
|
private var animatedDidAppear = false
|
||||||
private var wasDismissed = false
|
private var wasDismissed = false
|
||||||
@ -1384,7 +1390,7 @@ public final class ContextController: ViewController, StandalonePresentableContr
|
|||||||
|
|
||||||
public var reactionSelected: ((String) -> Void)?
|
public var reactionSelected: ((String) -> Void)?
|
||||||
|
|
||||||
public init(account: Account, presentationData: PresentationData, source: ContextContentSource, items: Signal<[ContextMenuItem], NoError>, reactionItems: [ReactionContextItem], recognizer: TapLongTapOrDoubleTapGestureRecognizer? = nil, gesture: ContextGesture? = nil) {
|
public init(account: Account, presentationData: PresentationData, source: ContextContentSource, items: Signal<[ContextMenuItem], NoError>, reactionItems: [ReactionContextItem], recognizer: TapLongTapOrDoubleTapGestureRecognizer? = nil, gesture: ContextGesture? = nil, displayTextSelectionTip: Bool = false) {
|
||||||
self.account = account
|
self.account = account
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
self.source = source
|
self.source = source
|
||||||
@ -1392,6 +1398,7 @@ public final class ContextController: ViewController, StandalonePresentableContr
|
|||||||
self.reactionItems = reactionItems
|
self.reactionItems = reactionItems
|
||||||
self.recognizer = recognizer
|
self.recognizer = recognizer
|
||||||
self.gesture = gesture
|
self.gesture = gesture
|
||||||
|
self.displayTextSelectionTip = displayTextSelectionTip
|
||||||
|
|
||||||
super.init(navigationBarPresentationData: nil)
|
super.init(navigationBarPresentationData: nil)
|
||||||
|
|
||||||
@ -1425,7 +1432,7 @@ public final class ContextController: ViewController, StandalonePresentableContr
|
|||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
})
|
}, displayTextSelectionTip: self.displayTextSelectionTip)
|
||||||
|
|
||||||
self.displayNodeDidLoad()
|
self.displayNodeDidLoad()
|
||||||
|
|
||||||
|
@ -88,12 +88,12 @@ public struct ChatListGroupReferenceEntry: Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public enum ChatListEntry: Comparable {
|
public enum ChatListEntry: Comparable {
|
||||||
case MessageEntry(ChatListIndex, Message?, CombinedPeerReadState?, PeerNotificationSettings?, PeerChatListEmbeddedInterfaceState?, RenderedPeer, PeerPresence?, ChatListMessageTagSummaryInfo)
|
case MessageEntry(ChatListIndex, Message?, CombinedPeerReadState?, PeerNotificationSettings?, PeerChatListEmbeddedInterfaceState?, RenderedPeer, PeerPresence?, ChatListMessageTagSummaryInfo, Bool)
|
||||||
case HoleEntry(ChatListHole)
|
case HoleEntry(ChatListHole)
|
||||||
|
|
||||||
public var index: ChatListIndex {
|
public var index: ChatListIndex {
|
||||||
switch self {
|
switch self {
|
||||||
case let .MessageEntry(index, _, _, _, _, _, _, _):
|
case let .MessageEntry(index, _, _, _, _, _, _, _, _):
|
||||||
return index
|
return index
|
||||||
case let .HoleEntry(hole):
|
case let .HoleEntry(hole):
|
||||||
return ChatListIndex(pinningIndex: nil, messageIndex: hole.index)
|
return ChatListIndex(pinningIndex: nil, messageIndex: hole.index)
|
||||||
@ -102,9 +102,9 @@ public enum ChatListEntry: Comparable {
|
|||||||
|
|
||||||
public static func ==(lhs: ChatListEntry, rhs: ChatListEntry) -> Bool {
|
public static func ==(lhs: ChatListEntry, rhs: ChatListEntry) -> Bool {
|
||||||
switch lhs {
|
switch lhs {
|
||||||
case let .MessageEntry(lhsIndex, lhsMessage, lhsReadState, lhsSettings, lhsEmbeddedState, lhsPeer, lhsPresence, lhsInfo):
|
case let .MessageEntry(lhsIndex, lhsMessage, lhsReadState, lhsSettings, lhsEmbeddedState, lhsPeer, lhsPresence, lhsInfo, lhsHasFailed):
|
||||||
switch rhs {
|
switch rhs {
|
||||||
case let .MessageEntry(rhsIndex, rhsMessage, rhsReadState, rhsSettings, rhsEmbeddedState, rhsPeer, rhsPresence, rhsInfo):
|
case let .MessageEntry(rhsIndex, rhsMessage, rhsReadState, rhsSettings, rhsEmbeddedState, rhsPeer, rhsPresence, rhsInfo, rhsHasFailed):
|
||||||
if lhsIndex != rhsIndex {
|
if lhsIndex != rhsIndex {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -141,6 +141,9 @@ public enum ChatListEntry: Comparable {
|
|||||||
if lhsInfo != rhsInfo {
|
if lhsInfo != rhsInfo {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhsHasFailed != rhsHasFailed {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
@ -178,7 +181,7 @@ private func processedChatListEntry(_ entry: MutableChatListEntry, cachedDataTab
|
|||||||
|
|
||||||
enum MutableChatListEntry: Equatable {
|
enum MutableChatListEntry: Equatable {
|
||||||
case IntermediateMessageEntry(ChatListIndex, IntermediateMessage?, CombinedPeerReadState?, PeerChatListEmbeddedInterfaceState?)
|
case IntermediateMessageEntry(ChatListIndex, IntermediateMessage?, CombinedPeerReadState?, PeerChatListEmbeddedInterfaceState?)
|
||||||
case MessageEntry(ChatListIndex, Message?, CombinedPeerReadState?, PeerNotificationSettings?, PeerChatListEmbeddedInterfaceState?, RenderedPeer, PeerPresence?, ChatListMessageTagSummaryInfo)
|
case MessageEntry(ChatListIndex, Message?, CombinedPeerReadState?, PeerNotificationSettings?, PeerChatListEmbeddedInterfaceState?, RenderedPeer, PeerPresence?, ChatListMessageTagSummaryInfo, Bool)
|
||||||
case HoleEntry(ChatListHole)
|
case HoleEntry(ChatListHole)
|
||||||
|
|
||||||
init(_ intermediateEntry: ChatListIntermediateEntry, cachedDataTable: CachedPeerDataTable, readStateTable: MessageHistoryReadStateTable, messageHistoryTable: MessageHistoryTable) {
|
init(_ intermediateEntry: ChatListIntermediateEntry, cachedDataTable: CachedPeerDataTable, readStateTable: MessageHistoryReadStateTable, messageHistoryTable: MessageHistoryTable) {
|
||||||
@ -194,7 +197,7 @@ enum MutableChatListEntry: Equatable {
|
|||||||
switch self {
|
switch self {
|
||||||
case let .IntermediateMessageEntry(index, _, _, _):
|
case let .IntermediateMessageEntry(index, _, _, _):
|
||||||
return index
|
return index
|
||||||
case let .MessageEntry(index, _, _, _, _, _, _, _):
|
case let .MessageEntry(index, _, _, _, _, _, _, _, _):
|
||||||
return index
|
return index
|
||||||
case let .HoleEntry(hole):
|
case let .HoleEntry(hole):
|
||||||
return ChatListIndex(pinningIndex: nil, messageIndex: hole.index)
|
return ChatListIndex(pinningIndex: nil, messageIndex: hole.index)
|
||||||
@ -488,13 +491,13 @@ final class MutableChatListView {
|
|||||||
if !updatedPeerNotificationSettings.isEmpty {
|
if !updatedPeerNotificationSettings.isEmpty {
|
||||||
for i in 0 ..< self.entries.count {
|
for i in 0 ..< self.entries.count {
|
||||||
switch self.entries[i] {
|
switch self.entries[i] {
|
||||||
case let .MessageEntry(index, message, readState, _, embeddedState, peer, peerPresence, summaryInfo):
|
case let .MessageEntry(index, message, readState, _, embeddedState, peer, peerPresence, summaryInfo, hasFailed):
|
||||||
var notificationSettingsPeerId = peer.peerId
|
var notificationSettingsPeerId = peer.peerId
|
||||||
if let peer = peer.peers[peer.peerId], let associatedPeerId = peer.associatedPeerId {
|
if let peer = peer.peers[peer.peerId], let associatedPeerId = peer.associatedPeerId {
|
||||||
notificationSettingsPeerId = associatedPeerId
|
notificationSettingsPeerId = associatedPeerId
|
||||||
}
|
}
|
||||||
if let settings = updatedPeerNotificationSettings[notificationSettingsPeerId] {
|
if let settings = updatedPeerNotificationSettings[notificationSettingsPeerId] {
|
||||||
self.entries[i] = .MessageEntry(index, message, readState, settings, embeddedState, peer, peerPresence, summaryInfo)
|
self.entries[i] = .MessageEntry(index, message, readState, settings, embeddedState, peer, peerPresence, summaryInfo, hasFailed)
|
||||||
hasChanges = true
|
hasChanges = true
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -502,17 +505,35 @@ final class MutableChatListView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !transaction.updatedFailedMessagePeerIds.isEmpty {
|
||||||
|
for i in 0 ..< self.entries.count {
|
||||||
|
switch self.entries[i] {
|
||||||
|
case let .MessageEntry(index, message, readState, settings, embeddedState, peer, peerPresence, summaryInfo, previousHasFailed):
|
||||||
|
if transaction.updatedFailedMessagePeerIds.contains(index.messageIndex.id.peerId) {
|
||||||
|
let hasFailed = postbox.messageHistoryFailedTable.contains(peerId: index.messageIndex.id.peerId)
|
||||||
|
if previousHasFailed != hasFailed {
|
||||||
|
self.entries[i] = .MessageEntry(index, message, readState, settings, embeddedState, peer, peerPresence, summaryInfo, hasFailed)
|
||||||
|
hasChanges = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !updatedPeers.isEmpty {
|
if !updatedPeers.isEmpty {
|
||||||
for i in 0 ..< self.entries.count {
|
for i in 0 ..< self.entries.count {
|
||||||
switch self.entries[i] {
|
switch self.entries[i] {
|
||||||
case let .MessageEntry(index, message, readState, settings, embeddedState, peer, peerPresence, summaryInfo):
|
case let .MessageEntry(index, message, readState, settings, embeddedState, peer, peerPresence, summaryInfo, hasFailed):
|
||||||
var updatedMessage: Message?
|
var updatedMessage: Message?
|
||||||
if let message = message {
|
if let message = message {
|
||||||
updatedMessage = updateMessagePeers(message, updatedPeers: updatedPeers)
|
updatedMessage = updateMessagePeers(message, updatedPeers: updatedPeers)
|
||||||
}
|
}
|
||||||
let updatedPeer = updatedRenderedPeer(peer, updatedPeers: updatedPeers)
|
let updatedPeer = updatedRenderedPeer(peer, updatedPeers: updatedPeers)
|
||||||
if updatedMessage != nil || updatedPeer != nil {
|
if updatedMessage != nil || updatedPeer != nil {
|
||||||
self.entries[i] = .MessageEntry(index, updatedMessage ?? message, readState, settings, embeddedState, updatedPeer ?? peer, peerPresence, summaryInfo)
|
self.entries[i] = .MessageEntry(index, updatedMessage ?? message, readState, settings, embeddedState, updatedPeer ?? peer, peerPresence, summaryInfo, hasFailed)
|
||||||
hasChanges = true
|
hasChanges = true
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -523,13 +544,13 @@ final class MutableChatListView {
|
|||||||
if !updatedPeerPresences.isEmpty {
|
if !updatedPeerPresences.isEmpty {
|
||||||
for i in 0 ..< self.entries.count {
|
for i in 0 ..< self.entries.count {
|
||||||
switch self.entries[i] {
|
switch self.entries[i] {
|
||||||
case let .MessageEntry(index, message, readState, settings, embeddedState, peer, _, summaryInfo):
|
case let .MessageEntry(index, message, readState, settings, embeddedState, peer, _, summaryInfo, hasFailed):
|
||||||
var presencePeerId = peer.peerId
|
var presencePeerId = peer.peerId
|
||||||
if let peer = peer.peers[peer.peerId], let associatedPeerId = peer.associatedPeerId {
|
if let peer = peer.peers[peer.peerId], let associatedPeerId = peer.associatedPeerId {
|
||||||
presencePeerId = associatedPeerId
|
presencePeerId = associatedPeerId
|
||||||
}
|
}
|
||||||
if let presence = updatedPeerPresences[presencePeerId] {
|
if let presence = updatedPeerPresences[presencePeerId] {
|
||||||
self.entries[i] = .MessageEntry(index, message, readState, settings, embeddedState, peer, presence, summaryInfo)
|
self.entries[i] = .MessageEntry(index, message, readState, settings, embeddedState, peer, presence, summaryInfo, hasFailed)
|
||||||
hasChanges = true
|
hasChanges = true
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -540,7 +561,7 @@ final class MutableChatListView {
|
|||||||
if !transaction.currentUpdatedMessageTagSummaries.isEmpty || !transaction.currentUpdatedMessageActionsSummaries.isEmpty {
|
if !transaction.currentUpdatedMessageTagSummaries.isEmpty || !transaction.currentUpdatedMessageActionsSummaries.isEmpty {
|
||||||
for i in 0 ..< self.entries.count {
|
for i in 0 ..< self.entries.count {
|
||||||
switch self.entries[i] {
|
switch self.entries[i] {
|
||||||
case let .MessageEntry(index, message, readState, settings, embeddedState, peer, peerPresence, currentSummary):
|
case let .MessageEntry(index, message, readState, settings, embeddedState, peer, peerPresence, currentSummary, hasFailed):
|
||||||
var updatedTagSummaryCount: Int32?
|
var updatedTagSummaryCount: Int32?
|
||||||
var updatedActionsSummaryCount: Int32?
|
var updatedActionsSummaryCount: Int32?
|
||||||
|
|
||||||
@ -561,7 +582,7 @@ final class MutableChatListView {
|
|||||||
if updatedTagSummaryCount != nil || updatedActionsSummaryCount != nil {
|
if updatedTagSummaryCount != nil || updatedActionsSummaryCount != nil {
|
||||||
let summaryInfo = ChatListMessageTagSummaryInfo(tagSummaryCount: updatedTagSummaryCount ?? currentSummary.tagSummaryCount, actionsSummaryCount: updatedActionsSummaryCount ?? currentSummary.actionsSummaryCount)
|
let summaryInfo = ChatListMessageTagSummaryInfo(tagSummaryCount: updatedTagSummaryCount ?? currentSummary.tagSummaryCount, actionsSummaryCount: updatedActionsSummaryCount ?? currentSummary.actionsSummaryCount)
|
||||||
|
|
||||||
self.entries[i] = .MessageEntry(index, message, readState, settings, embeddedState, peer, peerPresence, summaryInfo)
|
self.entries[i] = .MessageEntry(index, message, readState, settings, embeddedState, peer, peerPresence, summaryInfo, hasFailed)
|
||||||
hasChanges = true
|
hasChanges = true
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -816,51 +837,48 @@ final class MutableChatListView {
|
|||||||
|
|
||||||
private func renderEntry(_ entry: MutableChatListEntry, postbox: Postbox, renderMessage: (IntermediateMessage) -> Message, getPeer: (PeerId) -> Peer?, getPeerNotificationSettings: (PeerId) -> PeerNotificationSettings?, getPeerPresence: (PeerId) -> PeerPresence?) -> MutableChatListEntry? {
|
private func renderEntry(_ entry: MutableChatListEntry, postbox: Postbox, renderMessage: (IntermediateMessage) -> Message, getPeer: (PeerId) -> Peer?, getPeerNotificationSettings: (PeerId) -> PeerNotificationSettings?, getPeerPresence: (PeerId) -> PeerPresence?) -> MutableChatListEntry? {
|
||||||
switch entry {
|
switch entry {
|
||||||
case let .IntermediateMessageEntry(index, message, combinedReadState, embeddedState):
|
case let .IntermediateMessageEntry(index, message, combinedReadState, embeddedState):
|
||||||
let renderedMessage: Message?
|
let renderedMessage: Message?
|
||||||
if let message = message {
|
if let message = message {
|
||||||
renderedMessage = renderMessage(message)
|
renderedMessage = renderMessage(message)
|
||||||
|
} else {
|
||||||
|
renderedMessage = nil
|
||||||
|
}
|
||||||
|
var peers = SimpleDictionary<PeerId, Peer>()
|
||||||
|
var notificationSettings: PeerNotificationSettings?
|
||||||
|
var presence: PeerPresence?
|
||||||
|
if let peer = getPeer(index.messageIndex.id.peerId) {
|
||||||
|
peers[peer.id] = peer
|
||||||
|
if let associatedPeerId = peer.associatedPeerId {
|
||||||
|
if let associatedPeer = getPeer(associatedPeerId) {
|
||||||
|
peers[associatedPeer.id] = associatedPeer
|
||||||
|
}
|
||||||
|
notificationSettings = getPeerNotificationSettings(associatedPeerId)
|
||||||
|
presence = getPeerPresence(associatedPeerId)
|
||||||
} else {
|
} else {
|
||||||
renderedMessage = nil
|
notificationSettings = getPeerNotificationSettings(index.messageIndex.id.peerId)
|
||||||
|
presence = getPeerPresence(index.messageIndex.id.peerId)
|
||||||
}
|
}
|
||||||
var peers = SimpleDictionary<PeerId, Peer>()
|
}
|
||||||
var notificationSettings: PeerNotificationSettings?
|
|
||||||
var presence: PeerPresence?
|
var tagSummaryCount: Int32?
|
||||||
if let peer = getPeer(index.messageIndex.id.peerId) {
|
var actionsSummaryCount: Int32?
|
||||||
peers[peer.id] = peer
|
|
||||||
if let associatedPeerId = peer.associatedPeerId {
|
if let tagSummary = self.summaryComponents.tagSummary {
|
||||||
if let associatedPeer = getPeer(associatedPeerId) {
|
let key = MessageHistoryTagsSummaryKey(tag: tagSummary.tag, peerId: index.messageIndex.id.peerId, namespace: tagSummary.namespace)
|
||||||
peers[associatedPeer.id] = associatedPeer
|
if let summary = postbox.messageHistoryTagsSummaryTable.get(key) {
|
||||||
}
|
tagSummaryCount = summary.count
|
||||||
notificationSettings = getPeerNotificationSettings(associatedPeerId)
|
|
||||||
presence = getPeerPresence(associatedPeerId)
|
|
||||||
} else {
|
|
||||||
notificationSettings = getPeerNotificationSettings(index.messageIndex.id.peerId)
|
|
||||||
presence = getPeerPresence(index.messageIndex.id.peerId)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var tagSummaryCount: Int32?
|
if let actionsSummary = self.summaryComponents.actionsSummary {
|
||||||
var actionsSummaryCount: Int32?
|
let key = PendingMessageActionsSummaryKey(type: actionsSummary.type, peerId: index.messageIndex.id.peerId, namespace: actionsSummary.namespace)
|
||||||
|
actionsSummaryCount = postbox.pendingMessageActionsMetadataTable.getCount(.peerNamespaceAction(key.peerId, key.namespace, key.type))
|
||||||
|
}
|
||||||
|
|
||||||
if let tagSummary = self.summaryComponents.tagSummary {
|
return .MessageEntry(index, renderedMessage, combinedReadState, notificationSettings, embeddedState, RenderedPeer(peerId: index.messageIndex.id.peerId, peers: peers), presence, ChatListMessageTagSummaryInfo(tagSummaryCount: tagSummaryCount, actionsSummaryCount: actionsSummaryCount), postbox.messageHistoryFailedTable.contains(peerId: index.messageIndex.id.peerId))
|
||||||
let key = MessageHistoryTagsSummaryKey(tag: tagSummary.tag, peerId: index.messageIndex.id.peerId, namespace: tagSummary.namespace)
|
default:
|
||||||
if let summary = postbox.messageHistoryTagsSummaryTable.get(key) {
|
return nil
|
||||||
tagSummaryCount = summary.count
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let actionsSummary = self.summaryComponents.actionsSummary {
|
|
||||||
let key = PendingMessageActionsSummaryKey(type: actionsSummary.type, peerId: index.messageIndex.id.peerId, namespace: actionsSummary.namespace)
|
|
||||||
actionsSummaryCount = postbox.pendingMessageActionsMetadataTable.getCount(.peerNamespaceAction(key.peerId, key.namespace, key.type))
|
|
||||||
}
|
|
||||||
|
|
||||||
return .MessageEntry(index, renderedMessage, combinedReadState, notificationSettings, embeddedState, RenderedPeer(peerId: index.messageIndex.id.peerId, peers: peers), presence, ChatListMessageTagSummaryInfo(tagSummaryCount: tagSummaryCount, actionsSummaryCount: actionsSummaryCount))
|
|
||||||
/*case let .IntermediateGroupReferenceEntry(groupId, index, counters):
|
|
||||||
let message = postbox.messageHistoryTable.getMessage(index.messageIndex).flatMap(postbox.renderIntermediateMessage)
|
|
||||||
return .GroupReferenceEntry(groupId, index, message, ChatListGroupReferenceTopPeers(postbox: postbox, groupId: groupId), counters ?? ChatListGroupReferenceUnreadCounters(postbox: postbox, groupId: groupId))*/
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -892,8 +910,8 @@ public final class ChatListView {
|
|||||||
var entries: [ChatListEntry] = []
|
var entries: [ChatListEntry] = []
|
||||||
for entry in mutableView.entries {
|
for entry in mutableView.entries {
|
||||||
switch entry {
|
switch entry {
|
||||||
case let .MessageEntry(index, message, combinedReadState, notificationSettings, embeddedState, peer, peerPresence, summaryInfo):
|
case let .MessageEntry(index, message, combinedReadState, notificationSettings, embeddedState, peer, peerPresence, summaryInfo, hasFailed):
|
||||||
entries.append(.MessageEntry(index, message, combinedReadState, notificationSettings, embeddedState, peer, peerPresence, summaryInfo))
|
entries.append(.MessageEntry(index, message, combinedReadState, notificationSettings, embeddedState, peer, peerPresence, summaryInfo, hasFailed))
|
||||||
case let .HoleEntry(hole):
|
case let .HoleEntry(hole):
|
||||||
entries.append(.HoleEntry(hole))
|
entries.append(.HoleEntry(hole))
|
||||||
/*case let .GroupReferenceEntry(groupId, index, message, topPeers, counters):
|
/*case let .GroupReferenceEntry(groupId, index, message, topPeers, counters):
|
||||||
@ -912,8 +930,8 @@ public final class ChatListView {
|
|||||||
var additionalItemEntries: [ChatListEntry] = []
|
var additionalItemEntries: [ChatListEntry] = []
|
||||||
for entry in mutableView.additionalItemEntries {
|
for entry in mutableView.additionalItemEntries {
|
||||||
switch entry {
|
switch entry {
|
||||||
case let .MessageEntry(index, message, combinedReadState, notificationSettings, embeddedState, peer, peerPresence, summaryInfo):
|
case let .MessageEntry(index, message, combinedReadState, notificationSettings, embeddedState, peer, peerPresence, summaryInfo, hasFailed):
|
||||||
additionalItemEntries.append(.MessageEntry(index, message, combinedReadState, notificationSettings, embeddedState, peer, peerPresence, summaryInfo))
|
additionalItemEntries.append(.MessageEntry(index, message, combinedReadState, notificationSettings, embeddedState, peer, peerPresence, summaryInfo, hasFailed))
|
||||||
case .HoleEntry:
|
case .HoleEntry:
|
||||||
assertionFailure()
|
assertionFailure()
|
||||||
/*case .GroupReferenceEntry:
|
/*case .GroupReferenceEntry:
|
||||||
|
55
submodules/Postbox/Sources/MessageHistoryFailedTable.swift
Normal file
55
submodules/Postbox/Sources/MessageHistoryFailedTable.swift
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
final class MessageHistoryFailedTable: Table {
|
||||||
|
static func tableSpec(_ id: Int32) -> ValueBoxTable {
|
||||||
|
return ValueBoxTable(id: id, keyType: .binary, compactValuesOnCreation: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private let sharedKey = ValueBoxKey(length: 8 + 4 + 4)
|
||||||
|
|
||||||
|
private(set) var updatedPeerIds = Set<PeerId>()
|
||||||
|
|
||||||
|
private func key(_ id: MessageId) -> ValueBoxKey {
|
||||||
|
self.sharedKey.setInt64(0, value: id.peerId.toInt64())
|
||||||
|
self.sharedKey.setInt32(8, value: id.namespace)
|
||||||
|
self.sharedKey.setInt32(8 + 4, value: id.id)
|
||||||
|
|
||||||
|
return self.sharedKey
|
||||||
|
}
|
||||||
|
|
||||||
|
private func lowerBound(peerId: PeerId) -> ValueBoxKey {
|
||||||
|
let key = ValueBoxKey(length: 8)
|
||||||
|
key.setInt64(0, value: peerId.toInt64())
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
|
private func upperBound(peerId: PeerId) -> ValueBoxKey {
|
||||||
|
let key = ValueBoxKey(length: 8)
|
||||||
|
key.setInt64(0, value: peerId.toInt64())
|
||||||
|
return key.successor
|
||||||
|
}
|
||||||
|
|
||||||
|
func add(_ id: MessageId) {
|
||||||
|
self.valueBox.set(self.table, key: self.key(id), value: MemoryBuffer())
|
||||||
|
self.updatedPeerIds.insert(id.peerId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func remove(_ id: MessageId) {
|
||||||
|
self.valueBox.remove(self.table, key: self.key(id), secure: false)
|
||||||
|
self.updatedPeerIds.insert(id.peerId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func contains(peerId: PeerId) -> Bool {
|
||||||
|
var result = false
|
||||||
|
self.valueBox.range(self.table, start: self.lowerBound(peerId: peerId), end: self.upperBound(peerId: peerId), keys: { _ in
|
||||||
|
result = true
|
||||||
|
return false
|
||||||
|
}, limit: 1)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
override func beforeCommit() {
|
||||||
|
self.updatedPeerIds.removeAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -69,6 +69,7 @@ final class MessageHistoryTable: Table {
|
|||||||
let historyMetadataTable: MessageHistoryMetadataTable
|
let historyMetadataTable: MessageHistoryMetadataTable
|
||||||
let globallyUniqueMessageIdsTable: MessageGloballyUniqueIdTable
|
let globallyUniqueMessageIdsTable: MessageGloballyUniqueIdTable
|
||||||
let unsentTable: MessageHistoryUnsentTable
|
let unsentTable: MessageHistoryUnsentTable
|
||||||
|
let failedTable: MessageHistoryFailedTable
|
||||||
let tagsTable: MessageHistoryTagsTable
|
let tagsTable: MessageHistoryTagsTable
|
||||||
let globalTagsTable: GlobalMessageHistoryTagsTable
|
let globalTagsTable: GlobalMessageHistoryTagsTable
|
||||||
let localTagsTable: LocalMessageHistoryTagsTable
|
let localTagsTable: LocalMessageHistoryTagsTable
|
||||||
@ -78,7 +79,7 @@ final class MessageHistoryTable: Table {
|
|||||||
let summaryTable: MessageHistoryTagsSummaryTable
|
let summaryTable: MessageHistoryTagsSummaryTable
|
||||||
let pendingActionsTable: PendingMessageActionsTable
|
let pendingActionsTable: PendingMessageActionsTable
|
||||||
|
|
||||||
init(valueBox: ValueBox, table: ValueBoxTable, seedConfiguration: SeedConfiguration, messageHistoryIndexTable: MessageHistoryIndexTable, messageHistoryHoleIndexTable: MessageHistoryHoleIndexTable, messageMediaTable: MessageMediaTable, historyMetadataTable: MessageHistoryMetadataTable, globallyUniqueMessageIdsTable: MessageGloballyUniqueIdTable, unsentTable: MessageHistoryUnsentTable, tagsTable: MessageHistoryTagsTable, globalTagsTable: GlobalMessageHistoryTagsTable, localTagsTable: LocalMessageHistoryTagsTable, readStateTable: MessageHistoryReadStateTable, synchronizeReadStateTable: MessageHistorySynchronizeReadStateTable, textIndexTable: MessageHistoryTextIndexTable, summaryTable: MessageHistoryTagsSummaryTable, pendingActionsTable: PendingMessageActionsTable) {
|
init(valueBox: ValueBox, table: ValueBoxTable, seedConfiguration: SeedConfiguration, messageHistoryIndexTable: MessageHistoryIndexTable, messageHistoryHoleIndexTable: MessageHistoryHoleIndexTable, messageMediaTable: MessageMediaTable, historyMetadataTable: MessageHistoryMetadataTable, globallyUniqueMessageIdsTable: MessageGloballyUniqueIdTable, unsentTable: MessageHistoryUnsentTable, failedTable: MessageHistoryFailedTable, tagsTable: MessageHistoryTagsTable, globalTagsTable: GlobalMessageHistoryTagsTable, localTagsTable: LocalMessageHistoryTagsTable, readStateTable: MessageHistoryReadStateTable, synchronizeReadStateTable: MessageHistorySynchronizeReadStateTable, textIndexTable: MessageHistoryTextIndexTable, summaryTable: MessageHistoryTagsSummaryTable, pendingActionsTable: PendingMessageActionsTable) {
|
||||||
self.seedConfiguration = seedConfiguration
|
self.seedConfiguration = seedConfiguration
|
||||||
self.messageHistoryIndexTable = messageHistoryIndexTable
|
self.messageHistoryIndexTable = messageHistoryIndexTable
|
||||||
self.messageHistoryHoleIndexTable = messageHistoryHoleIndexTable
|
self.messageHistoryHoleIndexTable = messageHistoryHoleIndexTable
|
||||||
@ -86,6 +87,7 @@ final class MessageHistoryTable: Table {
|
|||||||
self.historyMetadataTable = historyMetadataTable
|
self.historyMetadataTable = historyMetadataTable
|
||||||
self.globallyUniqueMessageIdsTable = globallyUniqueMessageIdsTable
|
self.globallyUniqueMessageIdsTable = globallyUniqueMessageIdsTable
|
||||||
self.unsentTable = unsentTable
|
self.unsentTable = unsentTable
|
||||||
|
self.failedTable = failedTable
|
||||||
self.tagsTable = tagsTable
|
self.tagsTable = tagsTable
|
||||||
self.globalTagsTable = globalTagsTable
|
self.globalTagsTable = globalTagsTable
|
||||||
self.localTagsTable = localTagsTable
|
self.localTagsTable = localTagsTable
|
||||||
@ -249,6 +251,9 @@ final class MessageHistoryTable: Table {
|
|||||||
if message.flags.contains(.Unsent) && !message.flags.contains(.Failed) {
|
if message.flags.contains(.Unsent) && !message.flags.contains(.Failed) {
|
||||||
self.unsentTable.add(message.id, operations: &unsentMessageOperations)
|
self.unsentTable.add(message.id, operations: &unsentMessageOperations)
|
||||||
}
|
}
|
||||||
|
if message.flags.contains(.Failed) {
|
||||||
|
self.failedTable.add(message.id)
|
||||||
|
}
|
||||||
let tags = message.tags.rawValue
|
let tags = message.tags.rawValue
|
||||||
if tags != 0 {
|
if tags != 0 {
|
||||||
for i in 0 ..< 32 {
|
for i in 0 ..< 32 {
|
||||||
@ -1194,6 +1199,9 @@ final class MessageHistoryTable: Table {
|
|||||||
if message.flags.contains(.Unsent) && !message.flags.contains(.Failed) {
|
if message.flags.contains(.Unsent) && !message.flags.contains(.Failed) {
|
||||||
self.unsentTable.remove(index.id, operations: &unsentMessageOperations)
|
self.unsentTable.remove(index.id, operations: &unsentMessageOperations)
|
||||||
}
|
}
|
||||||
|
if message.flags.contains(.Failed) {
|
||||||
|
self.failedTable.remove(message.id)
|
||||||
|
}
|
||||||
|
|
||||||
if let globallyUniqueId = message.globallyUniqueId {
|
if let globallyUniqueId = message.globallyUniqueId {
|
||||||
self.globallyUniqueMessageIdsTable.remove(peerId: message.id.peerId, globallyUniqueId: globallyUniqueId)
|
self.globallyUniqueMessageIdsTable.remove(peerId: message.id.peerId, globallyUniqueId: globallyUniqueId)
|
||||||
@ -1447,6 +1455,23 @@ final class MessageHistoryTable: Table {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if previousMessage.id != message.id {
|
||||||
|
if previousMessage.flags.contains(.Failed) {
|
||||||
|
self.failedTable.remove(previousMessage.id)
|
||||||
|
}
|
||||||
|
if message.flags.contains(.Failed) {
|
||||||
|
self.failedTable.add(message.id)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if previousMessage.flags.contains(.Failed) != message.flags.contains(.Failed) {
|
||||||
|
if previousMessage.flags.contains(.Failed) {
|
||||||
|
self.failedTable.remove(previousMessage.id)
|
||||||
|
} else {
|
||||||
|
self.failedTable.add(message.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if self.seedConfiguration.peerNamespacesRequiringMessageTextIndex.contains(message.id.peerId.namespace) {
|
if self.seedConfiguration.peerNamespacesRequiringMessageTextIndex.contains(message.id.peerId.namespace) {
|
||||||
if previousMessage.id != message.id || previousMessage.text != message.text || previousMessage.tags != message.tags {
|
if previousMessage.id != message.id || previousMessage.text != message.text || previousMessage.tags != message.tags {
|
||||||
self.textIndexTable.remove(messageId: previousMessage.id)
|
self.textIndexTable.remove(messageId: previousMessage.id)
|
||||||
|
@ -1134,6 +1134,7 @@ public final class Postbox {
|
|||||||
let additionalChatListItemsTable: AdditionalChatListItemsTable
|
let additionalChatListItemsTable: AdditionalChatListItemsTable
|
||||||
let messageHistoryMetadataTable: MessageHistoryMetadataTable
|
let messageHistoryMetadataTable: MessageHistoryMetadataTable
|
||||||
let messageHistoryUnsentTable: MessageHistoryUnsentTable
|
let messageHistoryUnsentTable: MessageHistoryUnsentTable
|
||||||
|
let messageHistoryFailedTable: MessageHistoryFailedTable
|
||||||
let messageHistoryTagsTable: MessageHistoryTagsTable
|
let messageHistoryTagsTable: MessageHistoryTagsTable
|
||||||
let globalMessageHistoryTagsTable: GlobalMessageHistoryTagsTable
|
let globalMessageHistoryTagsTable: GlobalMessageHistoryTagsTable
|
||||||
let localMessageHistoryTagsTable: LocalMessageHistoryTagsTable
|
let localMessageHistoryTagsTable: LocalMessageHistoryTagsTable
|
||||||
@ -1211,6 +1212,7 @@ public final class Postbox {
|
|||||||
self.messageHistoryMetadataTable = MessageHistoryMetadataTable(valueBox: self.valueBox, table: MessageHistoryMetadataTable.tableSpec(10))
|
self.messageHistoryMetadataTable = MessageHistoryMetadataTable(valueBox: self.valueBox, table: MessageHistoryMetadataTable.tableSpec(10))
|
||||||
self.messageHistoryHoleIndexTable = MessageHistoryHoleIndexTable(valueBox: self.valueBox, table: MessageHistoryHoleIndexTable.tableSpec(56), metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration)
|
self.messageHistoryHoleIndexTable = MessageHistoryHoleIndexTable(valueBox: self.valueBox, table: MessageHistoryHoleIndexTable.tableSpec(56), metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration)
|
||||||
self.messageHistoryUnsentTable = MessageHistoryUnsentTable(valueBox: self.valueBox, table: MessageHistoryUnsentTable.tableSpec(11))
|
self.messageHistoryUnsentTable = MessageHistoryUnsentTable(valueBox: self.valueBox, table: MessageHistoryUnsentTable.tableSpec(11))
|
||||||
|
self.messageHistoryFailedTable = MessageHistoryFailedTable(valueBox: self.valueBox, table: MessageHistoryFailedTable.tableSpec(49))
|
||||||
self.invalidatedMessageHistoryTagsSummaryTable = InvalidatedMessageHistoryTagsSummaryTable(valueBox: self.valueBox, table: InvalidatedMessageHistoryTagsSummaryTable.tableSpec(47))
|
self.invalidatedMessageHistoryTagsSummaryTable = InvalidatedMessageHistoryTagsSummaryTable(valueBox: self.valueBox, table: InvalidatedMessageHistoryTagsSummaryTable.tableSpec(47))
|
||||||
self.messageHistoryTagsSummaryTable = MessageHistoryTagsSummaryTable(valueBox: self.valueBox, table: MessageHistoryTagsSummaryTable.tableSpec(44), invalidateTable: self.invalidatedMessageHistoryTagsSummaryTable)
|
self.messageHistoryTagsSummaryTable = MessageHistoryTagsSummaryTable(valueBox: self.valueBox, table: MessageHistoryTagsSummaryTable.tableSpec(44), invalidateTable: self.invalidatedMessageHistoryTagsSummaryTable)
|
||||||
self.pendingMessageActionsMetadataTable = PendingMessageActionsMetadataTable(valueBox: self.valueBox, table: PendingMessageActionsMetadataTable.tableSpec(45))
|
self.pendingMessageActionsMetadataTable = PendingMessageActionsMetadataTable(valueBox: self.valueBox, table: PendingMessageActionsMetadataTable.tableSpec(45))
|
||||||
@ -1227,7 +1229,7 @@ public final class Postbox {
|
|||||||
self.timestampBasedMessageAttributesTable = TimestampBasedMessageAttributesTable(valueBox: self.valueBox, table: TimestampBasedMessageAttributesTable.tableSpec(34), indexTable: self.timestampBasedMessageAttributesIndexTable)
|
self.timestampBasedMessageAttributesTable = TimestampBasedMessageAttributesTable(valueBox: self.valueBox, table: TimestampBasedMessageAttributesTable.tableSpec(34), indexTable: self.timestampBasedMessageAttributesIndexTable)
|
||||||
self.textIndexTable = MessageHistoryTextIndexTable(valueBox: self.valueBox, table: MessageHistoryTextIndexTable.tableSpec(41))
|
self.textIndexTable = MessageHistoryTextIndexTable(valueBox: self.valueBox, table: MessageHistoryTextIndexTable.tableSpec(41))
|
||||||
self.additionalChatListItemsTable = AdditionalChatListItemsTable(valueBox: self.valueBox, table: AdditionalChatListItemsTable.tableSpec(55))
|
self.additionalChatListItemsTable = AdditionalChatListItemsTable(valueBox: self.valueBox, table: AdditionalChatListItemsTable.tableSpec(55))
|
||||||
self.messageHistoryTable = MessageHistoryTable(valueBox: self.valueBox, table: MessageHistoryTable.tableSpec(7), seedConfiguration: seedConfiguration, messageHistoryIndexTable: self.messageHistoryIndexTable, messageHistoryHoleIndexTable: self.messageHistoryHoleIndexTable, messageMediaTable: self.mediaTable, historyMetadataTable: self.messageHistoryMetadataTable, globallyUniqueMessageIdsTable: self.globallyUniqueMessageIdsTable, unsentTable: self.messageHistoryUnsentTable, tagsTable: self.messageHistoryTagsTable, globalTagsTable: self.globalMessageHistoryTagsTable, localTagsTable: self.localMessageHistoryTagsTable, readStateTable: self.readStateTable, synchronizeReadStateTable: self.synchronizeReadStateTable, textIndexTable: self.textIndexTable, summaryTable: self.messageHistoryTagsSummaryTable, pendingActionsTable: self.pendingMessageActionsTable)
|
self.messageHistoryTable = MessageHistoryTable(valueBox: self.valueBox, table: MessageHistoryTable.tableSpec(7), seedConfiguration: seedConfiguration, messageHistoryIndexTable: self.messageHistoryIndexTable, messageHistoryHoleIndexTable: self.messageHistoryHoleIndexTable, messageMediaTable: self.mediaTable, historyMetadataTable: self.messageHistoryMetadataTable, globallyUniqueMessageIdsTable: self.globallyUniqueMessageIdsTable, unsentTable: self.messageHistoryUnsentTable, failedTable: self.messageHistoryFailedTable, tagsTable: self.messageHistoryTagsTable, globalTagsTable: self.globalMessageHistoryTagsTable, localTagsTable: self.localMessageHistoryTagsTable, readStateTable: self.readStateTable, synchronizeReadStateTable: self.synchronizeReadStateTable, textIndexTable: self.textIndexTable, summaryTable: self.messageHistoryTagsSummaryTable, pendingActionsTable: self.pendingMessageActionsTable)
|
||||||
self.peerChatStateTable = PeerChatStateTable(valueBox: self.valueBox, table: PeerChatStateTable.tableSpec(13))
|
self.peerChatStateTable = PeerChatStateTable(valueBox: self.valueBox, table: PeerChatStateTable.tableSpec(13))
|
||||||
self.peerNameTokenIndexTable = ReverseIndexReferenceTable<PeerIdReverseIndexReference>(valueBox: self.valueBox, table: ReverseIndexReferenceTable<PeerIdReverseIndexReference>.tableSpec(26))
|
self.peerNameTokenIndexTable = ReverseIndexReferenceTable<PeerIdReverseIndexReference>(valueBox: self.valueBox, table: ReverseIndexReferenceTable<PeerIdReverseIndexReference>.tableSpec(26))
|
||||||
self.peerNameIndexTable = PeerNameIndexTable(valueBox: self.valueBox, table: PeerNameIndexTable.tableSpec(27), peerTable: self.peerTable, peerNameTokenIndexTable: self.peerNameTokenIndexTable)
|
self.peerNameIndexTable = PeerNameIndexTable(valueBox: self.valueBox, table: PeerNameIndexTable.tableSpec(27), peerTable: self.peerTable, peerNameTokenIndexTable: self.peerNameTokenIndexTable)
|
||||||
@ -1267,6 +1269,7 @@ public final class Postbox {
|
|||||||
tables.append(self.globallyUniqueMessageIdsTable)
|
tables.append(self.globallyUniqueMessageIdsTable)
|
||||||
tables.append(self.messageHistoryMetadataTable)
|
tables.append(self.messageHistoryMetadataTable)
|
||||||
tables.append(self.messageHistoryUnsentTable)
|
tables.append(self.messageHistoryUnsentTable)
|
||||||
|
tables.append(self.messageHistoryFailedTable)
|
||||||
tables.append(self.messageHistoryTagsTable)
|
tables.append(self.messageHistoryTagsTable)
|
||||||
tables.append(self.globalMessageHistoryTagsTable)
|
tables.append(self.globalMessageHistoryTagsTable)
|
||||||
tables.append(self.localMessageHistoryTagsTable)
|
tables.append(self.localMessageHistoryTagsTable)
|
||||||
@ -1700,7 +1703,7 @@ public final class Postbox {
|
|||||||
let transactionParticipationInTotalUnreadCountUpdates = self.peerNotificationSettingsTable.transactionParticipationInTotalUnreadCountUpdates(postbox: self)
|
let transactionParticipationInTotalUnreadCountUpdates = self.peerNotificationSettingsTable.transactionParticipationInTotalUnreadCountUpdates(postbox: self)
|
||||||
self.chatListIndexTable.commitWithTransaction(postbox: self, alteredInitialPeerCombinedReadStates: alteredInitialPeerCombinedReadStates, updatedPeers: updatedPeers, transactionParticipationInTotalUnreadCountUpdates: transactionParticipationInTotalUnreadCountUpdates, updatedRootUnreadState: &self.currentUpdatedTotalUnreadState, updatedGroupTotalUnreadSummaries: &self.currentUpdatedGroupTotalUnreadSummaries, currentUpdatedGroupSummarySynchronizeOperations: &self.currentUpdatedGroupSummarySynchronizeOperations)
|
self.chatListIndexTable.commitWithTransaction(postbox: self, alteredInitialPeerCombinedReadStates: alteredInitialPeerCombinedReadStates, updatedPeers: updatedPeers, transactionParticipationInTotalUnreadCountUpdates: transactionParticipationInTotalUnreadCountUpdates, updatedRootUnreadState: &self.currentUpdatedTotalUnreadState, updatedGroupTotalUnreadSummaries: &self.currentUpdatedGroupTotalUnreadSummaries, currentUpdatedGroupSummarySynchronizeOperations: &self.currentUpdatedGroupSummarySynchronizeOperations)
|
||||||
|
|
||||||
let transaction = PostboxTransaction(currentUpdatedState: self.currentUpdatedState, currentPeerHoleOperations: self.currentPeerHoleOperations, currentOperationsByPeerId: self.currentOperationsByPeerId, chatListOperations: self.currentChatListOperations, currentUpdatedChatListInclusions: self.currentUpdatedChatListInclusions, currentUpdatedPeers: self.currentUpdatedPeers, currentUpdatedPeerNotificationSettings: self.currentUpdatedPeerNotificationSettings, currentUpdatedPeerNotificationBehaviorTimestamps: self.currentUpdatedPeerNotificationBehaviorTimestamps, currentUpdatedCachedPeerData: self.currentUpdatedCachedPeerData, currentUpdatedPeerPresences: currentUpdatedPeerPresences, currentUpdatedPeerChatListEmbeddedStates: self.currentUpdatedPeerChatListEmbeddedStates, currentUpdatedTotalUnreadState: self.currentUpdatedTotalUnreadState, currentUpdatedTotalUnreadSummaries: self.currentUpdatedGroupTotalUnreadSummaries, alteredInitialPeerCombinedReadStates: alteredInitialPeerCombinedReadStates, currentPeerMergedOperationLogOperations: self.currentPeerMergedOperationLogOperations, currentTimestampBasedMessageAttributesOperations: self.currentTimestampBasedMessageAttributesOperations, unsentMessageOperations: self.currentUnsentOperations, updatedSynchronizePeerReadStateOperations: self.currentUpdatedSynchronizeReadStateOperations, currentUpdatedGroupSummarySynchronizeOperations: self.currentUpdatedGroupSummarySynchronizeOperations, currentPreferencesOperations: self.currentPreferencesOperations, currentOrderedItemListOperations: self.currentOrderedItemListOperations, currentItemCollectionItemsOperations: self.currentItemCollectionItemsOperations, currentItemCollectionInfosOperations: self.currentItemCollectionInfosOperations, currentUpdatedPeerChatStates: self.currentUpdatedPeerChatStates, currentGlobalTagsOperations: self.currentGlobalTagsOperations, currentLocalTagsOperations: self.currentLocalTagsOperations, updatedMedia: self.currentUpdatedMedia, replaceRemoteContactCount: self.currentReplaceRemoteContactCount, replaceContactPeerIds: self.currentReplacedContactPeerIds, currentPendingMessageActionsOperations: self.currentPendingMessageActionsOperations, currentUpdatedMessageActionsSummaries: self.currentUpdatedMessageActionsSummaries, currentUpdatedMessageTagSummaries: self.currentUpdatedMessageTagSummaries, currentInvalidateMessageTagSummaries: self.currentInvalidateMessageTagSummaries, currentUpdatedPendingPeerNotificationSettings: self.currentUpdatedPendingPeerNotificationSettings, replacedAdditionalChatListItems: self.currentReplacedAdditionalChatListItems, updatedNoticeEntryKeys: self.currentUpdatedNoticeEntryKeys, updatedCacheEntryKeys: self.currentUpdatedCacheEntryKeys, currentUpdatedMasterClientId: currentUpdatedMasterClientId)
|
let transaction = PostboxTransaction(currentUpdatedState: self.currentUpdatedState, currentPeerHoleOperations: self.currentPeerHoleOperations, currentOperationsByPeerId: self.currentOperationsByPeerId, chatListOperations: self.currentChatListOperations, currentUpdatedChatListInclusions: self.currentUpdatedChatListInclusions, currentUpdatedPeers: self.currentUpdatedPeers, currentUpdatedPeerNotificationSettings: self.currentUpdatedPeerNotificationSettings, currentUpdatedPeerNotificationBehaviorTimestamps: self.currentUpdatedPeerNotificationBehaviorTimestamps, currentUpdatedCachedPeerData: self.currentUpdatedCachedPeerData, currentUpdatedPeerPresences: currentUpdatedPeerPresences, currentUpdatedPeerChatListEmbeddedStates: self.currentUpdatedPeerChatListEmbeddedStates, currentUpdatedTotalUnreadState: self.currentUpdatedTotalUnreadState, currentUpdatedTotalUnreadSummaries: self.currentUpdatedGroupTotalUnreadSummaries, alteredInitialPeerCombinedReadStates: alteredInitialPeerCombinedReadStates, currentPeerMergedOperationLogOperations: self.currentPeerMergedOperationLogOperations, currentTimestampBasedMessageAttributesOperations: self.currentTimestampBasedMessageAttributesOperations, unsentMessageOperations: self.currentUnsentOperations, updatedSynchronizePeerReadStateOperations: self.currentUpdatedSynchronizeReadStateOperations, currentUpdatedGroupSummarySynchronizeOperations: self.currentUpdatedGroupSummarySynchronizeOperations, currentPreferencesOperations: self.currentPreferencesOperations, currentOrderedItemListOperations: self.currentOrderedItemListOperations, currentItemCollectionItemsOperations: self.currentItemCollectionItemsOperations, currentItemCollectionInfosOperations: self.currentItemCollectionInfosOperations, currentUpdatedPeerChatStates: self.currentUpdatedPeerChatStates, currentGlobalTagsOperations: self.currentGlobalTagsOperations, currentLocalTagsOperations: self.currentLocalTagsOperations, updatedMedia: self.currentUpdatedMedia, replaceRemoteContactCount: self.currentReplaceRemoteContactCount, replaceContactPeerIds: self.currentReplacedContactPeerIds, currentPendingMessageActionsOperations: self.currentPendingMessageActionsOperations, currentUpdatedMessageActionsSummaries: self.currentUpdatedMessageActionsSummaries, currentUpdatedMessageTagSummaries: self.currentUpdatedMessageTagSummaries, currentInvalidateMessageTagSummaries: self.currentInvalidateMessageTagSummaries, currentUpdatedPendingPeerNotificationSettings: self.currentUpdatedPendingPeerNotificationSettings, replacedAdditionalChatListItems: self.currentReplacedAdditionalChatListItems, updatedNoticeEntryKeys: self.currentUpdatedNoticeEntryKeys, updatedCacheEntryKeys: self.currentUpdatedCacheEntryKeys, currentUpdatedMasterClientId: currentUpdatedMasterClientId, updatedFailedMessagePeerIds: self.messageHistoryFailedTable.updatedPeerIds)
|
||||||
var updatedTransactionState: Int64?
|
var updatedTransactionState: Int64?
|
||||||
var updatedMasterClientId: Int64?
|
var updatedMasterClientId: Int64?
|
||||||
if !transaction.isEmpty {
|
if !transaction.isEmpty {
|
||||||
|
@ -40,6 +40,7 @@ final class PostboxTransaction {
|
|||||||
let replacedAdditionalChatListItems: [PeerId]?
|
let replacedAdditionalChatListItems: [PeerId]?
|
||||||
let updatedNoticeEntryKeys: Set<NoticeEntryKey>
|
let updatedNoticeEntryKeys: Set<NoticeEntryKey>
|
||||||
let updatedCacheEntryKeys: Set<ItemCacheEntryId>
|
let updatedCacheEntryKeys: Set<ItemCacheEntryId>
|
||||||
|
let updatedFailedMessagePeerIds: Set<PeerId>
|
||||||
|
|
||||||
var isEmpty: Bool {
|
var isEmpty: Bool {
|
||||||
if currentUpdatedState != nil {
|
if currentUpdatedState != nil {
|
||||||
@ -159,10 +160,13 @@ final class PostboxTransaction {
|
|||||||
if !updatedCacheEntryKeys.isEmpty {
|
if !updatedCacheEntryKeys.isEmpty {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if !updatedFailedMessagePeerIds.isEmpty {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
init(currentUpdatedState: PostboxCoding?, currentPeerHoleOperations: [MessageHistoryIndexHoleOperationKey: [MessageHistoryIndexHoleOperation]] = [:], currentOperationsByPeerId: [PeerId: [MessageHistoryOperation]], chatListOperations: [PeerGroupId: [ChatListOperation]], currentUpdatedChatListInclusions: [PeerId: PeerChatListInclusion], currentUpdatedPeers: [PeerId: Peer], currentUpdatedPeerNotificationSettings: [PeerId: PeerNotificationSettings], currentUpdatedPeerNotificationBehaviorTimestamps: [PeerId: PeerNotificationSettingsBehaviorTimestamp], currentUpdatedCachedPeerData: [PeerId: CachedPeerData], currentUpdatedPeerPresences: [PeerId: PeerPresence], currentUpdatedPeerChatListEmbeddedStates: [PeerId: PeerChatListEmbeddedInterfaceState?], currentUpdatedTotalUnreadState: ChatListTotalUnreadState?, currentUpdatedTotalUnreadSummaries: [PeerGroupId: PeerGroupUnreadCountersCombinedSummary], alteredInitialPeerCombinedReadStates: [PeerId: CombinedPeerReadState], currentPeerMergedOperationLogOperations: [PeerMergedOperationLogOperation], currentTimestampBasedMessageAttributesOperations: [TimestampBasedMessageAttributesOperation], unsentMessageOperations: [IntermediateMessageHistoryUnsentOperation], updatedSynchronizePeerReadStateOperations: [PeerId: PeerReadStateSynchronizationOperation?], currentUpdatedGroupSummarySynchronizeOperations: [PeerGroupAndNamespace: Bool], currentPreferencesOperations: [PreferencesOperation], currentOrderedItemListOperations: [Int32: [OrderedItemListOperation]], currentItemCollectionItemsOperations: [ItemCollectionId: [ItemCollectionItemsOperation]], currentItemCollectionInfosOperations: [ItemCollectionInfosOperation], currentUpdatedPeerChatStates: Set<PeerId>, currentGlobalTagsOperations: [GlobalMessageHistoryTagsOperation], currentLocalTagsOperations: [IntermediateMessageHistoryLocalTagsOperation], updatedMedia: [MediaId: Media?], replaceRemoteContactCount: Int32?, replaceContactPeerIds: Set<PeerId>?, currentPendingMessageActionsOperations: [PendingMessageActionsOperation], currentUpdatedMessageActionsSummaries: [PendingMessageActionsSummaryKey: Int32], currentUpdatedMessageTagSummaries: [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], currentInvalidateMessageTagSummaries: [InvalidatedMessageHistoryTagsSummaryEntryOperation], currentUpdatedPendingPeerNotificationSettings: Set<PeerId>, replacedAdditionalChatListItems: [PeerId]?, updatedNoticeEntryKeys: Set<NoticeEntryKey>, updatedCacheEntryKeys: Set<ItemCacheEntryId>, currentUpdatedMasterClientId: Int64?) {
|
init(currentUpdatedState: PostboxCoding?, currentPeerHoleOperations: [MessageHistoryIndexHoleOperationKey: [MessageHistoryIndexHoleOperation]] = [:], currentOperationsByPeerId: [PeerId: [MessageHistoryOperation]], chatListOperations: [PeerGroupId: [ChatListOperation]], currentUpdatedChatListInclusions: [PeerId: PeerChatListInclusion], currentUpdatedPeers: [PeerId: Peer], currentUpdatedPeerNotificationSettings: [PeerId: PeerNotificationSettings], currentUpdatedPeerNotificationBehaviorTimestamps: [PeerId: PeerNotificationSettingsBehaviorTimestamp], currentUpdatedCachedPeerData: [PeerId: CachedPeerData], currentUpdatedPeerPresences: [PeerId: PeerPresence], currentUpdatedPeerChatListEmbeddedStates: [PeerId: PeerChatListEmbeddedInterfaceState?], currentUpdatedTotalUnreadState: ChatListTotalUnreadState?, currentUpdatedTotalUnreadSummaries: [PeerGroupId: PeerGroupUnreadCountersCombinedSummary], alteredInitialPeerCombinedReadStates: [PeerId: CombinedPeerReadState], currentPeerMergedOperationLogOperations: [PeerMergedOperationLogOperation], currentTimestampBasedMessageAttributesOperations: [TimestampBasedMessageAttributesOperation], unsentMessageOperations: [IntermediateMessageHistoryUnsentOperation], updatedSynchronizePeerReadStateOperations: [PeerId: PeerReadStateSynchronizationOperation?], currentUpdatedGroupSummarySynchronizeOperations: [PeerGroupAndNamespace: Bool], currentPreferencesOperations: [PreferencesOperation], currentOrderedItemListOperations: [Int32: [OrderedItemListOperation]], currentItemCollectionItemsOperations: [ItemCollectionId: [ItemCollectionItemsOperation]], currentItemCollectionInfosOperations: [ItemCollectionInfosOperation], currentUpdatedPeerChatStates: Set<PeerId>, currentGlobalTagsOperations: [GlobalMessageHistoryTagsOperation], currentLocalTagsOperations: [IntermediateMessageHistoryLocalTagsOperation], updatedMedia: [MediaId: Media?], replaceRemoteContactCount: Int32?, replaceContactPeerIds: Set<PeerId>?, currentPendingMessageActionsOperations: [PendingMessageActionsOperation], currentUpdatedMessageActionsSummaries: [PendingMessageActionsSummaryKey: Int32], currentUpdatedMessageTagSummaries: [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], currentInvalidateMessageTagSummaries: [InvalidatedMessageHistoryTagsSummaryEntryOperation], currentUpdatedPendingPeerNotificationSettings: Set<PeerId>, replacedAdditionalChatListItems: [PeerId]?, updatedNoticeEntryKeys: Set<NoticeEntryKey>, updatedCacheEntryKeys: Set<ItemCacheEntryId>, currentUpdatedMasterClientId: Int64?, updatedFailedMessagePeerIds: Set<PeerId>) {
|
||||||
self.currentUpdatedState = currentUpdatedState
|
self.currentUpdatedState = currentUpdatedState
|
||||||
self.currentPeerHoleOperations = currentPeerHoleOperations
|
self.currentPeerHoleOperations = currentPeerHoleOperations
|
||||||
self.currentOperationsByPeerId = currentOperationsByPeerId
|
self.currentOperationsByPeerId = currentOperationsByPeerId
|
||||||
@ -201,5 +205,6 @@ final class PostboxTransaction {
|
|||||||
self.replacedAdditionalChatListItems = replacedAdditionalChatListItems
|
self.replacedAdditionalChatListItems = replacedAdditionalChatListItems
|
||||||
self.updatedNoticeEntryKeys = updatedNoticeEntryKeys
|
self.updatedNoticeEntryKeys = updatedNoticeEntryKeys
|
||||||
self.updatedCacheEntryKeys = updatedCacheEntryKeys
|
self.updatedCacheEntryKeys = updatedCacheEntryKeys
|
||||||
|
self.updatedFailedMessagePeerIds = updatedFailedMessagePeerIds
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -349,7 +349,8 @@ final class ViewTracker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !transaction.chatListOperations.isEmpty || !transaction.currentUpdatedPeerNotificationSettings.isEmpty || !transaction.currentUpdatedPeers.isEmpty || !transaction.currentInvalidateMessageTagSummaries.isEmpty || !transaction.currentUpdatedMessageTagSummaries.isEmpty || !transaction.currentOperationsByPeerId.isEmpty || transaction.replacedAdditionalChatListItems != nil || !transaction.currentUpdatedPeerPresences.isEmpty {
|
if !transaction.chatListOperations.isEmpty || !transaction.currentUpdatedPeerNotificationSettings.isEmpty || !transaction.currentUpdatedPeers.isEmpty || !transaction.currentInvalidateMessageTagSummaries.isEmpty || !transaction.currentUpdatedMessageTagSummaries.isEmpty || !transaction.currentOperationsByPeerId.isEmpty || transaction.replacedAdditionalChatListItems != nil || !transaction.currentUpdatedPeerPresences.isEmpty ||
|
||||||
|
!transaction.updatedFailedMessagePeerIds.isEmpty {
|
||||||
for (mutableView, pipe) in self.chatListViews.copyItems() {
|
for (mutableView, pipe) in self.chatListViews.copyItems() {
|
||||||
let context = MutableChatListViewReplayContext()
|
let context = MutableChatListViewReplayContext()
|
||||||
if mutableView.replay(postbox: postbox, operations: transaction.chatListOperations, updatedPeerNotificationSettings: transaction.currentUpdatedPeerNotificationSettings, updatedPeers: transaction.currentUpdatedPeers, updatedPeerPresences: transaction.currentUpdatedPeerPresences, transaction: transaction, context: context) {
|
if mutableView.replay(postbox: postbox, operations: transaction.chatListOperations, updatedPeerNotificationSettings: transaction.currentUpdatedPeerNotificationSettings, updatedPeers: transaction.currentUpdatedPeers, updatedPeerPresences: transaction.currentUpdatedPeerPresences, transaction: transaction, context: context) {
|
||||||
|
@ -215,22 +215,22 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
|
|||||||
let timestamp = self.referenceTimestamp
|
let timestamp = self.referenceTimestamp
|
||||||
|
|
||||||
let timestamp1 = timestamp + 120
|
let timestamp1 = timestamp + 120
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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))]), notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: 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, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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))]), notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let presenceTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + 60 * 60)
|
let presenceTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + 60 * 60)
|
||||||
let timestamp2 = timestamp + 3660
|
let timestamp2 = timestamp + 3660
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer2.id, namespace: 0, id: 0), timestamp: timestamp2)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer2.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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, notificationSettings: nil, presence: TelegramUserPresence(status: .present(until: presenceTimestamp), lastActivity: presenceTimestamp), summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: [(peer2, .typingText)], isAd: false, ignoreUnreadBadge: false, displayAsMessage: 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, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer2.id, namespace: 0, id: 0), timestamp: timestamp2)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer2.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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, notificationSettings: nil, presence: TelegramUserPresence(status: .present(until: presenceTimestamp), lastActivity: presenceTimestamp), summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: [(peer2, .typingText)], isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let timestamp3 = timestamp + 3200
|
let timestamp3 = timestamp + 3200
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer3.id, namespace: 0, id: 0), timestamp: timestamp3)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer3.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: 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, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer3.id, namespace: 0, id: 0), timestamp: timestamp3)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer3.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let timestamp4 = timestamp + 3000
|
let timestamp4 = timestamp + 3000
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer4.id, namespace: 0, id: 0), timestamp: timestamp4)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: 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, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer4.id, namespace: 0, id: 0), timestamp: timestamp4)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let timestamp5 = timestamp + 1000
|
let timestamp5 = timestamp + 1000
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer5.id, namespace: 0, id: 0), timestamp: timestamp5)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: 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, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer5.id, namespace: 0, id: 0), timestamp: timestamp5)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, 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, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer6.id, namespace: 0, id: 0), timestamp: timestamp - 360)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer6.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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))]), notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: 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, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer6.id, namespace: 0, id: 0), timestamp: timestamp - 360)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer6.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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))]), notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let width: CGFloat
|
let width: CGFloat
|
||||||
if case .regular = layout.metrics.widthClass {
|
if case .regular = layout.metrics.widthClass {
|
||||||
|
@ -439,17 +439,17 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
|||||||
let timestamp = self.referenceTimestamp
|
let timestamp = self.referenceTimestamp
|
||||||
|
|
||||||
let timestamp1 = timestamp + 120
|
let timestamp1 = timestamp + 120
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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))]), notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: 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, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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))]), notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let presenceTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + 60 * 60)
|
let presenceTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + 60 * 60)
|
||||||
let timestamp2 = timestamp + 3660
|
let timestamp2 = timestamp + 3660
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer2.id, namespace: 0, id: 0), timestamp: timestamp2)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer2.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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))]), notificationSettings: nil, presence: TelegramUserPresence(status: .present(until: presenceTimestamp), lastActivity: presenceTimestamp), summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: 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, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer2.id, namespace: 0, id: 0), timestamp: timestamp2)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer2.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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))]), notificationSettings: nil, presence: TelegramUserPresence(status: .present(until: presenceTimestamp), lastActivity: presenceTimestamp), summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let timestamp3 = timestamp + 3200
|
let timestamp3 = timestamp + 3200
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer3.id, namespace: 0, id: 0), timestamp: timestamp3)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer3.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: 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, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer3.id, namespace: 0, id: 0), timestamp: timestamp3)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer3.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let timestamp4 = timestamp + 3000
|
let timestamp4 = timestamp + 3000
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer4.id, namespace: 0, id: 0), timestamp: timestamp4)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: 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, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer4.id, namespace: 0, id: 0), timestamp: timestamp4)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, availableHeight: layout.size.height)
|
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, availableHeight: layout.size.height)
|
||||||
if let chatNodes = self.chatNodes {
|
if let chatNodes = self.chatNodes {
|
||||||
|
@ -351,24 +351,24 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
let timestamp = self.referenceTimestamp
|
let timestamp = self.referenceTimestamp
|
||||||
|
|
||||||
let timestamp1 = timestamp + 120
|
let timestamp1 = timestamp + 120
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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))]), notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: 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, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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))]), notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let presenceTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + 60 * 60)
|
let presenceTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + 60 * 60)
|
||||||
let timestamp2 = timestamp + 3660
|
let timestamp2 = timestamp + 3660
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer2.id, namespace: 0, id: 0), timestamp: timestamp2)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer2.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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, notificationSettings: nil, presence: TelegramUserPresence(status: .present(until: presenceTimestamp), lastActivity: presenceTimestamp), summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: [(peer2, .typingText)], isAd: false, ignoreUnreadBadge: false, displayAsMessage: 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, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer2.id, namespace: 0, id: 0), timestamp: timestamp2)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer2.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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, notificationSettings: nil, presence: TelegramUserPresence(status: .present(until: presenceTimestamp), lastActivity: presenceTimestamp), summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: [(peer2, .typingText)], isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let timestamp3 = timestamp + 3200
|
let timestamp3 = timestamp + 3200
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer3.id, namespace: 0, id: 0), timestamp: timestamp3)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer3.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: 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, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer3.id, namespace: 0, id: 0), timestamp: timestamp3)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer3.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let timestamp4 = timestamp + 3000
|
let timestamp4 = timestamp + 3000
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer4.id, namespace: 0, id: 0), timestamp: timestamp4)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: 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, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer4.id, namespace: 0, id: 0), timestamp: timestamp4)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let timestamp5 = timestamp + 1000
|
let timestamp5 = timestamp + 1000
|
||||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer5.id, namespace: 0, id: 0), timestamp: timestamp5)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: 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, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer5.id, namespace: 0, id: 0), timestamp: timestamp5)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, 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, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer6.id, namespace: 0, id: 0), timestamp: timestamp - 360)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer6.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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))]), notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: 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, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer6.id, namespace: 0, id: 0), timestamp: timestamp - 360)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer6.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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))]), notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, 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, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer7.id, namespace: 0, id: 0), timestamp: timestamp - 420)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer7.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: 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, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer7.id, namespace: 0, id: 0), timestamp: timestamp - 420)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer7.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: 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, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||||
|
|
||||||
let width: CGFloat
|
let width: CGFloat
|
||||||
if case .regular = layout.metrics.widthClass {
|
if case .regular = layout.metrics.widthClass {
|
||||||
|
@ -804,7 +804,7 @@ public final class ShareController: ViewController {
|
|||||||
var peers: [RenderedPeer] = []
|
var peers: [RenderedPeer] = []
|
||||||
for entry in view.0.entries.reversed() {
|
for entry in view.0.entries.reversed() {
|
||||||
switch entry {
|
switch entry {
|
||||||
case let .MessageEntry(_, _, _, _, _, renderedPeer, _, _):
|
case let .MessageEntry(_, _, _, _, _, renderedPeer, _, _, _):
|
||||||
if let peer = renderedPeer.peers[renderedPeer.peerId], peer.id != accountPeer.id, canSendMessagesToPeer(peer) {
|
if let peer = renderedPeer.peers[renderedPeer.peerId], peer.id != accountPeer.id, canSendMessagesToPeer(peer) {
|
||||||
peers.append(renderedPeer)
|
peers.append(renderedPeer)
|
||||||
}
|
}
|
||||||
|
@ -336,7 +336,7 @@ final class ChatHistoryPreloadManager {
|
|||||||
|
|
||||||
var indices: [(ChatHistoryPreloadIndex, Bool, Bool)] = []
|
var indices: [(ChatHistoryPreloadIndex, Bool, Bool)] = []
|
||||||
for entry in view.0.entries {
|
for entry in view.0.entries {
|
||||||
if case let .MessageEntry(index, _, readState, notificationSettings, _, _, _, _) = entry {
|
if case let .MessageEntry(index, _, readState, notificationSettings, _, _, _, _, _) = entry {
|
||||||
var hasUnread = false
|
var hasUnread = false
|
||||||
if let readState = readState {
|
if let readState = readState {
|
||||||
hasUnread = readState.count != 0
|
hasUnread = readState.count != 0
|
||||||
|
@ -133,6 +133,7 @@ private enum ApplicationSpecificGlobalNotice: Int32 {
|
|||||||
case cellularDataPermissionWarning = 13
|
case cellularDataPermissionWarning = 13
|
||||||
case chatMessageSearchResultsTip = 14
|
case chatMessageSearchResultsTip = 14
|
||||||
case chatMessageOptionsTip = 15
|
case chatMessageOptionsTip = 15
|
||||||
|
case chatTextSelectionTip = 16
|
||||||
|
|
||||||
var key: ValueBoxKey {
|
var key: ValueBoxKey {
|
||||||
let v = ValueBoxKey(length: 4)
|
let v = ValueBoxKey(length: 4)
|
||||||
@ -238,6 +239,10 @@ private struct ApplicationSpecificNoticeKeys {
|
|||||||
static func chatMessageOptionsTip() -> NoticeEntryKey {
|
static func chatMessageOptionsTip() -> NoticeEntryKey {
|
||||||
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.chatMessageOptionsTip.key)
|
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.chatMessageOptionsTip.key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func chatTextSelectionTip() -> NoticeEntryKey {
|
||||||
|
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.chatTextSelectionTip.key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ApplicationSpecificNotice {
|
public struct ApplicationSpecificNotice {
|
||||||
@ -573,6 +578,28 @@ public struct ApplicationSpecificNotice {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func getChatTextSelectionTips(accountManager: AccountManager) -> Signal<Int32, NoError> {
|
||||||
|
return accountManager.transaction { transaction -> Int32 in
|
||||||
|
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatTextSelectionTip()) as? ApplicationSpecificCounterNotice {
|
||||||
|
return value.value
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func incrementChatTextSelectionTips(accountManager: AccountManager, count: Int32 = 1) -> Signal<Void, NoError> {
|
||||||
|
return accountManager.transaction { transaction -> Void in
|
||||||
|
var currentValue: Int32 = 0
|
||||||
|
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatTextSelectionTip()) as? ApplicationSpecificCounterNotice {
|
||||||
|
currentValue = value.value
|
||||||
|
}
|
||||||
|
currentValue += count
|
||||||
|
|
||||||
|
transaction.setNotice(ApplicationSpecificNoticeKeys.chatTextSelectionTip(), ApplicationSpecificCounterNotice(value: currentValue))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static func reset(accountManager: AccountManager) -> Signal<Void, NoError> {
|
public static func reset(accountManager: AccountManager) -> Signal<Void, NoError> {
|
||||||
return accountManager.transaction { transaction -> Void in
|
return accountManager.transaction { transaction -> Void in
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
12
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Tip.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Tip.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "ic_lamp.pdf"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
BIN
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Tip.imageset/ic_lamp.pdf
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Tip.imageset/ic_lamp.pdf
vendored
Normal file
Binary file not shown.
@ -561,7 +561,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let _ = combineLatest(queue: .mainQueue(), contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState: strongSelf.presentationInterfaceState, context: strongSelf.context, messages: updatedMessages, controllerInteraction: strongSelf.controllerInteraction, selectAll: selectAll, interfaceInteraction: strongSelf.interfaceInteraction), loadedStickerPack(postbox: strongSelf.context.account.postbox, network: strongSelf.context.account.network, reference: .animatedEmoji, forceActualized: false)).start(next: { actions, animatedEmojiStickers in
|
let _ = combineLatest(queue: .mainQueue(), contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState: strongSelf.presentationInterfaceState, context: strongSelf.context, messages: updatedMessages, controllerInteraction: strongSelf.controllerInteraction, selectAll: selectAll, interfaceInteraction: strongSelf.interfaceInteraction), loadedStickerPack(postbox: strongSelf.context.account.postbox, network: strongSelf.context.account.network, reference: .animatedEmoji, forceActualized: false), ApplicationSpecificNotice.getChatTextSelectionTips(accountManager: strongSelf.context.sharedContext.accountManager)
|
||||||
|
).start(next: { actions, animatedEmojiStickers, chatTextSelectionTips in
|
||||||
guard let strongSelf = self, !actions.isEmpty else {
|
guard let strongSelf = self, !actions.isEmpty else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -590,7 +591,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
if Namespaces.Message.allScheduled.contains(message.id.namespace) {
|
if Namespaces.Message.allScheduled.contains(message.id.namespace) {
|
||||||
reactionItems = []
|
reactionItems = []
|
||||||
}
|
}
|
||||||
let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatMessageContextExtractedContentSource(chatNode: strongSelf.chatDisplayNode, message: message)), items: .single(actions), reactionItems: reactionItems, recognizer: recognizer)
|
|
||||||
|
let displayTextSelectionTip = !message.text.isEmpty && chatTextSelectionTips < 3
|
||||||
|
if displayTextSelectionTip {
|
||||||
|
let _ = ApplicationSpecificNotice.incrementChatTextSelectionTips(accountManager: strongSelf.context.sharedContext.accountManager).start()
|
||||||
|
}
|
||||||
|
|
||||||
|
let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatMessageContextExtractedContentSource(chatNode: strongSelf.chatDisplayNode, message: message)), items: .single(actions), reactionItems: reactionItems, recognizer: recognizer, displayTextSelectionTip: displayTextSelectionTip)
|
||||||
strongSelf.currentContextController = controller
|
strongSelf.currentContextController = controller
|
||||||
controller.reactionSelected = { [weak controller] value in
|
controller.reactionSelected = { [weak controller] value in
|
||||||
guard let strongSelf = self, let message = updatedMessages.first else {
|
guard let strongSelf = self, let message = updatedMessages.first else {
|
||||||
|
@ -11,6 +11,7 @@ import TelegramStringFormatting
|
|||||||
import MergeLists
|
import MergeLists
|
||||||
import ChatListUI
|
import ChatListUI
|
||||||
import AccountContext
|
import AccountContext
|
||||||
|
import ContextUI
|
||||||
|
|
||||||
private enum ChatListSearchEntryStableId: Hashable {
|
private enum ChatListSearchEntryStableId: Hashable {
|
||||||
case messageId(MessageId)
|
case messageId(MessageId)
|
||||||
@ -76,7 +77,7 @@ private enum ChatListSearchEntry: Comparable, Identifiable {
|
|||||||
public func item(context: AccountContext, interaction: ChatListNodeInteraction) -> ListViewItem {
|
public func item(context: AccountContext, interaction: ChatListNodeInteraction) -> ListViewItem {
|
||||||
switch self {
|
switch self {
|
||||||
case let .message(message, peer, readState, presentationData):
|
case let .message(message, peer, readState, presentationData):
|
||||||
return ChatListItem(presentationData: presentationData, context: context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: message.index), content: .peer(message: message, peer: peer, combinedReadState: readState, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: true, displayAsMessage: true), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
|
return ChatListItem(presentationData: presentationData, context: context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: message.index), content: .peer(message: message, peer: peer, combinedReadState: readState, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: true, displayAsMessage: true, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -129,7 +130,7 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, UIScrollViewDe
|
|||||||
|
|
||||||
private let previousEntries = Atomic<[ChatListSearchEntry]?>(value: nil)
|
private let previousEntries = Atomic<[ChatListSearchEntry]?>(value: nil)
|
||||||
|
|
||||||
init(context: AccountContext, location: SearchMessagesLocation, searchQuery: String, searchResult: SearchMessagesResult, searchState: SearchMessagesState) {
|
init(context: AccountContext, location: SearchMessagesLocation, searchQuery: String, searchResult: SearchMessagesResult, searchState: SearchMessagesState, presentInGlobalOverlay: @escaping (ViewController) -> Void) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.location = location
|
self.location = location
|
||||||
self.searchQuery = searchQuery
|
self.searchQuery = searchQuery
|
||||||
@ -183,7 +184,24 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, UIScrollViewDe
|
|||||||
}, updatePeerGrouping: { _, _ in
|
}, updatePeerGrouping: { _, _ in
|
||||||
}, togglePeerMarkedUnread: { _, _ in
|
}, togglePeerMarkedUnread: { _, _ in
|
||||||
}, toggleArchivedFolderHiddenByDefault: {
|
}, toggleArchivedFolderHiddenByDefault: {
|
||||||
}, activateChatPreview: { _, _, _ in
|
}, activateChatPreview: { [weak self] item, node, gesture in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
gesture?.cancel()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch item.content {
|
||||||
|
case let .peer(peer):
|
||||||
|
if let message = peer.message {
|
||||||
|
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peer.peer.peerId), subject: .message(message.id), botStart: nil, mode: .standard(previewing: true))
|
||||||
|
chatController.canReadHistory.set(false)
|
||||||
|
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: .single([]), reactionItems: [], gesture: gesture)
|
||||||
|
presentInGlobalOverlay(contextController)
|
||||||
|
} else {
|
||||||
|
gesture?.cancel()
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
gesture?.cancel()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
interaction.searchTextHighightState = searchQuery
|
interaction.searchTextHighightState = searchQuery
|
||||||
self.interaction = interaction
|
self.interaction = interaction
|
||||||
@ -317,3 +335,32 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, UIScrollViewDe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final class ContextControllerContentSourceImpl: ContextControllerContentSource {
|
||||||
|
let controller: ViewController
|
||||||
|
weak var sourceNode: ASDisplayNode?
|
||||||
|
|
||||||
|
let navigationController: NavigationController? = nil
|
||||||
|
|
||||||
|
let passthroughTouches: Bool = true
|
||||||
|
|
||||||
|
init(controller: ViewController, sourceNode: ASDisplayNode?) {
|
||||||
|
self.controller = controller
|
||||||
|
self.sourceNode = sourceNode
|
||||||
|
}
|
||||||
|
|
||||||
|
func transitionInfo() -> ContextControllerTakeControllerInfo? {
|
||||||
|
let sourceNode = self.sourceNode
|
||||||
|
return ContextControllerTakeControllerInfo(contentAreaInScreenSpace: CGRect(origin: CGPoint(), size: CGSize(width: 10.0, height: 10.0)), sourceNode: { [weak sourceNode] in
|
||||||
|
if let sourceNode = sourceNode {
|
||||||
|
return (sourceNode, sourceNode.bounds)
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func animatedIn() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -64,7 +64,9 @@ final class ChatSearchResultsController: ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override public func loadDisplayNode() {
|
override public func loadDisplayNode() {
|
||||||
self.displayNode = ChatSearchResultsControllerNode(context: self.context, location: self.location, searchQuery: self.searchQuery, searchResult: self.searchResult, searchState: self.searchState)
|
self.displayNode = ChatSearchResultsControllerNode(context: self.context, location: self.location, searchQuery: self.searchQuery, searchResult: self.searchResult, searchState: self.searchState, presentInGlobalOverlay: { [weak self] c in
|
||||||
|
self?.presentInGlobalOverlay(c)
|
||||||
|
})
|
||||||
self.controllerNode.resultSelected = { [weak self] messageIndex in
|
self.controllerNode.resultSelected = { [weak self] messageIndex in
|
||||||
self?.navigateToMessageIndex(messageIndex)
|
self?.navigateToMessageIndex(messageIndex)
|
||||||
self?.dismiss()
|
self?.dismiss()
|
||||||
|
Binary file not shown.
@ -34,12 +34,12 @@ private func cancelScrollViewGestures(view: UIView?) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func generateKnobImage(color: UIColor, inverted: Bool = false) -> UIImage? {
|
private func generateKnobImage(color: UIColor, diameter: CGFloat, inverted: Bool = false) -> UIImage? {
|
||||||
let f: (CGSize, CGContext) -> Void = { size, context in
|
let f: (CGSize, CGContext) -> Void = { size, context in
|
||||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
context.setFillColor(color.cgColor)
|
context.setFillColor(color.cgColor)
|
||||||
context.fill(CGRect(origin: CGPoint(x: (size.width - 2.0) / 2.0, y: size.width / 2.0), size: CGSize(width: 2.0, height: size.height - size.width / 2.0 - 1.0)))
|
context.fill(CGRect(origin: CGPoint(x: (size.width - 2.0) / 2.0, y: size.width / 2.0), size: CGSize(width: 2.0, height: size.height - size.width / 2.0 - 1.0)))
|
||||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.width)))
|
context.fillEllipse(in: CGRect(origin: CGPoint(x: floor((size.width - diameter) / 2.0), y: floor((size.width - diameter) / 2.0)), size: CGSize(width: diameter, height: diameter)))
|
||||||
context.fillEllipse(in: CGRect(origin: CGPoint(x: (size.width - 2.0) / 2.0, y: size.width + 2.0), size: CGSize(width: 2.0, height: 2.0)))
|
context.fillEllipse(in: CGRect(origin: CGPoint(x: (size.width - 2.0) / 2.0, y: size.width + 2.0), size: CGSize(width: 2.0, height: 2.0)))
|
||||||
}
|
}
|
||||||
let size = CGSize(width: 12.0, height: 12.0 + 2.0 + 2.0)
|
let size = CGSize(width: 12.0, height: 12.0 + 2.0 + 2.0)
|
||||||
@ -53,10 +53,12 @@ private func generateKnobImage(color: UIColor, inverted: Bool = false) -> UIImag
|
|||||||
public final class TextSelectionTheme {
|
public final class TextSelectionTheme {
|
||||||
public let selection: UIColor
|
public let selection: UIColor
|
||||||
public let knob: UIColor
|
public let knob: UIColor
|
||||||
|
public let knobDiameter: CGFloat
|
||||||
|
|
||||||
public init(selection: UIColor, knob: UIColor) {
|
public init(selection: UIColor, knob: UIColor, knobDiameter: CGFloat = 12.0) {
|
||||||
self.selection = selection
|
self.selection = selection
|
||||||
self.knob = knob
|
self.knob = knob
|
||||||
|
self.knobDiameter = knobDiameter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,6 +206,9 @@ public final class TextSelectionNode: ASDisplayNode {
|
|||||||
|
|
||||||
public let highlightAreaNode: ASDisplayNode
|
public let highlightAreaNode: ASDisplayNode
|
||||||
|
|
||||||
|
private var recognizer: TextSelectionGetureRecognizer?
|
||||||
|
private var displayLinkAnimator: DisplayLinkAnimator?
|
||||||
|
|
||||||
public init(theme: TextSelectionTheme, strings: PresentationStrings, textNode: TextNode, updateIsActive: @escaping (Bool) -> Void, present: @escaping (ViewController, Any?) -> Void, rootNode: ASDisplayNode, performAction: @escaping (String, TextSelectionAction) -> Void) {
|
public init(theme: TextSelectionTheme, strings: PresentationStrings, textNode: TextNode, updateIsActive: @escaping (Bool) -> Void, present: @escaping (ViewController, Any?) -> Void, rootNode: ASDisplayNode, performAction: @escaping (String, TextSelectionAction) -> Void) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
@ -214,13 +219,13 @@ public final class TextSelectionNode: ASDisplayNode {
|
|||||||
self.performAction = performAction
|
self.performAction = performAction
|
||||||
self.leftKnob = ASImageNode()
|
self.leftKnob = ASImageNode()
|
||||||
self.leftKnob.isUserInteractionEnabled = false
|
self.leftKnob.isUserInteractionEnabled = false
|
||||||
self.leftKnob.image = generateKnobImage(color: theme.knob)
|
self.leftKnob.image = generateKnobImage(color: theme.knob, diameter: theme.knobDiameter)
|
||||||
self.leftKnob.displaysAsynchronously = false
|
self.leftKnob.displaysAsynchronously = false
|
||||||
self.leftKnob.displayWithoutProcessing = true
|
self.leftKnob.displayWithoutProcessing = true
|
||||||
self.leftKnob.alpha = 0.0
|
self.leftKnob.alpha = 0.0
|
||||||
self.rightKnob = ASImageNode()
|
self.rightKnob = ASImageNode()
|
||||||
self.rightKnob.isUserInteractionEnabled = false
|
self.rightKnob.isUserInteractionEnabled = false
|
||||||
self.rightKnob.image = generateKnobImage(color: theme.knob, inverted: true)
|
self.rightKnob.image = generateKnobImage(color: theme.knob, diameter: theme.knobDiameter, inverted: true)
|
||||||
self.rightKnob.displaysAsynchronously = false
|
self.rightKnob.displaysAsynchronously = false
|
||||||
self.rightKnob.displayWithoutProcessing = true
|
self.rightKnob.displayWithoutProcessing = true
|
||||||
self.rightKnob.alpha = 0.0
|
self.rightKnob.alpha = 0.0
|
||||||
@ -255,7 +260,6 @@ public final class TextSelectionNode: ASDisplayNode {
|
|||||||
|
|
||||||
let mappedPoint = strongSelf.view.convert(point, to: strongSelf.textNode.view)
|
let mappedPoint = strongSelf.view.convert(point, to: strongSelf.textNode.view)
|
||||||
if let stringIndex = strongSelf.textNode.attributesAtPoint(mappedPoint, orNearest: true)?.0 {
|
if let stringIndex = strongSelf.textNode.attributesAtPoint(mappedPoint, orNearest: true)?.0 {
|
||||||
//let string = attributedString.string as NSString
|
|
||||||
var updatedMin = currentRange.0
|
var updatedMin = currentRange.0
|
||||||
var updatedMax = currentRange.1
|
var updatedMax = currentRange.1
|
||||||
switch knob {
|
switch knob {
|
||||||
@ -324,6 +328,7 @@ public final class TextSelectionNode: ASDisplayNode {
|
|||||||
self?.dismissSelection()
|
self?.dismissSelection()
|
||||||
self?.updateIsActive(false)
|
self?.updateIsActive(false)
|
||||||
}
|
}
|
||||||
|
self.recognizer = recognizer
|
||||||
self.view.addGestureRecognizer(recognizer)
|
self.view.addGestureRecognizer(recognizer)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,6 +342,60 @@ public final class TextSelectionNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func pretendInitiateSelection() {
|
||||||
|
guard let cachedLayout = self.textNode.cachedLayout, let attributedString = cachedLayout.attributedString else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultRange: NSRange?
|
||||||
|
let stringIndex = 0
|
||||||
|
let string = attributedString.string as NSString
|
||||||
|
|
||||||
|
let inputRange = CFRangeMake(0, string.length)
|
||||||
|
let flag = UInt(kCFStringTokenizerUnitWord)
|
||||||
|
let locale = CFLocaleCopyCurrent()
|
||||||
|
let tokenizer = CFStringTokenizerCreate(kCFAllocatorDefault, string as CFString, inputRange, flag, locale)
|
||||||
|
var tokenType = CFStringTokenizerAdvanceToNextToken(tokenizer)
|
||||||
|
|
||||||
|
while !tokenType.isEmpty {
|
||||||
|
let currentTokenRange = CFStringTokenizerGetCurrentTokenRange(tokenizer)
|
||||||
|
if currentTokenRange.location <= stringIndex && currentTokenRange.location + currentTokenRange.length > stringIndex {
|
||||||
|
resultRange = NSRange(location: currentTokenRange.location, length: currentTokenRange.length)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
tokenType = CFStringTokenizerAdvanceToNextToken(tokenizer)
|
||||||
|
}
|
||||||
|
if resultRange == nil {
|
||||||
|
resultRange = NSRange(location: stringIndex, length: 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.currentRange = resultRange.flatMap {
|
||||||
|
($0.lowerBound, $0.upperBound)
|
||||||
|
}
|
||||||
|
self.updateSelection(range: resultRange, animateIn: true)
|
||||||
|
self.updateIsActive(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func pretendExtendSelection(to index: Int) {
|
||||||
|
guard let cachedLayout = self.textNode.cachedLayout, let attributedString = cachedLayout.attributedString, let endRangeRect = cachedLayout.rangeRects(in: NSRange(location: index, length: 1))?.first else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let startPoint = self.rightKnob.frame.center
|
||||||
|
let endPoint = endRangeRect.center
|
||||||
|
let displayLinkAnimator = DisplayLinkAnimator(duration: 0.3, from: 0.0, to: 1.0, update: { [weak self] progress in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let point = CGPoint(x: (1.0 - progress) * startPoint.x + progress * endPoint.x, y: (1.0 - progress) * startPoint.y + progress * endPoint.y)
|
||||||
|
strongSelf.recognizer?.moveKnob?(.right, point)
|
||||||
|
}, completion: { [weak self] in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
self.displayLinkAnimator = displayLinkAnimator
|
||||||
|
}
|
||||||
|
|
||||||
private func updateSelection(range: NSRange?, animateIn: Bool) {
|
private func updateSelection(range: NSRange?, animateIn: Bool) {
|
||||||
var rects: [CGRect]?
|
var rects: [CGRect]?
|
||||||
|
|
||||||
@ -362,8 +421,8 @@ public final class TextSelectionNode: ASDisplayNode {
|
|||||||
highlightOverlay.frame = self.bounds
|
highlightOverlay.frame = self.bounds
|
||||||
highlightOverlay.updateRects(rects)
|
highlightOverlay.updateRects(rects)
|
||||||
if let image = self.leftKnob.image {
|
if let image = self.leftKnob.image {
|
||||||
self.leftKnob.frame = CGRect(origin: CGPoint(x: floor(rects[0].minX - 1.0 - image.size.width / 2.0), y: rects[0].minY - 1.0 - image.size.width), size: CGSize(width: image.size.width, height: image.size.width + rects[0].height + 2.0))
|
self.leftKnob.frame = CGRect(origin: CGPoint(x: floor(rects[0].minX - 1.0 - image.size.width / 2.0), y: rects[0].minY - 1.0 - self.theme.knobDiameter), size: CGSize(width: image.size.width, height: self.theme.knobDiameter + rects[0].height + 2.0))
|
||||||
self.rightKnob.frame = CGRect(origin: CGPoint(x: floor(rects[rects.count - 1].maxX + 1.0 - image.size.width / 2.0), y: rects[rects.count - 1].maxY + 1.0 - (rects[0].height + 2.0)), size: CGSize(width: image.size.width, height: image.size.width + rects[0].height + 2.0))
|
self.rightKnob.frame = CGRect(origin: CGPoint(x: floor(rects[rects.count - 1].maxX + 1.0 - image.size.width / 2.0), y: rects[rects.count - 1].maxY + 1.0 - (rects[0].height + 2.0)), size: CGSize(width: image.size.width, height: self.theme.knobDiameter + rects[0].height + 2.0))
|
||||||
}
|
}
|
||||||
if self.leftKnob.alpha.isZero {
|
if self.leftKnob.alpha.isZero {
|
||||||
highlightOverlay.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue)
|
highlightOverlay.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue)
|
||||||
|
@ -319,7 +319,7 @@ func makeBridgeMedia(message: Message, strings: PresentationStrings, chatPeer: P
|
|||||||
}
|
}
|
||||||
|
|
||||||
func makeBridgeChat(_ entry: ChatListEntry, strings: PresentationStrings) -> (TGBridgeChat, [Int64 : TGBridgeUser])? {
|
func makeBridgeChat(_ entry: ChatListEntry, strings: PresentationStrings) -> (TGBridgeChat, [Int64 : TGBridgeUser])? {
|
||||||
if case let .MessageEntry(index, message, readState, _, _, renderedPeer, _, _) = entry {
|
if case let .MessageEntry(index, message, readState, _, _, renderedPeer, _, _, hasFailed) = entry {
|
||||||
guard index.messageIndex.id.peerId.namespace != Namespaces.Peer.SecretChat else {
|
guard index.messageIndex.id.peerId.namespace != Namespaces.Peer.SecretChat else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -332,7 +332,7 @@ func makeBridgeChat(_ entry: ChatListEntry, strings: PresentationStrings) -> (TG
|
|||||||
bridgeChat.text = message.text
|
bridgeChat.text = message.text
|
||||||
bridgeChat.outgoing = !message.flags.contains(.Incoming)
|
bridgeChat.outgoing = !message.flags.contains(.Incoming)
|
||||||
bridgeChat.deliveryState = makeBridgeDeliveryState(message)
|
bridgeChat.deliveryState = makeBridgeDeliveryState(message)
|
||||||
bridgeChat.deliveryError = message.flags.contains(.Failed)
|
bridgeChat.deliveryError = hasFailed
|
||||||
bridgeChat.media = makeBridgeMedia(message: message, strings: strings, filterUnsupportedActions: false)
|
bridgeChat.media = makeBridgeMedia(message: message, strings: strings, filterUnsupportedActions: false)
|
||||||
}
|
}
|
||||||
bridgeChat.unread = readState?.isUnread ?? false
|
bridgeChat.unread = readState?.isUnread ?? false
|
||||||
|
Loading…
x
Reference in New Issue
Block a user