mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-19 20:21:26 +00:00
no message
This commit is contained in:
parent
034531e433
commit
aa5346e28a
@ -28,6 +28,8 @@
|
|||||||
D01BAA561ED1D70C00295217 /* ManagedFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01BAA541ED1D70C00295217 /* ManagedFile.swift */; };
|
D01BAA561ED1D70C00295217 /* ManagedFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01BAA541ED1D70C00295217 /* ManagedFile.swift */; };
|
||||||
D01C7EDE1EF73F71008305F1 /* MessageHistoryTextIndexTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C7EDD1EF73F71008305F1 /* MessageHistoryTextIndexTable.swift */; };
|
D01C7EDE1EF73F71008305F1 /* MessageHistoryTextIndexTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C7EDD1EF73F71008305F1 /* MessageHistoryTextIndexTable.swift */; };
|
||||||
D01C7EDF1EF73F71008305F1 /* MessageHistoryTextIndexTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C7EDD1EF73F71008305F1 /* MessageHistoryTextIndexTable.swift */; };
|
D01C7EDF1EF73F71008305F1 /* MessageHistoryTextIndexTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C7EDD1EF73F71008305F1 /* MessageHistoryTextIndexTable.swift */; };
|
||||||
|
D01C7F071EFC1ED3008305F1 /* UnorderedItemListTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C7F061EFC1ED3008305F1 /* UnorderedItemListTable.swift */; };
|
||||||
|
D01C7F081EFC1ED3008305F1 /* UnorderedItemListTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C7F061EFC1ED3008305F1 /* UnorderedItemListTable.swift */; };
|
||||||
D01F7D9B1CBEC390008765C9 /* MessageHistoryInvalidatedReadStateTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F7D9A1CBEC390008765C9 /* MessageHistoryInvalidatedReadStateTable.swift */; };
|
D01F7D9B1CBEC390008765C9 /* MessageHistoryInvalidatedReadStateTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F7D9A1CBEC390008765C9 /* MessageHistoryInvalidatedReadStateTable.swift */; };
|
||||||
D01F7D9D1CBF8586008765C9 /* SynchronizePeerReadStatesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F7D9C1CBF8586008765C9 /* SynchronizePeerReadStatesView.swift */; };
|
D01F7D9D1CBF8586008765C9 /* SynchronizePeerReadStatesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F7D9C1CBF8586008765C9 /* SynchronizePeerReadStatesView.swift */; };
|
||||||
D021E0D41DB4FAE100C6B04F /* ItemCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D021E0D31DB4FAE100C6B04F /* ItemCollection.swift */; };
|
D021E0D41DB4FAE100C6B04F /* ItemCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D021E0D31DB4FAE100C6B04F /* ItemCollection.swift */; };
|
||||||
@ -304,6 +306,7 @@
|
|||||||
D019B1CE1E2E770700F80DB3 /* MessageGloballyUniqueIdTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageGloballyUniqueIdTable.swift; sourceTree = "<group>"; };
|
D019B1CE1E2E770700F80DB3 /* MessageGloballyUniqueIdTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageGloballyUniqueIdTable.swift; sourceTree = "<group>"; };
|
||||||
D01BAA541ED1D70C00295217 /* ManagedFile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedFile.swift; sourceTree = "<group>"; };
|
D01BAA541ED1D70C00295217 /* ManagedFile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedFile.swift; sourceTree = "<group>"; };
|
||||||
D01C7EDD1EF73F71008305F1 /* MessageHistoryTextIndexTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageHistoryTextIndexTable.swift; sourceTree = "<group>"; };
|
D01C7EDD1EF73F71008305F1 /* MessageHistoryTextIndexTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageHistoryTextIndexTable.swift; sourceTree = "<group>"; };
|
||||||
|
D01C7F061EFC1ED3008305F1 /* UnorderedItemListTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnorderedItemListTable.swift; sourceTree = "<group>"; };
|
||||||
D01F7D9A1CBEC390008765C9 /* MessageHistoryInvalidatedReadStateTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageHistoryInvalidatedReadStateTable.swift; sourceTree = "<group>"; };
|
D01F7D9A1CBEC390008765C9 /* MessageHistoryInvalidatedReadStateTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageHistoryInvalidatedReadStateTable.swift; sourceTree = "<group>"; };
|
||||||
D01F7D9C1CBF8586008765C9 /* SynchronizePeerReadStatesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizePeerReadStatesView.swift; sourceTree = "<group>"; };
|
D01F7D9C1CBF8586008765C9 /* SynchronizePeerReadStatesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizePeerReadStatesView.swift; sourceTree = "<group>"; };
|
||||||
D021E0D31DB4FAE100C6B04F /* ItemCollection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemCollection.swift; sourceTree = "<group>"; };
|
D021E0D31DB4FAE100C6B04F /* ItemCollection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemCollection.swift; sourceTree = "<group>"; };
|
||||||
@ -597,6 +600,7 @@
|
|||||||
D08774FF1E3E3D9F00A97350 /* PreferencesTable.swift */,
|
D08774FF1E3E3D9F00A97350 /* PreferencesTable.swift */,
|
||||||
D0F82CFC1E4345D7007E499C /* OrderedItemListTable.swift */,
|
D0F82CFC1E4345D7007E499C /* OrderedItemListTable.swift */,
|
||||||
D0F82D0E1E43A024007E499C /* OrderedItemListIndexTable.swift */,
|
D0F82D0E1E43A024007E499C /* OrderedItemListIndexTable.swift */,
|
||||||
|
D01C7F061EFC1ED3008305F1 /* UnorderedItemListTable.swift */,
|
||||||
);
|
);
|
||||||
name = Tables;
|
name = Tables;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -932,6 +936,7 @@
|
|||||||
files = (
|
files = (
|
||||||
D050F2661E4A5B5A00988324 /* MessageGloballyUniqueIdTable.swift in Sources */,
|
D050F2661E4A5B5A00988324 /* MessageGloballyUniqueIdTable.swift in Sources */,
|
||||||
D03229EF1E6B33FD0000AF9C /* SqliteInterface.swift in Sources */,
|
D03229EF1E6B33FD0000AF9C /* SqliteInterface.swift in Sources */,
|
||||||
|
D01C7F081EFC1ED3008305F1 /* UnorderedItemListTable.swift in Sources */,
|
||||||
D050F2671E4A5B5A00988324 /* TimestampBasedMessageAttributesTable.swift in Sources */,
|
D050F2671E4A5B5A00988324 /* TimestampBasedMessageAttributesTable.swift in Sources */,
|
||||||
D050F2681E4A5B5A00988324 /* TimestampBasedMessageAttributesIndexTable.swift in Sources */,
|
D050F2681E4A5B5A00988324 /* TimestampBasedMessageAttributesIndexTable.swift in Sources */,
|
||||||
D050F2691E4A5B5A00988324 /* MultiplePeersView.swift in Sources */,
|
D050F2691E4A5B5A00988324 /* MultiplePeersView.swift in Sources */,
|
||||||
@ -1062,6 +1067,7 @@
|
|||||||
files = (
|
files = (
|
||||||
D08775061E3E3F2100A97350 /* PreferencesView.swift in Sources */,
|
D08775061E3E3F2100A97350 /* PreferencesView.swift in Sources */,
|
||||||
D03229EE1E6B33FD0000AF9C /* SqliteInterface.swift in Sources */,
|
D03229EE1E6B33FD0000AF9C /* SqliteInterface.swift in Sources */,
|
||||||
|
D01C7F071EFC1ED3008305F1 /* UnorderedItemListTable.swift in Sources */,
|
||||||
D0F9E8631C579F0200037222 /* MediaCleanupTable.swift in Sources */,
|
D0F9E8631C579F0200037222 /* MediaCleanupTable.swift in Sources */,
|
||||||
D0F3CC741DDE1EB9008148FA /* ItemCacheMetaTable.swift in Sources */,
|
D0F3CC741DDE1EB9008148FA /* ItemCacheMetaTable.swift in Sources */,
|
||||||
D08D451F1D5D2CA700A7428A /* RatingTable.swift in Sources */,
|
D08D451F1D5D2CA700A7428A /* RatingTable.swift in Sources */,
|
||||||
|
@ -63,13 +63,13 @@ public func <(lhs: ChatListEntry, rhs: ChatListEntry) -> Bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum MutableChatListEntry: Equatable {
|
enum MutableChatListEntry: Equatable {
|
||||||
case IntermediateMessageEntry(ChatListIndex, IntermediateMessage?, CombinedPeerReadState?, PeerNotificationSettings?, PeerChatListEmbeddedInterfaceState?)
|
case IntermediateMessageEntry(ChatListIndex, IntermediateMessage?, CombinedPeerReadState?, PeerChatListEmbeddedInterfaceState?)
|
||||||
case MessageEntry(ChatListIndex, Message?, CombinedPeerReadState?, PeerNotificationSettings?, PeerChatListEmbeddedInterfaceState?, RenderedPeer)
|
case MessageEntry(ChatListIndex, Message?, CombinedPeerReadState?, PeerNotificationSettings?, PeerChatListEmbeddedInterfaceState?, RenderedPeer)
|
||||||
case HoleEntry(ChatListHole)
|
case HoleEntry(ChatListHole)
|
||||||
|
|
||||||
var index: ChatListIndex {
|
var index: ChatListIndex {
|
||||||
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
|
||||||
@ -119,6 +119,50 @@ final class MutableChatListViewReplayContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func updateMessagePeers(_ message: Message, updatedPeers: [PeerId: Peer]) -> Message? {
|
||||||
|
var updated = false
|
||||||
|
for (peerId, currentPeer) in message.peers {
|
||||||
|
if let updatedPeer = updatedPeers[peerId], !arePeersEqual(currentPeer, updatedPeer) {
|
||||||
|
updated = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if updated {
|
||||||
|
var peers = SimpleDictionary<PeerId, Peer>()
|
||||||
|
for (peerId, currentPeer) in message.peers {
|
||||||
|
if let updatedPeer = updatedPeers[peerId] {
|
||||||
|
peers[peerId] = updatedPeer
|
||||||
|
} else {
|
||||||
|
peers[peerId] = currentPeer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Message(stableId: message.stableId, stableVersion: message.stableVersion, id: message.id, globallyUniqueId: message.globallyUniqueId, timestamp: message.timestamp, flags: message.flags, tags: message.tags, globalTags: message.globalTags, forwardInfo: message.forwardInfo, author: message.author, text: message.text, attributes: message.attributes, media: message.media, peers: peers, associatedMessages: message.associatedMessages, associatedMessageIds: message.associatedMessageIds)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updatedRenderedPeer(_ renderedPeer: RenderedPeer, updatedPeers: [PeerId: Peer]) -> RenderedPeer? {
|
||||||
|
var updated = false
|
||||||
|
for (peerId, currentPeer) in renderedPeer.peers {
|
||||||
|
if let updatedPeer = updatedPeers[peerId], !arePeersEqual(currentPeer, updatedPeer) {
|
||||||
|
updated = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if updated {
|
||||||
|
var peers = SimpleDictionary<PeerId, Peer>()
|
||||||
|
for (peerId, currentPeer) in renderedPeer.peers {
|
||||||
|
if let updatedPeer = updatedPeers[peerId] {
|
||||||
|
peers[peerId] = updatedPeer
|
||||||
|
} else {
|
||||||
|
peers[peerId] = currentPeer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return RenderedPeer(peerId: renderedPeer.peerId, peers: peers)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
final class MutableChatListView {
|
final class MutableChatListView {
|
||||||
fileprivate var earlier: MutableChatListEntry?
|
fileprivate var earlier: MutableChatListEntry?
|
||||||
fileprivate var later: MutableChatListEntry?
|
fileprivate var later: MutableChatListEntry?
|
||||||
@ -150,12 +194,12 @@ final class MutableChatListView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func replay(_ operations: [ChatListOperation], updatedPeerNotificationSettings: [PeerId: PeerNotificationSettings], context: MutableChatListViewReplayContext) -> Bool {
|
func replay(_ operations: [ChatListOperation], updatedPeerNotificationSettings: [PeerId: PeerNotificationSettings], updatedPeers: [PeerId: Peer], context: MutableChatListViewReplayContext) -> Bool {
|
||||||
var hasChanges = false
|
var hasChanges = false
|
||||||
for operation in operations {
|
for operation in operations {
|
||||||
switch operation {
|
switch operation {
|
||||||
case let .InsertEntry(index, message, combinedReadState, embeddedState):
|
case let .InsertEntry(index, message, combinedReadState, embeddedState):
|
||||||
if self.add(.IntermediateMessageEntry(index, message, combinedReadState, nil, embeddedState)) {
|
if self.add(.IntermediateMessageEntry(index, message, combinedReadState, embeddedState)) {
|
||||||
hasChanges = true
|
hasChanges = true
|
||||||
}
|
}
|
||||||
case let .InsertHole(index):
|
case let .InsertHole(index):
|
||||||
@ -175,14 +219,31 @@ 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 .IntermediateMessageEntry(index, message, readState, _, embeddedState):
|
case let .MessageEntry(index, message, readState, _, embeddedState, peer):
|
||||||
if let settings = updatedPeerNotificationSettings[index.messageIndex.id.peerId] {
|
var notificationSettingsPeerId = peer.peerId
|
||||||
self.entries[i] = .IntermediateMessageEntry(index, message, readState, settings, embeddedState)
|
if let peer = peer.peers[peer.peerId], let associatedPeerId = peer.associatedPeerId {
|
||||||
|
notificationSettingsPeerId = associatedPeerId
|
||||||
|
}
|
||||||
|
if let settings = updatedPeerNotificationSettings[notificationSettingsPeerId] {
|
||||||
|
self.entries[i] = .MessageEntry(index, message, readState, settings, embeddedState, peer)
|
||||||
hasChanges = true
|
hasChanges = true
|
||||||
}
|
}
|
||||||
case let .MessageEntry(index, message, readState, _, embeddedState, peer):
|
default:
|
||||||
if let settings = updatedPeerNotificationSettings[index.messageIndex.id.peerId] {
|
continue
|
||||||
self.entries[i] = .MessageEntry(index, message, readState, settings, embeddedState, peer)
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !updatedPeers.isEmpty {
|
||||||
|
for i in 0 ..< self.entries.count {
|
||||||
|
switch self.entries[i] {
|
||||||
|
case let .MessageEntry(index, message, readState, settings, embeddedState, peer):
|
||||||
|
var updatedMessage: Message?
|
||||||
|
if let message = message {
|
||||||
|
updatedMessage = updateMessagePeers(message, updatedPeers: updatedPeers)
|
||||||
|
}
|
||||||
|
let updatedPeer = updatedRenderedPeer(peer, updatedPeers: updatedPeers)
|
||||||
|
if updatedMessage != nil || updatedPeer != nil {
|
||||||
|
self.entries[i] = .MessageEntry(index, updatedMessage ?? message, readState, settings, embeddedState, updatedPeer ?? peer)
|
||||||
hasChanges = true
|
hasChanges = true
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -403,38 +464,10 @@ final class MutableChatListView {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func updatePeers(_ peers: [PeerId: Peer]) -> Bool {
|
|
||||||
let hasChanges = false
|
|
||||||
/*for i in 0 ..< self.entries.count {
|
|
||||||
switch self.entries[i] {
|
|
||||||
case let .MessageEntry(message):
|
|
||||||
var updatedAuthor: Peer?
|
|
||||||
if let author = message.author, let peer = peers[author.id] {
|
|
||||||
updatedAuthor = peer
|
|
||||||
}
|
|
||||||
|
|
||||||
for peer in message.peers {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
return hasChanges
|
|
||||||
}
|
|
||||||
|
|
||||||
func render(_ renderMessage: (IntermediateMessage) -> Message, getPeer: (PeerId) -> Peer?, getPeerNotificationSettings: (PeerId) -> PeerNotificationSettings?) {
|
func render(_ renderMessage: (IntermediateMessage) -> Message, getPeer: (PeerId) -> Peer?, getPeerNotificationSettings: (PeerId) -> PeerNotificationSettings?) {
|
||||||
for i in 0 ..< self.entries.count {
|
for i in 0 ..< self.entries.count {
|
||||||
switch self.entries[i] {
|
switch self.entries[i] {
|
||||||
case let .IntermediateMessageEntry(index, message, combinedReadState, notificationSettings, embeddedState):
|
case let .IntermediateMessageEntry(index, message, combinedReadState, embeddedState):
|
||||||
let updatedNotificationSettings: PeerNotificationSettings?
|
|
||||||
if let notificationSettings = notificationSettings {
|
|
||||||
updatedNotificationSettings = notificationSettings
|
|
||||||
} else {
|
|
||||||
updatedNotificationSettings = getPeerNotificationSettings(index.messageIndex.id.peerId)
|
|
||||||
}
|
|
||||||
let renderedMessage: Message?
|
let renderedMessage: Message?
|
||||||
if let message = message {
|
if let message = message {
|
||||||
renderedMessage = renderMessage(message)
|
renderedMessage = renderMessage(message)
|
||||||
@ -442,15 +475,20 @@ final class MutableChatListView {
|
|||||||
renderedMessage = nil
|
renderedMessage = nil
|
||||||
}
|
}
|
||||||
var peers = SimpleDictionary<PeerId, Peer>()
|
var peers = SimpleDictionary<PeerId, Peer>()
|
||||||
|
var notificationSettings: PeerNotificationSettings?
|
||||||
if let peer = getPeer(index.messageIndex.id.peerId) {
|
if let peer = getPeer(index.messageIndex.id.peerId) {
|
||||||
peers[peer.id] = peer
|
peers[peer.id] = peer
|
||||||
if let associatedPeerId = peer.associatedPeerId {
|
if let associatedPeerId = peer.associatedPeerId {
|
||||||
if let associatedPeer = getPeer(associatedPeerId) {
|
if let associatedPeer = getPeer(associatedPeerId) {
|
||||||
peers[associatedPeer.id] = associatedPeer
|
peers[associatedPeer.id] = associatedPeer
|
||||||
}
|
}
|
||||||
|
notificationSettings = getPeerNotificationSettings(associatedPeerId)
|
||||||
|
} else {
|
||||||
|
notificationSettings = getPeerNotificationSettings(index.messageIndex.id.peerId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.entries[i] = .MessageEntry(index, renderedMessage, combinedReadState, updatedNotificationSettings, embeddedState, RenderedPeer(peerId: index.messageIndex.id.peerId, peers: peers))
|
|
||||||
|
self.entries[i] = .MessageEntry(index, renderedMessage, combinedReadState, notificationSettings, embeddedState, RenderedPeer(peerId: index.messageIndex.id.peerId, peers: peers))
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -108,3 +108,19 @@ public func arePeersEqual(_ lhs: Peer?, _ rhs: Peer?) -> Bool {
|
|||||||
return (lhs != nil) == (rhs != nil)
|
return (lhs != nil) == (rhs != nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func arePeerDictionariesEqual(_ lhs: SimpleDictionary<PeerId, Peer>, _ rhs: SimpleDictionary<PeerId, Peer>) -> Bool {
|
||||||
|
if lhs.count != rhs.count {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for (id, lhsPeer) in lhs {
|
||||||
|
if let rhsPeer = rhs[id] {
|
||||||
|
if !lhsPeer.isEqual(rhsPeer) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
@ -589,6 +589,24 @@ public final class Modifier {
|
|||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func unorderedItemListDifference(tag: UnorderedItemListEntryTag, updatedEntryInfos: [ValueBoxKey: UnorderedItemListEntryInfo]) -> (metaInfo: UnorderedItemListTagMetaInfo?, added: [ValueBoxKey], removed: [UnorderedItemListEntry], updated: [UnorderedItemListEntry]) {
|
||||||
|
assert(!self.disposed)
|
||||||
|
if let postbox = self.postbox {
|
||||||
|
return postbox.unorderedItemListTable.difference(tag: tag, updatedEntryInfos: updatedEntryInfos)
|
||||||
|
} else {
|
||||||
|
return (nil, [], [], [])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func unorderedItemListApplyDifference(tag: UnorderedItemListEntryTag, previousInfo: UnorderedItemListTagMetaInfo?, updatedInfo: UnorderedItemListTagMetaInfo, setItems: [UnorderedItemListEntry], removeItemIds: [ValueBoxKey]) -> Bool {
|
||||||
|
assert(!self.disposed)
|
||||||
|
if let postbox = self.postbox {
|
||||||
|
return postbox.unorderedItemListTable.applyDifference(tag: tag, previousInfo: previousInfo, updatedInfo: updatedInfo, setItems: setItems, removeItemIds: removeItemIds)
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate class PipeNotifier: NSObject {
|
fileprivate class PipeNotifier: NSObject {
|
||||||
@ -778,6 +796,7 @@ public final class Postbox {
|
|||||||
let orderedItemListTable: OrderedItemListTable
|
let orderedItemListTable: OrderedItemListTable
|
||||||
let orderedItemListIndexTable: OrderedItemListIndexTable
|
let orderedItemListIndexTable: OrderedItemListIndexTable
|
||||||
let textIndexTable: MessageHistoryTextIndexTable
|
let textIndexTable: MessageHistoryTextIndexTable
|
||||||
|
let unorderedItemListTable: UnorderedItemListTable
|
||||||
|
|
||||||
//temporary
|
//temporary
|
||||||
let peerRatingTable: RatingTable<PeerId>
|
let peerRatingTable: RatingTable<PeerId>
|
||||||
@ -851,6 +870,7 @@ public final class Postbox {
|
|||||||
self.preferencesTable = PreferencesTable(valueBox: self.valueBox, table: PreferencesTable.tableSpec(35))
|
self.preferencesTable = PreferencesTable(valueBox: self.valueBox, table: PreferencesTable.tableSpec(35))
|
||||||
self.orderedItemListIndexTable = OrderedItemListIndexTable(valueBox: self.valueBox, table: OrderedItemListIndexTable.tableSpec(37))
|
self.orderedItemListIndexTable = OrderedItemListIndexTable(valueBox: self.valueBox, table: OrderedItemListIndexTable.tableSpec(37))
|
||||||
self.orderedItemListTable = OrderedItemListTable(valueBox: self.valueBox, table: OrderedItemListTable.tableSpec(38), indexTable: self.orderedItemListIndexTable)
|
self.orderedItemListTable = OrderedItemListTable(valueBox: self.valueBox, table: OrderedItemListTable.tableSpec(38), indexTable: self.orderedItemListIndexTable)
|
||||||
|
self.unorderedItemListTable = UnorderedItemListTable(valueBox: self.valueBox, table: UnorderedItemListTable.tableSpec(42))
|
||||||
|
|
||||||
var tables: [Table] = []
|
var tables: [Table] = []
|
||||||
tables.append(self.metadataTable)
|
tables.append(self.metadataTable)
|
||||||
@ -893,6 +913,7 @@ public final class Postbox {
|
|||||||
tables.append(self.preferencesTable)
|
tables.append(self.preferencesTable)
|
||||||
tables.append(self.orderedItemListTable)
|
tables.append(self.orderedItemListTable)
|
||||||
tables.append(self.orderedItemListIndexTable)
|
tables.append(self.orderedItemListIndexTable)
|
||||||
|
tables.append(self.unorderedItemListTable)
|
||||||
|
|
||||||
self.tables = tables
|
self.tables = tables
|
||||||
|
|
||||||
@ -1221,7 +1242,7 @@ public final class Postbox {
|
|||||||
for entry in intermediateEntries {
|
for entry in intermediateEntries {
|
||||||
switch entry {
|
switch entry {
|
||||||
case let .Message(index, message, embeddedState):
|
case let .Message(index, message, embeddedState):
|
||||||
entries.append(.IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), self.peerNotificationSettingsTable.get(index.messageIndex.id.peerId), embeddedState))
|
entries.append(.IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), embeddedState))
|
||||||
case let .Hole(hole):
|
case let .Hole(hole):
|
||||||
entries.append(.HoleEntry(hole))
|
entries.append(.HoleEntry(hole))
|
||||||
}
|
}
|
||||||
@ -1230,7 +1251,7 @@ public final class Postbox {
|
|||||||
if let intermediateLower = intermediateLower {
|
if let intermediateLower = intermediateLower {
|
||||||
switch intermediateLower {
|
switch intermediateLower {
|
||||||
case let .Message(index, message, embeddedState):
|
case let .Message(index, message, embeddedState):
|
||||||
lower = .IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), self.peerNotificationSettingsTable.get(index.messageIndex.id.peerId), embeddedState)
|
lower = .IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), embeddedState)
|
||||||
case let .Hole(hole):
|
case let .Hole(hole):
|
||||||
lower = .HoleEntry(hole)
|
lower = .HoleEntry(hole)
|
||||||
}
|
}
|
||||||
@ -1239,7 +1260,7 @@ public final class Postbox {
|
|||||||
if let intermediateUpper = intermediateUpper {
|
if let intermediateUpper = intermediateUpper {
|
||||||
switch intermediateUpper {
|
switch intermediateUpper {
|
||||||
case let .Message(index, message, embeddedState):
|
case let .Message(index, message, embeddedState):
|
||||||
upper = .IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), self.peerNotificationSettingsTable.get(index.messageIndex.id.peerId), embeddedState)
|
upper = .IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), embeddedState)
|
||||||
case let .Hole(hole):
|
case let .Hole(hole):
|
||||||
upper = .HoleEntry(hole)
|
upper = .HoleEntry(hole)
|
||||||
}
|
}
|
||||||
@ -1254,7 +1275,7 @@ public final class Postbox {
|
|||||||
for entry in intermediateEntries {
|
for entry in intermediateEntries {
|
||||||
switch entry {
|
switch entry {
|
||||||
case let .Message(index, message, embeddedState):
|
case let .Message(index, message, embeddedState):
|
||||||
entries.append(.IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), self.peerNotificationSettingsTable.get(index.messageIndex.id.peerId), embeddedState))
|
entries.append(.IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), embeddedState))
|
||||||
case let .Hole(hole):
|
case let .Hole(hole):
|
||||||
entries.append(.HoleEntry(hole))
|
entries.append(.HoleEntry(hole))
|
||||||
}
|
}
|
||||||
@ -1268,7 +1289,7 @@ public final class Postbox {
|
|||||||
for entry in intermediateEntries {
|
for entry in intermediateEntries {
|
||||||
switch entry {
|
switch entry {
|
||||||
case let .Message(index, message, embeddedState):
|
case let .Message(index, message, embeddedState):
|
||||||
entries.append(.IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), self.peerNotificationSettingsTable.get(index.messageIndex.id.peerId), embeddedState))
|
entries.append(.IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), embeddedState))
|
||||||
case let .Hole(index):
|
case let .Hole(index):
|
||||||
entries.append(.HoleEntry(index))
|
entries.append(.HoleEntry(index))
|
||||||
}
|
}
|
||||||
|
@ -95,4 +95,3 @@ public struct SimpleDictionary<K: Hashable, V>: Sequence {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
219
Postbox/UnorderedItemListTable.swift
Normal file
219
Postbox/UnorderedItemListTable.swift
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
public struct UnorderedItemListEntryInfo {
|
||||||
|
public let hashValue: Int64
|
||||||
|
|
||||||
|
public init(hashValue: Int64) {
|
||||||
|
self.hashValue = hashValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct UnorderedItemListEntry {
|
||||||
|
public let id: ValueBoxKey
|
||||||
|
public let info: UnorderedItemListEntryInfo
|
||||||
|
public let contents: Coding
|
||||||
|
|
||||||
|
public init(id: ValueBoxKey, info: UnorderedItemListEntryInfo, contents: Coding) {
|
||||||
|
self.id = id
|
||||||
|
self.info = info
|
||||||
|
self.contents = contents
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct UnorderedItemListEntryTag {
|
||||||
|
public let value: ValueBoxKey
|
||||||
|
|
||||||
|
public init(value: ValueBoxKey) {
|
||||||
|
self.value = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public protocol UnorderedItemListTagMetaInfo: Coding {
|
||||||
|
func isEqual(to: UnorderedItemListTagMetaInfo) -> Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum UnorderedItemListTableKeyspace: UInt8 {
|
||||||
|
case metaInfo = 0
|
||||||
|
case entries = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
private func extractEntryKey(tagLength: Int, key: ValueBoxKey) -> ValueBoxKey {
|
||||||
|
let result = ValueBoxKey(length: key.length - tagLength - 1)
|
||||||
|
memcpy(result.memory, key.memory.advanced(by: 1 + tagLength), result.length)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private func extractEntryInfo(_ value: ReadBuffer) -> UnorderedItemListEntryInfo {
|
||||||
|
var hashValue: Int64 = 0
|
||||||
|
value.read(&hashValue, offset: 0, length: 8)
|
||||||
|
return UnorderedItemListEntryInfo(hashValue: hashValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
final class UnorderedItemListTable: Table {
|
||||||
|
static func tableSpec(_ id: Int32) -> ValueBoxTable {
|
||||||
|
return ValueBoxTable(id: id, keyType: .binary)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func metaInfoKey(tag: UnorderedItemListEntryTag) -> ValueBoxKey {
|
||||||
|
let tagValue = tag.value
|
||||||
|
let key = ValueBoxKey(length: 1 + tagValue.length)
|
||||||
|
key.setUInt8(0, value: UnorderedItemListTableKeyspace.metaInfo.rawValue)
|
||||||
|
memcpy(key.memory.advanced(by: 1), tagValue.memory, tagValue.length)
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
|
private func entryKey(tag: UnorderedItemListEntryTag, id: ValueBoxKey) -> ValueBoxKey {
|
||||||
|
let tagValue = tag.value
|
||||||
|
let key = ValueBoxKey(length: 1 + tagValue.length + id.length)
|
||||||
|
key.setUInt8(0, value: UnorderedItemListTableKeyspace.entries.rawValue)
|
||||||
|
memcpy(key.memory.advanced(by: 1), tagValue.memory, tagValue.length)
|
||||||
|
memcpy(key.memory.advanced(by: 1 + tagValue.length), id.memory, id.length)
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
|
private func entryLowerBoundKey(tag: UnorderedItemListEntryTag) -> ValueBoxKey {
|
||||||
|
let tagValue = tag.value
|
||||||
|
let key = ValueBoxKey(length: 1 + tagValue.length)
|
||||||
|
key.setUInt8(0, value: UnorderedItemListTableKeyspace.entries.rawValue)
|
||||||
|
memcpy(key.memory.advanced(by: 1), tagValue.memory, tagValue.length)
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
|
private func entryUpperBoundKey(tag: UnorderedItemListEntryTag) -> ValueBoxKey {
|
||||||
|
let tagValue = tag.value.successor
|
||||||
|
let key = ValueBoxKey(length: 1 + tagValue.length)
|
||||||
|
key.setUInt8(0, value: UnorderedItemListTableKeyspace.entries.rawValue)
|
||||||
|
memcpy(key.memory.advanced(by: 1), tagValue.memory, tagValue.length)
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
|
private func getMetaInfo(tag: UnorderedItemListEntryTag) -> UnorderedItemListTagMetaInfo? {
|
||||||
|
if let value = self.valueBox.get(self.table, key: self.metaInfoKey(tag: tag)), let info = Decoder(buffer: value).decodeRootObject() as? UnorderedItemListTagMetaInfo {
|
||||||
|
return info
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func setMetaInfo(tag: UnorderedItemListEntryTag, info: UnorderedItemListTagMetaInfo) {
|
||||||
|
let encoder = Encoder()
|
||||||
|
encoder.encodeRootObject(info)
|
||||||
|
self.valueBox.set(self.table, key: self.metaInfoKey(tag: tag), value: encoder.readBufferNoCopy())
|
||||||
|
}
|
||||||
|
|
||||||
|
private func getEntryInfos(tag: UnorderedItemListEntryTag) -> [ValueBoxKey: UnorderedItemListEntryInfo] {
|
||||||
|
var result: [ValueBoxKey: UnorderedItemListEntryInfo] = [:]
|
||||||
|
let tagLength = tag.value.length
|
||||||
|
self.valueBox.range(self.table, start: self.entryLowerBoundKey(tag: tag), end: self.entryUpperBoundKey(tag: tag), values: { key, value in
|
||||||
|
result[extractEntryKey(tagLength: tagLength, key: key)] = extractEntryInfo(value)
|
||||||
|
return true
|
||||||
|
}, limit: 0)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private func getEntry(tag: UnorderedItemListEntryTag, id: ValueBoxKey) -> UnorderedItemListEntry? {
|
||||||
|
if let value = self.valueBox.get(self.table, key: self.entryKey(tag: tag, id: id)) {
|
||||||
|
var hashValue: Int64 = 0
|
||||||
|
value.read(&hashValue, offset: 0, length: 8)
|
||||||
|
let tempBuffer = MemoryBuffer(memory: value.memory.advanced(by: 8), capacity: value.length - 8, length: value.length - 8, freeWhenDone: false)
|
||||||
|
let contents = withExtendedLifetime(tempBuffer, {
|
||||||
|
return Decoder(buffer: tempBuffer).decodeRootObject()
|
||||||
|
})
|
||||||
|
if let contents = contents {
|
||||||
|
let entry = UnorderedItemListEntry(id: id, info: UnorderedItemListEntryInfo(hashValue: hashValue), contents: contents)
|
||||||
|
return entry
|
||||||
|
} else {
|
||||||
|
assertionFailure()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func setEntry(tag: UnorderedItemListEntryTag, entry: UnorderedItemListEntry, sharedBuffer: WriteBuffer, sharedEncoder: Encoder) {
|
||||||
|
sharedBuffer.reset()
|
||||||
|
sharedEncoder.reset()
|
||||||
|
|
||||||
|
var hashValue: Int64 = entry.info.hashValue
|
||||||
|
sharedBuffer.write(&hashValue, offset: 0, length: 8)
|
||||||
|
|
||||||
|
sharedEncoder.encodeRootObject(entry.contents)
|
||||||
|
let tempBuffer = sharedEncoder.readBufferNoCopy()
|
||||||
|
withExtendedLifetime(tempBuffer, {
|
||||||
|
sharedBuffer.write(tempBuffer.memory, offset: 0, length: tempBuffer.length)
|
||||||
|
})
|
||||||
|
|
||||||
|
self.valueBox.set(self.table, key: self.entryKey(tag: tag, id: entry.id), value: sharedBuffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func difference(tag: UnorderedItemListEntryTag, updatedEntryInfos: [ValueBoxKey: UnorderedItemListEntryInfo]) -> (metaInfo: UnorderedItemListTagMetaInfo?, added: [ValueBoxKey], removed: [UnorderedItemListEntry], updated: [UnorderedItemListEntry]) {
|
||||||
|
let currentEntryInfos = self.getEntryInfos(tag: tag)
|
||||||
|
var currentInfoIds = Set<ValueBoxKey>()
|
||||||
|
for key in currentEntryInfos.keys {
|
||||||
|
currentInfoIds.insert(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
var updatedInfoIds = Set<ValueBoxKey>()
|
||||||
|
for key in updatedEntryInfos.keys {
|
||||||
|
updatedInfoIds.insert(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
let addedKeys = updatedInfoIds.subtracting(currentInfoIds)
|
||||||
|
let added: [ValueBoxKey] = Array(addedKeys)
|
||||||
|
|
||||||
|
let removedKeys = currentInfoIds.subtracting(updatedInfoIds)
|
||||||
|
var removed: [UnorderedItemListEntry] = []
|
||||||
|
for key in removedKeys {
|
||||||
|
if let entry = self.getEntry(tag: tag, id: key) {
|
||||||
|
removed.append(entry)
|
||||||
|
} else {
|
||||||
|
assertionFailure()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var updated: [UnorderedItemListEntry] = []
|
||||||
|
for (key, info) in updatedEntryInfos {
|
||||||
|
if !addedKeys.contains(key) {
|
||||||
|
if let currentInfo = currentEntryInfos[key] {
|
||||||
|
if info.hashValue != currentInfo.hashValue {
|
||||||
|
if let entry = self.getEntry(tag: tag, id: key) {
|
||||||
|
updated.append(entry)
|
||||||
|
} else {
|
||||||
|
assertionFailure()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assertionFailure()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (self.getMetaInfo(tag: tag), added, removed, updated)
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyDifference(tag: UnorderedItemListEntryTag, previousInfo: UnorderedItemListTagMetaInfo?, updatedInfo: UnorderedItemListTagMetaInfo, setItems: [UnorderedItemListEntry], removeItemIds: [ValueBoxKey]) -> Bool {
|
||||||
|
let currentInfo = self.getMetaInfo(tag: tag)
|
||||||
|
if let currentInfo = currentInfo, let previousInfo = previousInfo {
|
||||||
|
if !currentInfo.isEqual(to: previousInfo) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else if (currentInfo != nil) != (previousInfo != nil) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
self.setMetaInfo(tag: tag, info: updatedInfo)
|
||||||
|
|
||||||
|
let sharedBuffer = WriteBuffer()
|
||||||
|
let sharedEncoder = Encoder()
|
||||||
|
for entry in setItems {
|
||||||
|
self.setEntry(tag: tag, entry: entry, sharedBuffer: sharedBuffer, sharedEncoder: sharedEncoder)
|
||||||
|
}
|
||||||
|
|
||||||
|
for id in removeItemIds {
|
||||||
|
self.valueBox.remove(self.table, key: self.entryKey(tag: tag, id: id))
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
@ -190,6 +190,14 @@ public struct ValueBoxKey: Hashable, CustomStringConvertible, Comparable {
|
|||||||
return string as String
|
return string as String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var stringValue: String {
|
||||||
|
if let string = String(data: Data(bytes: self.memory, count: self.length), encoding: .utf8) {
|
||||||
|
return string
|
||||||
|
} else {
|
||||||
|
return "<unavailable>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public var hashValue: Int {
|
public var hashValue: Int {
|
||||||
var hash = 37
|
var hash = 37
|
||||||
let bytes = self.memory.assumingMemoryBound(to: Int8.self)
|
let bytes = self.memory.assumingMemoryBound(to: Int8.self)
|
||||||
|
@ -400,10 +400,10 @@ final class ViewTracker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !transaction.chatListOperations.isEmpty || !transaction.currentUpdatedPeerNotificationSettings.isEmpty {
|
if !transaction.chatListOperations.isEmpty || !transaction.currentUpdatedPeerNotificationSettings.isEmpty || !transaction.currentUpdatedPeers.isEmpty {
|
||||||
for (mutableView, pipe) in self.chatListViews.copyItems() {
|
for (mutableView, pipe) in self.chatListViews.copyItems() {
|
||||||
let context = MutableChatListViewReplayContext()
|
let context = MutableChatListViewReplayContext()
|
||||||
if mutableView.replay(transaction.chatListOperations, updatedPeerNotificationSettings: transaction.currentUpdatedPeerNotificationSettings, context: context) {
|
if mutableView.replay(transaction.chatListOperations, updatedPeerNotificationSettings: transaction.currentUpdatedPeerNotificationSettings, updatedPeers: transaction.currentUpdatedPeers, context: context) {
|
||||||
mutableView.complete(context: context, fetchEarlier: self.fetchEarlierChatEntries, fetchLater: self.fetchLaterChatEntries)
|
mutableView.complete(context: context, fetchEarlier: self.fetchEarlierChatEntries, fetchLater: self.fetchLaterChatEntries)
|
||||||
mutableView.render(self.renderMessage, getPeer: { id in
|
mutableView.render(self.renderMessage, getPeer: { id in
|
||||||
return self.getPeer(id)
|
return self.getPeer(id)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user