Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin 2020-07-17 21:05:21 +03:00
commit 987cbeae08
7 changed files with 165 additions and 22 deletions

View File

@ -272,6 +272,8 @@ final class MutableMessageHistoryView {
fileprivate(set) var sampledState: HistoryViewSample
fileprivate var isAddedToChatList: Bool
init(postbox: Postbox, orderStatistics: MessageHistoryViewOrderStatistics, clipHoles: Bool, peerIds: MessageHistoryViewPeerIds, anchor inputAnchor: HistoryViewInputAnchor, combinedReadStates: MessageHistoryViewReadState?, transientReadStates: MessageHistoryViewReadState?, tag: MessageTags?, namespaces: MessageIdNamespaces, count: Int, topTaggedMessages: [MessageId.Namespace: MessageHistoryTopTaggedMessage?], additionalDatas: [AdditionalMessageHistoryViewDataEntry], getMessageCountInRange: (MessageIndex, MessageIndex) -> Int32) {
self.anchor = inputAnchor
@ -286,6 +288,15 @@ final class MutableMessageHistoryView {
self.topTaggedMessages = topTaggedMessages
self.additionalDatas = additionalDatas
let mainPeerId: PeerId
switch peerIds {
case let .associated(peerId, _):
mainPeerId = peerId
case let .single(peerId):
mainPeerId = peerId
}
self.isAddedToChatList = postbox.chatListTable.getPeerChatListIndex(peerId: mainPeerId) != nil
self.state = HistoryViewState(postbox: postbox, inputAnchor: inputAnchor, tag: tag, namespaces: namespaces, statistics: self.orderStatistics, halfLimit: count + 1, locations: peerIds)
if case let .loading(loadingState) = self.state {
let sampledState = loadingState.checkAndSample(postbox: postbox)
@ -351,6 +362,17 @@ final class MutableMessageHistoryView {
var operations: [[MessageHistoryOperation]] = []
var peerIdsSet = Set<PeerId>()
if !transaction.chatListOperations.isEmpty {
let mainPeerId: PeerId
switch peerIds {
case let .associated(peerId, _):
mainPeerId = peerId
case let .single(peerId):
mainPeerId = peerId
}
self.isAddedToChatList = postbox.chatListTable.getPeerChatListIndex(peerId: mainPeerId) != nil
}
switch self.peerIds {
case let .single(peerId):
peerIdsSet.insert(peerId)
@ -718,10 +740,12 @@ public final class MessageHistoryView {
public let topTaggedMessages: [Message]
public let additionalData: [AdditionalMessageHistoryViewDataEntry]
public let isLoading: Bool
public let isAddedToChatList: Bool
init(_ mutableView: MutableMessageHistoryView) {
self.tagMask = mutableView.tag
self.namespaces = mutableView.namespaces
self.isAddedToChatList = mutableView.isAddedToChatList
var entries: [MessageHistoryEntry]
switch mutableView.sampledState {
case .loading:

View File

@ -945,6 +945,10 @@ public final class Transaction {
self.postbox?.scanMessages(peerId: peerId, namespace: namespace, tag: tag, f)
}
public func scanMessageAttributes(peerId: PeerId, namespace: MessageId.Namespace, _ f: (MessageId, [MessageAttribute]) -> Bool) {
self.postbox?.scanMessageAttributes(peerId: peerId, namespace: namespace, f)
}
public func invalidateMessageHistoryTagsSummary(peerId: PeerId, namespace: MessageId.Namespace, tagMask: MessageTags) {
assert(!self.disposed)
self.postbox?.invalidateMessageHistoryTagsSummary(peerId: peerId, namespace: namespace, tagMask: tagMask)
@ -1043,7 +1047,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration,
#if DEBUG
//debugSaveState(basePath: basePath, name: "previous1")
//debugRestoreState(basePath: basePath, name: "previous1")
debugRestoreState(basePath: basePath, name: "previous1")
#endif
let startTime = CFAbsoluteTimeGetCurrent()
@ -3170,6 +3174,24 @@ public final class Postbox {
}
}
fileprivate func scanMessageAttributes(peerId: PeerId, namespace: MessageId.Namespace, _ f: (MessageId, [MessageAttribute]) -> Bool) {
var index = MessageIndex.upperBound(peerId: peerId, namespace: namespace)
while true {
let messages = self.messageHistoryTable.fetch(peerId: peerId, namespace: namespace, tag: nil, from: index, includeFrom: false, to: MessageIndex.lowerBound(peerId: peerId, namespace: namespace), limit: 32)
for message in messages {
let attributes = MessageHistoryTable.renderMessageAttributes(message)
if !f(message.id, attributes) {
break
}
}
if let last = messages.last {
index = last.index
} else {
break
}
}
}
fileprivate func invalidateMessageHistoryTagsSummary(peerId: PeerId, namespace: MessageId.Namespace, tagMask: MessageTags) {
self.invalidatedMessageHistoryTagsSummaryTable.insert(InvalidatedMessageHistoryTagsSummaryKey(peerId: peerId, namespace: namespace, tagMask: tagMask), operations: &self.currentInvalidateMessageTagSummaries)
}

View File

@ -109,6 +109,22 @@ enum AccountStateMutationOperation {
case UpdateChatListFilter(id: Int32, filter: Api.DialogFilter?)
}
struct HoleFromPreviousState {
var validateChannelPts: Int32?
func mergedWith(_ other: HoleFromPreviousState) -> HoleFromPreviousState {
var result = self
if let pts = self.validateChannelPts, let otherPts = other.validateChannelPts {
result.validateChannelPts = max(pts, otherPts)
} else if let pts = self.validateChannelPts {
result.validateChannelPts = pts
} else if let otherPts = other.validateChannelPts {
result.validateChannelPts = otherPts
}
return result
}
}
struct AccountMutableState {
let initialState: AccountInitialState
let branchOperationIndex: Int
@ -122,7 +138,7 @@ struct AccountMutableState {
var referencedMessageIds: Set<MessageId>
var storedMessages: Set<MessageId>
var readInboxMaxIds: [PeerId: MessageId]
var namespacesWithHolesFromPreviousState: [PeerId: Set<MessageId.Namespace>]
var namespacesWithHolesFromPreviousState: [PeerId: [MessageId.Namespace: HoleFromPreviousState]]
var updatedOutgoingUniqueMessageIds: [Int64: Int32]
var storedMessagesByPeerIdAndTimestamp: [PeerId: Set<MessageIndex>]
@ -154,7 +170,7 @@ struct AccountMutableState {
self.updatedOutgoingUniqueMessageIds = [:]
}
init(initialState: AccountInitialState, operations: [AccountStateMutationOperation], state: AuthorizedAccountState.State, peers: [PeerId: Peer], channelStates: [PeerId: AccountStateChannelState], peerChatInfos: [PeerId: PeerChatInfo], referencedMessageIds: Set<MessageId>, storedMessages: Set<MessageId>, readInboxMaxIds: [PeerId: MessageId], storedMessagesByPeerIdAndTimestamp: [PeerId: Set<MessageIndex>], namespacesWithHolesFromPreviousState: [PeerId: Set<MessageId.Namespace>], updatedOutgoingUniqueMessageIds: [Int64: Int32], displayAlerts: [(text: String, isDropAuth: Bool)], branchOperationIndex: Int) {
init(initialState: AccountInitialState, operations: [AccountStateMutationOperation], state: AuthorizedAccountState.State, peers: [PeerId: Peer], channelStates: [PeerId: AccountStateChannelState], peerChatInfos: [PeerId: PeerChatInfo], referencedMessageIds: Set<MessageId>, storedMessages: Set<MessageId>, readInboxMaxIds: [PeerId: MessageId], storedMessagesByPeerIdAndTimestamp: [PeerId: Set<MessageIndex>], namespacesWithHolesFromPreviousState: [PeerId: [MessageId.Namespace: HoleFromPreviousState]], updatedOutgoingUniqueMessageIds: [Int64: Int32], displayAlerts: [(text: String, isDropAuth: Bool)], branchOperationIndex: Int) {
self.initialState = initialState
self.operations = operations
self.state = state
@ -187,10 +203,14 @@ struct AccountMutableState {
self.externallyUpdatedPeerId.formUnion(other.externallyUpdatedPeerId)
for (peerId, namespaces) in other.namespacesWithHolesFromPreviousState {
if self.namespacesWithHolesFromPreviousState[peerId] == nil {
self.namespacesWithHolesFromPreviousState[peerId] = Set()
self.namespacesWithHolesFromPreviousState[peerId] = [:]
}
for namespace in namespaces {
self.namespacesWithHolesFromPreviousState[peerId]!.insert(namespace)
for (namespace, namespaceState) in namespaces {
if self.namespacesWithHolesFromPreviousState[peerId]![namespace] == nil {
self.namespacesWithHolesFromPreviousState[peerId]![namespace] = namespaceState
} else {
self.namespacesWithHolesFromPreviousState[peerId]![namespace] = self.namespacesWithHolesFromPreviousState[peerId]![namespace]!.mergedWith(namespaceState)
}
}
}
self.updatedOutgoingUniqueMessageIds.merge(other.updatedOutgoingUniqueMessageIds, uniquingKeysWith: { lhs, _ in lhs })
@ -296,11 +316,16 @@ struct AccountMutableState {
self.addOperation(.UpdateGlobalNotificationSettings(subject, notificationSettings))
}
mutating func setNeedsHoleFromPreviousState(peerId: PeerId, namespace: MessageId.Namespace) {
mutating func setNeedsHoleFromPreviousState(peerId: PeerId, namespace: MessageId.Namespace, validateChannelPts: Int32?) {
if self.namespacesWithHolesFromPreviousState[peerId] == nil {
self.namespacesWithHolesFromPreviousState[peerId] = Set()
self.namespacesWithHolesFromPreviousState[peerId] = [:]
}
let namespaceState = HoleFromPreviousState(validateChannelPts: validateChannelPts)
if self.namespacesWithHolesFromPreviousState[peerId]![namespace] == nil {
self.namespacesWithHolesFromPreviousState[peerId]![namespace] = namespaceState
} else {
self.namespacesWithHolesFromPreviousState[peerId]![namespace] = self.namespacesWithHolesFromPreviousState[peerId]![namespace]!.mergedWith(namespaceState)
}
self.namespacesWithHolesFromPreviousState[peerId]!.insert(namespace)
}
mutating func mergeChats(_ chats: [Api.Chat]) {

View File

@ -1510,7 +1510,7 @@ private func resolveMissingPeerChatInfos(network: Network, state: AccountMutable
case let .dialog(_, peer, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, notifySettings, pts, _, folderId):
let peerId = peer.peerId
updatedState.setNeedsHoleFromPreviousState(peerId: peerId, namespace: Namespaces.Message.Cloud)
updatedState.setNeedsHoleFromPreviousState(peerId: peerId, namespace: Namespaces.Message.Cloud, validateChannelPts: pts)
if topMessage != 0 {
topMessageIds.insert(MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: topMessage))
@ -1590,7 +1590,7 @@ private func resolveMissingPeerChatInfos(network: Network, state: AccountMutable
}
func keepPollingChannel(postbox: Postbox, network: Network, peerId: PeerId, stateManager: AccountStateManager) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Signal<Void, NoError> in
let signal: Signal<Void, NoError> = postbox.transaction { transaction -> Signal<Void, NoError> in
if let accountState = (transaction.getState() as? AuthorizedAccountState)?.state, let peer = transaction.getPeer(peerId) {
var channelStates: [PeerId: AccountStateChannelState] = [:]
if let channelState = transaction.getPeerChatState(peerId) as? ChannelState {
@ -1635,6 +1635,9 @@ func keepPollingChannel(postbox: Postbox, network: Network, peerId: PeerId, stat
}
|> switchToLatest
|> restart
return signal
|> delay(5.0, queue: .concurrentDefaultQueue())
}
private func resetChannels(network: Network, peers: [Peer], state: AccountMutableState) -> Signal<AccountMutableState, NoError> {
@ -1751,7 +1754,11 @@ private func resetChannels(network: Network, peers: [Peer], state: AccountMutabl
for message in storeMessages {
if case let .Id(id) = message.id, id.namespace == Namespaces.Message.Cloud {
updatedState.setNeedsHoleFromPreviousState(peerId: id.peerId, namespace: id.namespace)
var channelPts: Int32?
if let state = channelStates[id.peerId] {
channelPts = state.pts
}
updatedState.setNeedsHoleFromPreviousState(peerId: id.peerId, namespace: id.namespace, validateChannelPts: channelPts)
channelSynchronizedUntilMessage[id.peerId] = id.id
}
}
@ -1841,7 +1848,11 @@ private func pollChannel(network: Network, peer: Peer, state: AccountMutableStat
updatedState.mergeUsers(users)
for apiMessage in newMessages {
if let message = StoreMessage(apiMessage: apiMessage) {
if var message = StoreMessage(apiMessage: apiMessage) {
var attributes = message.attributes
attributes.append(ChannelMessageStateVersionAttribute(pts: pts))
message = message.withUpdatedAttributes(attributes)
if let preCachedResources = apiMessage.preCachedResources {
for (resource, data) in preCachedResources {
updatedState.addPreCachedResource(resource, data: data)
@ -1941,10 +1952,14 @@ private func pollChannel(network: Network, peer: Peer, state: AccountMutableStat
updatedState.mergeChats(chats)
updatedState.mergeUsers(users)
updatedState.setNeedsHoleFromPreviousState(peerId: peer.peerId, namespace: Namespaces.Message.Cloud)
updatedState.setNeedsHoleFromPreviousState(peerId: peer.peerId, namespace: Namespaces.Message.Cloud, validateChannelPts: pts)
for apiMessage in messages {
if let message = StoreMessage(apiMessage: apiMessage) {
if var message = StoreMessage(apiMessage: apiMessage) {
var attributes = message.attributes
attributes.append(ChannelMessageStateVersionAttribute(pts: pts))
message = message.withUpdatedAttributes(attributes)
if let preCachedResources = apiMessage.preCachedResources {
for (resource, data) in preCachedResources {
updatedState.addPreCachedResource(resource, data: data)
@ -2175,9 +2190,14 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
var syncChatListFilters = false
var holesFromPreviousStateMessageIds: [MessageId] = []
var clearHolesFromPreviousStateForChannelMessagesWithPts: [PeerIdAndMessageNamespace: Int32] = [:]
for (peerId, namespaces) in finalState.state.namespacesWithHolesFromPreviousState {
for namespace in namespaces {
for (namespace, namespaceState) in namespaces {
if let pts = namespaceState.validateChannelPts {
clearHolesFromPreviousStateForChannelMessagesWithPts[PeerIdAndMessageNamespace(peerId: peerId, namespace: namespace)] = pts
}
var topId: Int32?
if namespace == Namespaces.Message.Cloud, let channelState = transaction.getPeerChatState(peerId) as? ChannelState {
if let synchronizedUntilMessageId = channelState.synchronizedUntilMessageId {
@ -2838,6 +2858,36 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
}
}
for (peerIdAndNamespace, pts) in clearHolesFromPreviousStateForChannelMessagesWithPts {
var upperMessageId: Int32?
var lowerMessageId: Int32?
transaction.scanMessageAttributes(peerId: peerIdAndNamespace.peerId, namespace: peerIdAndNamespace.namespace, { id, attributes in
for attribute in attributes {
if let attribute = attribute as? ChannelMessageStateVersionAttribute {
if attribute.pts >= pts {
if upperMessageId == nil {
upperMessageId = id.id
}
if let lowerMessageIdValue = lowerMessageId {
lowerMessageId = min(id.id, lowerMessageIdValue)
} else {
lowerMessageId = id.id
}
return true
} else {
return false
}
}
}
return false
})
if let upperMessageId = upperMessageId, let lowerMessageId = lowerMessageId {
if upperMessageId != lowerMessageId {
transaction.removeHole(peerId: peerIdAndNamespace.peerId, namespace: peerIdAndNamespace.namespace, space: .everywhere, range: lowerMessageId ... upperMessageId)
}
}
}
if !peerActivityTimestamps.isEmpty {
updatePeerPresenceLastActivities(transaction: transaction, accountPeerId: accountPeerId, activities: peerActivityTimestamps)
}

View File

@ -1111,13 +1111,13 @@ public final class AccountViewTracker {
let combinedDisposable = MetaDisposable()
self.queue.async {
var addHole = false
/*if let context = self.channelPollingContexts[peerId] {
if let context = self.channelPollingContexts[peerId] {
if context.subscribers.isEmpty {
addHole = true
}
} else {
addHole = true
}*/
}
if addHole {
let _ = self.account?.postbox.transaction({ transaction -> Void in
if transaction.getPeerChatListIndex(peerId) == nil {

View File

@ -1435,7 +1435,13 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
loadState = .loading
}
var animateIn = false
if strongSelf.loadState != loadState {
if case .loading = strongSelf.loadState {
if case .messages = loadState {
animateIn = true
}
}
strongSelf.loadState = loadState
strongSelf.loadStateUpdated?(loadState, animated)
}
@ -1478,8 +1484,24 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
strongSelf._buttonKeyboardMessage.set(.single(transition.keyboardButtonsMessage))
}
if transition.animateIn {
strongSelf.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
if transition.animateIn || animateIn {
let heightNorm = strongSelf.bounds.height - strongSelf.insets.top
strongSelf.forEachVisibleItemNode { itemNode in
if let itemNode = itemNode as? ChatMessageItemView {
let delayFactor = itemNode.frame.minY / heightNorm
let delay = Double(delayFactor * 0.1)
itemNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15, delay: delay)
itemNode.layer.animateScale(from: 0.9, to: 1.0, duration: 0.4, delay: delay, timingFunction: kCAMediaTimingFunctionSpring)
}
}
strongSelf.forEachItemHeaderNode { itemNode in
let delayFactor = itemNode.frame.minY / heightNorm
let delay = Double(delayFactor * 0.2)
itemNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15, delay: delay)
itemNode.layer.animateScale(from: 0.9, to: 1.0, duration: 0.4, delay: delay, timingFunction: kCAMediaTimingFunctionSpring)
}
}
if let scrolledToIndex = transition.scrolledToIndex {

View File

@ -83,7 +83,7 @@ func chatHistoryViewForLocation(_ location: ChatHistoryLocationInput, account: A
}
var scrollPosition: ChatHistoryViewScrollPosition?
if let maxReadIndex = view.maxReadIndex, tagMask == nil {
if let maxReadIndex = view.maxReadIndex, tagMask == nil, view.isAddedToChatList {
let aroundIndex = maxReadIndex
scrollPosition = .unread(index: maxReadIndex)
@ -120,7 +120,7 @@ func chatHistoryViewForLocation(_ location: ChatHistoryLocationInput, account: A
}
}
}
} else if let historyScrollState = (initialData?.chatInterfaceState as? ChatInterfaceState)?.historyScrollState, tagMask == nil {
} else if view.isAddedToChatList, let historyScrollState = (initialData?.chatInterfaceState as? ChatInterfaceState)?.historyScrollState, tagMask == nil {
scrollPosition = .positionRestoration(index: historyScrollState.messageIndex, relativeOffset: CGFloat(historyScrollState.relativeOffset))
} else {
if view.entries.isEmpty && (view.holeEarlier || view.holeLater) {