mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-18 19:40:19 +00:00
760 lines
33 KiB
Swift
760 lines
33 KiB
Swift
import Foundation
|
|
|
|
private enum MessageOfInterestLocation: Equatable {
|
|
case id(MessageId)
|
|
case index(MessageIndex)
|
|
|
|
static func ==(lhs: MessageOfInterestLocation, rhs: MessageOfInterestLocation) -> Bool {
|
|
switch lhs {
|
|
case let .id(value):
|
|
if case .id(value) = rhs {
|
|
return true
|
|
} else {
|
|
return false
|
|
}
|
|
case let .index(value):
|
|
if case .index(value) = rhs {
|
|
return true
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private func getAnchorId(postbox: Postbox, location: MessageOfInterestViewLocation, namespace: MessageId.Namespace) -> MessageOfInterestLocation? {
|
|
switch location {
|
|
case let .peer(peerId):
|
|
if let readState = postbox.readStateTable.getCombinedState(peerId) {
|
|
loop: for (stateNamespace, state) in readState.states {
|
|
if stateNamespace == namespace {
|
|
if case let .idBased(maxIncomingReadId, _, _, _, _) = state {
|
|
return .id(MessageId(peerId: peerId, namespace: namespace, id: maxIncomingReadId))
|
|
}
|
|
break loop
|
|
}
|
|
}
|
|
}
|
|
case let .group(groupId):
|
|
if let state = postbox.groupFeedReadStateTable.get(groupId) {
|
|
return .index(state.maxReadIndex)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
private struct HolesViewEntryHole {
|
|
let hole: MessageHistoryHole
|
|
let lowerIndex: MessageIndex?
|
|
}
|
|
|
|
private enum HolesViewEntryMedia {
|
|
case media(authorId: PeerId?, [Media])
|
|
case intermediate(authorId: PeerId?, [MediaId], ReadBuffer)
|
|
}
|
|
|
|
public struct HolesViewMedia: Comparable {
|
|
public let media: Media
|
|
public let peer: Peer
|
|
public let authorIsContact: Bool
|
|
public let index: MessageIndex
|
|
|
|
public static func ==(lhs: HolesViewMedia, rhs: HolesViewMedia) -> Bool {
|
|
return lhs.index == rhs.index && (lhs.media === rhs.media || lhs.media.isEqual(to: rhs.media)) && lhs.peer.isEqual(rhs.peer) && lhs.authorIsContact == rhs.authorIsContact
|
|
}
|
|
|
|
public static func <(lhs: HolesViewMedia, rhs: HolesViewMedia) -> Bool {
|
|
return lhs.index < rhs.index
|
|
}
|
|
}
|
|
|
|
private struct HolesViewEntry {
|
|
let index: MessageIndex
|
|
let hole: HolesViewEntryHole?
|
|
var media: HolesViewEntryMedia?
|
|
|
|
init(index: MessageIndex, hole: HolesViewEntryHole?, media: HolesViewEntryMedia?) {
|
|
self.index = index
|
|
self.hole = hole
|
|
self.media = media
|
|
}
|
|
|
|
init(_ entry: IntermediateMessageHistoryEntry) {
|
|
switch entry {
|
|
case let .Message(message):
|
|
self.index = MessageIndex(message)
|
|
self.hole = nil
|
|
self.media = .intermediate(authorId: message.authorId, message.referencedMedia, message.embeddedMediaData)
|
|
case let .Hole(hole, lowerIndex):
|
|
self.index = hole.maxIndex
|
|
self.hole = HolesViewEntryHole(hole: hole, lowerIndex: lowerIndex)
|
|
self.media = nil
|
|
}
|
|
}
|
|
}
|
|
|
|
private func entriesFromIndexEntries(entries: [HistoryIndexEntry], postbox: Postbox) -> [HolesViewEntry] {
|
|
return entries.compactMap { entry -> HolesViewEntry? in
|
|
switch entry {
|
|
case let .Message(index):
|
|
guard let message = postbox.messageHistoryTable.getMessage(entry.index) else {
|
|
return nil
|
|
}
|
|
return HolesViewEntry(index: index, hole: nil, media: .intermediate(authorId: message.authorId, message.referencedMedia, message.embeddedMediaData))
|
|
case let .Hole(hole):
|
|
return HolesViewEntry(index: hole.maxIndex, hole: HolesViewEntryHole(hole: hole, lowerIndex: nil), media: nil)
|
|
}
|
|
}
|
|
}
|
|
|
|
private func fetchEntries(postbox: Postbox, location: MessageOfInterestViewLocation, anchor: MessageOfInterestLocation, count: Int) -> (entries: [HolesViewEntry], earlier: MessageIndex?, later: MessageIndex?) {
|
|
switch location {
|
|
case let .peer(peerId):
|
|
switch anchor {
|
|
case let .id(id):
|
|
assert(peerId == id.peerId)
|
|
let (entries, earlier, later) = postbox.messageHistoryIndexTable.entriesAround(id: id, count: count)
|
|
return (entriesFromIndexEntries(entries: entries, postbox: postbox), earlier?.index, later?.index)
|
|
case let .index(index):
|
|
assert(peerId == index.id.peerId)
|
|
let (entries, earlier, later) = postbox.messageHistoryIndexTable.entriesAround(id: index.id, count: count)
|
|
return (entriesFromIndexEntries(entries: entries, postbox: postbox), earlier?.index, later?.index)
|
|
}
|
|
case let .group(groupId):
|
|
switch anchor {
|
|
case let .index(index):
|
|
let (entries, earlier, later) = postbox.groupFeedIndexTable.entriesAround(groupId: groupId, index: index, count: count, messageHistoryTable: postbox.messageHistoryTable)
|
|
return (entries.map(HolesViewEntry.init), earlier?.index, later?.index)
|
|
default:
|
|
assertionFailure()
|
|
return ([], nil, nil)
|
|
}
|
|
}
|
|
}
|
|
|
|
private func fetchLater(postbox: Postbox, location: MessageOfInterestViewLocation, anchor: MessageOfInterestLocation, count: Int) -> [HolesViewEntry] {
|
|
switch location {
|
|
case let .peer(peerId):
|
|
switch anchor {
|
|
case let .id(id):
|
|
assert(id.peerId == peerId)
|
|
return entriesFromIndexEntries(entries: postbox.messageHistoryIndexTable.laterEntries(id: id, count: count), postbox: postbox)
|
|
case let .index(index):
|
|
assert(index.id.peerId == peerId)
|
|
return entriesFromIndexEntries(entries: postbox.messageHistoryIndexTable.laterEntries(id: index.id, count: count), postbox: postbox)
|
|
}
|
|
case let .group(groupId):
|
|
switch anchor {
|
|
case let .index(index):
|
|
return postbox.groupFeedIndexTable.laterEntries(groupId: groupId, index: index, count: count, messageHistoryTable: postbox.messageHistoryTable).map(HolesViewEntry.init)
|
|
default:
|
|
assertionFailure()
|
|
return []
|
|
}
|
|
}
|
|
}
|
|
|
|
private func fetchEarlier(postbox: Postbox, location: MessageOfInterestViewLocation, anchor: MessageOfInterestLocation, count: Int) -> [HolesViewEntry] {
|
|
switch location {
|
|
case let .peer(peerId):
|
|
switch anchor {
|
|
case let .id(id):
|
|
assert(id.peerId == peerId)
|
|
return entriesFromIndexEntries(entries: postbox.messageHistoryIndexTable.earlierEntries(id: id, count: count), postbox: postbox)
|
|
case let .index(index):
|
|
assert(index.id.peerId == peerId)
|
|
return entriesFromIndexEntries(entries: postbox.messageHistoryIndexTable.earlierEntries(id: index.id, count: count), postbox: postbox)
|
|
}
|
|
case let .group(groupId):
|
|
switch anchor {
|
|
case let .index(index):
|
|
return postbox.groupFeedIndexTable.earlierEntries(groupId: groupId, index: index, count: count, messageHistoryTable: postbox.messageHistoryTable).map(HolesViewEntry.init)
|
|
default:
|
|
assertionFailure()
|
|
return []
|
|
}
|
|
}
|
|
}
|
|
|
|
public struct MessageOfInterestHole: Hashable, Equatable {
|
|
public let hole: MessageHistoryViewHole
|
|
public let direction: MessageHistoryViewRelativeHoleDirection
|
|
|
|
public static func ==(lhs: MessageOfInterestHole, rhs: MessageOfInterestHole) -> Bool {
|
|
return lhs.hole == rhs.hole && lhs.direction == rhs.direction
|
|
}
|
|
|
|
public var hashValue: Int {
|
|
return self.hole.hashValue
|
|
}
|
|
}
|
|
|
|
public enum MessageOfInterestViewLocation: Hashable {
|
|
case peer(PeerId)
|
|
case group(PeerGroupId)
|
|
|
|
public static func ==(lhs: MessageOfInterestViewLocation, rhs: MessageOfInterestViewLocation) -> Bool {
|
|
switch lhs {
|
|
case let .peer(value):
|
|
if case .peer(value) = rhs {
|
|
return true
|
|
} else {
|
|
return false
|
|
}
|
|
case let .group(value):
|
|
if case .group(value) = rhs {
|
|
return true
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
public var hashValue: Int {
|
|
switch self {
|
|
case let .peer(id):
|
|
return id.hashValue
|
|
case let .group(id):
|
|
return id.hashValue
|
|
}
|
|
}
|
|
}
|
|
|
|
private func isGreaterOrEqual(index: MessageIndex, than location: MessageOfInterestLocation) -> Bool {
|
|
switch location {
|
|
case let .id(id):
|
|
return index.id >= id
|
|
case let .index(locationIndex):
|
|
return index >= locationIndex
|
|
}
|
|
}
|
|
|
|
final class MutableMessageOfInterestHolesView: MutablePostboxView {
|
|
private let location: MessageOfInterestViewLocation
|
|
private let namespace: MessageId.Namespace
|
|
private let count: Int
|
|
|
|
private var anchorLocation: MessageOfInterestLocation?
|
|
|
|
private var earlier: MessageIndex?
|
|
private var later: MessageIndex?
|
|
private var entries: [HolesViewEntry] = []
|
|
|
|
fileprivate var closestHole: MessageOfInterestHole?
|
|
fileprivate var closestLaterMedia: [HolesViewMedia] = []
|
|
|
|
init(postbox: Postbox, location: MessageOfInterestViewLocation, namespace: MessageId.Namespace, count: Int) {
|
|
self.location = location
|
|
self.namespace = namespace
|
|
self.count = count
|
|
self.anchorLocation = getAnchorId(postbox: postbox, location: self.location, namespace: self.namespace)
|
|
if let anchorLocation = self.anchorLocation {
|
|
let (entries, earlier, later) = fetchEntries(postbox: postbox, location: self.location, anchor: anchorLocation, count: self.count)
|
|
self.entries = entries
|
|
self.earlier = earlier
|
|
self.later = later
|
|
|
|
self.closestHole = self.firstHole()
|
|
self.closestLaterMedia = self.topLaterMedia(postbox: postbox)
|
|
}
|
|
}
|
|
|
|
func replay(postbox: Postbox, transaction: PostboxTransaction) -> Bool {
|
|
var updated = false
|
|
|
|
var anchorUpdated = false
|
|
switch self.location {
|
|
case let .peer(peerId):
|
|
if transaction.alteredInitialPeerCombinedReadStates[peerId] != nil {
|
|
let anchorLocation = getAnchorId(postbox: postbox, location: self.location, namespace: self.namespace)
|
|
if self.anchorLocation != anchorLocation {
|
|
self.anchorLocation = anchorLocation
|
|
anchorUpdated = true
|
|
}
|
|
}
|
|
case let .group(groupId):
|
|
if transaction.currentGroupFeedReadStateContext.updatedStates[groupId] != nil {
|
|
let anchorLocation = getAnchorId(postbox: postbox, location: self.location, namespace: self.namespace)
|
|
if self.anchorLocation != anchorLocation {
|
|
self.anchorLocation = anchorLocation
|
|
anchorUpdated = true
|
|
}
|
|
}
|
|
}
|
|
if anchorUpdated {
|
|
if let anchorLocation = self.anchorLocation {
|
|
let (entries, earlier, later) = fetchEntries(postbox: postbox, location: self.location, anchor: anchorLocation, count: self.count)
|
|
self.entries = entries
|
|
self.earlier = earlier
|
|
self.later = later
|
|
} else {
|
|
self.entries = []
|
|
self.earlier = nil
|
|
self.later = nil
|
|
}
|
|
updated = true
|
|
} else {
|
|
var invalidEarlier = false
|
|
var invalidLater = false
|
|
var removedEntries = false
|
|
var hasChanges = false
|
|
|
|
switch self.location {
|
|
case let .peer(peerId):
|
|
if let operations = transaction.currentOperationsByPeerId[peerId] {
|
|
for operation in operations {
|
|
switch operation {
|
|
case let .InsertHole(hole):
|
|
if hole.id.namespace == self.namespace {
|
|
if self.add(HolesViewEntry(index: hole.maxIndex, hole: HolesViewEntryHole(hole: hole, lowerIndex: nil), media: nil)) {
|
|
hasChanges = true
|
|
}
|
|
}
|
|
case let .InsertMessage(intermediateMessage):
|
|
if intermediateMessage.id.namespace == self.namespace {
|
|
if self.add(HolesViewEntry(index: MessageIndex(intermediateMessage), hole: nil, media: .intermediate(authorId: intermediateMessage.authorId, intermediateMessage.referencedMedia, intermediateMessage.embeddedMediaData))) {
|
|
hasChanges = true
|
|
}
|
|
}
|
|
case let .UpdateEmbeddedMedia(index, embeddedMedia):
|
|
break
|
|
case let .Remove(indices):
|
|
if self.remove(indices, invalidEarlier: &invalidEarlier, invalidLater: &invalidLater, removedEntries: &removedEntries) {
|
|
hasChanges = true
|
|
}
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
}
|
|
case let .group(groupId):
|
|
if let operations = transaction.currentGroupFeedOperations[groupId] {
|
|
for operation in operations {
|
|
switch operation {
|
|
case let .insertMessage(message):
|
|
if self.add(HolesViewEntry(index: MessageIndex(message), hole: nil, media: .intermediate(authorId: message.authorId, message.referencedMedia, message.embeddedMediaData))) {
|
|
hasChanges = true
|
|
}
|
|
case let .insertHole(hole, lowerIndex):
|
|
if self.add(HolesViewEntry(index: hole.maxIndex, hole: HolesViewEntryHole(hole: hole, lowerIndex: lowerIndex), media: nil)) {
|
|
hasChanges = true
|
|
}
|
|
case let .removeMessage(index):
|
|
if self.remove([(index, false, [])], invalidEarlier: &invalidEarlier, invalidLater: &invalidLater, removedEntries: &removedEntries) {
|
|
hasChanges = true
|
|
}
|
|
case let .removeHole(index):
|
|
if self.remove([(index, false, [])], invalidEarlier: &invalidEarlier, invalidLater: &invalidLater, removedEntries: &removedEntries) {
|
|
hasChanges = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if hasChanges {
|
|
updated = true
|
|
|
|
if let anchorLocation = self.anchorLocation {
|
|
if removedEntries && self.entries.count < self.count {
|
|
if self.entries.count == 0 {
|
|
let (entries, earlier, later) = fetchEntries(postbox: postbox, location: self.location, anchor: anchorLocation, count: self.count)
|
|
self.entries = entries
|
|
self.earlier = earlier
|
|
self.later = later
|
|
} else {
|
|
let fetchedLaterEntries = fetchLater(postbox: postbox, location: self.location, anchor: .index(self.entries.last!.index), count: self.count + 1)
|
|
self.entries.append(contentsOf: fetchedLaterEntries)
|
|
|
|
let fetchedEarlierEntries = fetchEarlier(postbox: postbox, location: self.location, anchor: .index(self.entries[0].index), count: self.count + 1)
|
|
for entry in fetchedEarlierEntries {
|
|
self.entries.insert(entry, at: 0)
|
|
}
|
|
}
|
|
}
|
|
|
|
var centerIndex: Int?
|
|
|
|
for i in 0 ..< self.entries.count {
|
|
if isGreaterOrEqual(index: self.entries[i].index, than: anchorLocation) {
|
|
centerIndex = i
|
|
break
|
|
}
|
|
}
|
|
|
|
if let centerIndex = centerIndex {
|
|
var minIndex = centerIndex
|
|
var maxIndex = centerIndex
|
|
let upperBound = self.entries.count - 1
|
|
var count = 1
|
|
while true {
|
|
if minIndex != 0 {
|
|
minIndex -= 1
|
|
count += 1
|
|
}
|
|
if count >= self.count {
|
|
break
|
|
}
|
|
if maxIndex != upperBound {
|
|
maxIndex += 1
|
|
count += 1
|
|
}
|
|
if count >= self.count {
|
|
break
|
|
}
|
|
if minIndex == 0 && maxIndex == upperBound {
|
|
break
|
|
}
|
|
}
|
|
if maxIndex != upperBound {
|
|
self.later = self.entries[maxIndex + 1].index
|
|
invalidLater = false
|
|
self.entries.removeLast(upperBound - maxIndex)
|
|
} else {
|
|
invalidLater = true
|
|
}
|
|
if minIndex != 0 {
|
|
self.earlier = self.entries[minIndex - 1].index
|
|
invalidEarlier = false
|
|
self.entries.removeFirst(minIndex)
|
|
} else {
|
|
invalidEarlier = true
|
|
}
|
|
}
|
|
|
|
if invalidEarlier {
|
|
if !self.entries.isEmpty {
|
|
let earlyIndex = self.entries[0].index
|
|
self.earlier = fetchEarlier(postbox: postbox, location: self.location, anchor: .index(earlyIndex), count: 1).first?.index
|
|
} else {
|
|
self.earlier = nil
|
|
}
|
|
}
|
|
|
|
if invalidLater {
|
|
if !self.entries.isEmpty {
|
|
let lateIndex = self.entries.last!.index
|
|
self.later = fetchLater(postbox: postbox, location: self.location, anchor: .index(lateIndex), count: 1).first?.index
|
|
} else {
|
|
self.later = nil
|
|
}
|
|
}
|
|
} else {
|
|
self.entries = []
|
|
self.earlier = nil
|
|
self.later = nil
|
|
}
|
|
}
|
|
}
|
|
|
|
if updated {
|
|
var updatedResult = false
|
|
let closestHole = self.firstHole()
|
|
if closestHole != self.closestHole {
|
|
self.closestHole = closestHole
|
|
updatedResult = true
|
|
}
|
|
|
|
let closestLaterMedia = self.topLaterMedia(postbox: postbox)
|
|
updatedResult = true
|
|
if closestLaterMedia.count != self.closestLaterMedia.count {
|
|
updatedResult = true
|
|
} else {
|
|
for i in 0 ..< closestLaterMedia.count {
|
|
if closestLaterMedia[i] != self.closestLaterMedia[i] {
|
|
updatedResult = true
|
|
break
|
|
}
|
|
}
|
|
}
|
|
self.closestLaterMedia = closestLaterMedia
|
|
|
|
return updatedResult
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
|
|
private func topLaterMedia(postbox: Postbox) -> [HolesViewMedia] {
|
|
guard let anchorLocation = self.anchorLocation else {
|
|
return []
|
|
}
|
|
let index: MessageIndex
|
|
switch anchorLocation {
|
|
case let .id(id):
|
|
guard let anchorIndex = postbox.messageHistoryTable.anchorIndex(id) else {
|
|
return []
|
|
}
|
|
switch anchorIndex {
|
|
case let .message(value, _):
|
|
index = value
|
|
case .lowerBound:
|
|
index = MessageIndex.lowerBound(peerId: id.peerId)
|
|
case .upperBound:
|
|
index = MessageIndex.upperBound(peerId: id.peerId)
|
|
}
|
|
case let .index(value):
|
|
index = value
|
|
}
|
|
var result: [HolesViewMedia] = []
|
|
for i in 0 ..< self.entries.count {
|
|
let entry = self.entries[i]
|
|
guard entry.index > index, let media = entry.media else {
|
|
continue
|
|
}
|
|
switch media {
|
|
case let .media(authorId, media):
|
|
for m in media {
|
|
if m.id != nil, let peer = postbox.peerTable.get(index.id.peerId) {
|
|
var isContact = false
|
|
if let authorId = authorId {
|
|
isContact = postbox.contactsTable.isContact(peerId: authorId)
|
|
}
|
|
result.append(HolesViewMedia(media: m, peer: peer, authorIsContact: isContact, index: index))
|
|
}
|
|
}
|
|
case let .intermediate(authorId, ids, data):
|
|
if ids.isEmpty && data.length <= 4 {
|
|
continue
|
|
}
|
|
var itemMedia: [Media] = []
|
|
for item in postbox.messageHistoryTable.renderMessageMedia(referencedMedia: ids, embeddedMediaData: data) {
|
|
if item.id != nil, let peer = postbox.peerTable.get(index.id.peerId) {
|
|
var isContact = false
|
|
if let authorId = authorId {
|
|
isContact = postbox.contactsTable.isContact(peerId: authorId)
|
|
}
|
|
result.append(HolesViewMedia(media: item, peer: peer, authorIsContact: isContact, index: entry.index))
|
|
itemMedia.append(item)
|
|
}
|
|
}
|
|
if itemMedia.isEmpty {
|
|
entries[i].media = nil
|
|
} else {
|
|
entries[i].media = .media(authorId: authorId, itemMedia)
|
|
}
|
|
}
|
|
|
|
if result.count >= 3 {
|
|
break
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
private func add(_ entry: HolesViewEntry) -> Bool {
|
|
let updated: Bool
|
|
|
|
if self.entries.count == 0 {
|
|
self.entries.append(entry)
|
|
updated = true
|
|
} else {
|
|
let latestIndex = self.entries[self.entries.count - 1].index
|
|
let earliestIndex = self.entries[0].index
|
|
|
|
let index = entry.index
|
|
|
|
if index < earliestIndex {
|
|
if self.earlier == nil || self.earlier! < index {
|
|
self.entries.insert(entry, at: 0)
|
|
updated = true
|
|
} else {
|
|
updated = false
|
|
}
|
|
} else if index > latestIndex {
|
|
if let later = self.later {
|
|
if index < later {
|
|
self.entries.append(entry)
|
|
updated = true
|
|
} else {
|
|
updated = false
|
|
}
|
|
} else {
|
|
self.entries.append(entry)
|
|
updated = true
|
|
}
|
|
} else if index != earliestIndex && index != latestIndex {
|
|
var i = self.entries.count
|
|
while i >= 1 {
|
|
if self.entries[i - 1].index < index {
|
|
break
|
|
}
|
|
i -= 1
|
|
}
|
|
self.entries.insert(entry, at: i)
|
|
updated = true
|
|
} else {
|
|
updated = false
|
|
}
|
|
}
|
|
|
|
return updated
|
|
}
|
|
|
|
private func remove(_ indicesAndFlags: [(MessageIndex, Bool, MessageTags)], invalidEarlier: inout Bool, invalidLater: inout Bool, removedEntries: inout Bool) -> Bool {
|
|
let indices = Set(indicesAndFlags.map { $0.0 })
|
|
var hasChanges = false
|
|
if let earlier = self.earlier, indices.contains(earlier) {
|
|
invalidEarlier = true
|
|
hasChanges = true
|
|
}
|
|
|
|
if let later = self.later, indices.contains(later) {
|
|
invalidLater = true
|
|
hasChanges = true
|
|
}
|
|
|
|
if self.entries.count != 0 {
|
|
var i = self.entries.count - 1
|
|
while i >= 0 {
|
|
let entry = self.entries[i]
|
|
if indices.contains(entry.index) {
|
|
self.entries.remove(at: i)
|
|
removedEntries = true
|
|
hasChanges = true
|
|
}
|
|
i -= 1
|
|
}
|
|
}
|
|
|
|
return hasChanges
|
|
}
|
|
|
|
private func firstHole() -> MessageOfInterestHole? {
|
|
if self.entries.isEmpty {
|
|
return nil
|
|
}
|
|
guard let anchorLocation = self.anchorLocation else {
|
|
return nil
|
|
}
|
|
|
|
var referenceIndex = self.entries.count - 1
|
|
for i in 0 ..< self.entries.count {
|
|
if isGreaterOrEqual(index: self.entries[i].index, than: anchorLocation) {
|
|
referenceIndex = i
|
|
break
|
|
}
|
|
}
|
|
|
|
var i = referenceIndex
|
|
var j = referenceIndex + 1
|
|
|
|
let lowerI = max(0, referenceIndex - 50)
|
|
let upperJ = min(referenceIndex + 50, self.entries.count)
|
|
|
|
switch self.location {
|
|
case let .group(groupId):
|
|
while i >= lowerI || j < upperJ {
|
|
if j < upperJ {
|
|
if let hole = self.entries[j].hole {
|
|
switch anchorLocation {
|
|
case let .index(index):
|
|
if let lowerIndex = hole.lowerIndex {
|
|
if index >= lowerIndex && index <= hole.hole.maxIndex {
|
|
return MessageOfInterestHole(hole: .groupFeed(groupId, lowerIndex: lowerIndex, upperIndex: hole.hole.maxIndex), direction: .AroundIndex(index))
|
|
}
|
|
} else {
|
|
assertionFailure()
|
|
}
|
|
default:
|
|
break
|
|
}
|
|
|
|
if let lowerIndex = hole.lowerIndex {
|
|
return MessageOfInterestHole(hole: .groupFeed(groupId, lowerIndex: lowerIndex, upperIndex: hole.hole.maxIndex), direction: isGreaterOrEqual(index: hole.hole.maxIndex, than: anchorLocation) ? .LowerToUpper : .UpperToLower)
|
|
} else {
|
|
assertionFailure()
|
|
}
|
|
}
|
|
}
|
|
|
|
if i >= lowerI {
|
|
if let hole = self.entries[i].hole {
|
|
switch anchorLocation {
|
|
case let .index(index):
|
|
if let lowerIndex = hole.lowerIndex {
|
|
if index >= lowerIndex && index <= hole.hole.maxIndex {
|
|
return MessageOfInterestHole(hole: .groupFeed(groupId, lowerIndex: lowerIndex, upperIndex: hole.hole.maxIndex), direction: .AroundIndex(index))
|
|
}
|
|
|
|
if hole.hole.maxIndex.timestamp >= Int32.max - 1 && index.timestamp >= Int32.max - 1 {
|
|
return MessageOfInterestHole(hole: .groupFeed(groupId, lowerIndex: lowerIndex, upperIndex: hole.hole.maxIndex), direction: .UpperToLower)
|
|
}
|
|
} else {
|
|
assertionFailure()
|
|
}
|
|
default:
|
|
break
|
|
}
|
|
|
|
/*if case .upperBound = self.anchorIndex, hole.maxIndex.timestamp >= Int32.max - 1 {
|
|
if case let .group(groupId) = self.peerIds {
|
|
if let lowerIndex = lowerIndex {
|
|
return (.groupFeed(groupId, lowerIndex: lowerIndex, upperIndex: hole.maxIndex), .UpperToLower)
|
|
}
|
|
} else {
|
|
return (.peer(hole), .UpperToLower)
|
|
}
|
|
} else {*/
|
|
if let lowerIndex = hole.lowerIndex {
|
|
return MessageOfInterestHole(hole: .groupFeed(groupId, lowerIndex: lowerIndex, upperIndex: hole.hole.maxIndex), direction: isGreaterOrEqual(index: hole.hole.maxIndex, than: anchorLocation) ? .LowerToUpper : .UpperToLower)
|
|
}
|
|
//}
|
|
}
|
|
}
|
|
|
|
i -= 1
|
|
j += 1
|
|
}
|
|
case .peer:
|
|
let anchorId: MessageId
|
|
switch anchorLocation {
|
|
case let .id(id):
|
|
anchorId = id
|
|
case let .index(index):
|
|
anchorId = index.id
|
|
}
|
|
while i >= lowerI || j < upperJ {
|
|
if j < upperJ {
|
|
if let hole = self.entries[j].hole {
|
|
if anchorId.id >= hole.hole.min && anchorId.id <= hole.hole.maxIndex.id.id {
|
|
return MessageOfInterestHole(hole: .peer(hole.hole), direction: .AroundId(anchorId))
|
|
}
|
|
|
|
return MessageOfInterestHole(hole: .peer(hole.hole), direction: hole.hole.maxIndex.id <= anchorId ? .UpperToLower : .LowerToUpper)
|
|
}
|
|
}
|
|
|
|
if i >= lowerI {
|
|
if let hole = self.entries[i].hole {
|
|
if anchorId.id >= hole.hole.min && anchorId.id <= hole.hole.maxIndex.id.id {
|
|
return MessageOfInterestHole(hole: .peer(hole.hole), direction: .AroundId(anchorId))
|
|
}
|
|
|
|
return MessageOfInterestHole(hole: .peer(hole.hole), direction: hole.hole.maxIndex.id <= anchorId ? .UpperToLower : .LowerToUpper)
|
|
}
|
|
}
|
|
|
|
i -= 1
|
|
j += 1
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func immutableView() -> PostboxView {
|
|
return MessageOfInterestHolesView(self)
|
|
}
|
|
}
|
|
|
|
public final class MessageOfInterestHolesView: PostboxView {
|
|
public let closestHole: MessageOfInterestHole?
|
|
public let closestLaterMedia: [HolesViewMedia]
|
|
|
|
init(_ view: MutableMessageOfInterestHolesView) {
|
|
self.closestHole = view.closestHole
|
|
self.closestLaterMedia = view.closestLaterMedia
|
|
}
|
|
}
|