mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-07-13 14:59:23 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
987cbeae08
@ -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:
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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]) {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user