diff --git a/.bazelrc b/.bazelrc index 3397576710..4471fa12d1 100644 --- a/.bazelrc +++ b/.bazelrc @@ -27,9 +27,9 @@ build:swift_profile --local_cpu_resources=1 build:swift_profile --features=-swift.enable_batch_mode build:swift_profile --experimental_ui_max_stdouterr_bytes=104857600 build:swift_profile --@build_bazel_rules_swift//swift:copt=-Xfrontend -build:swift_profile --@build_bazel_rules_swift//swift:copt=-debug-time-function-bodies +build:swift_profile --@build_bazel_rules_swift//swift:copt=-warn-long-function-bodies=350 build:swift_profile --@build_bazel_rules_swift//swift:copt=-Xfrontend -build:swift_profile --@build_bazel_rules_swift//swift:copt=-debug-time-expression-type-checking +build:swift_profile --@build_bazel_rules_swift//swift:copt=-warn-long-expression-type-checking=350 common:index_build --experimental_convenience_symlinks=ignore common:index_build --bes_backend= --bes_results_url= diff --git a/build-system/Make/TartBuild.py b/build-system/Make/TartBuild.py index 449e9ce0e1..9f890ca3d8 100644 --- a/build-system/Make/TartBuild.py +++ b/build-system/Make/TartBuild.py @@ -604,7 +604,7 @@ def remote_build_tart(macos_version, bazel_cache_host, configuration, build_inpu else: guest_build_sh += '--cacheHost="$CACHE_HOST" \\' guest_build_sh += 'build \\' - guest_build_sh += '--lock \\' + #guest_build_sh += '--lock \\' guest_build_sh += '--buildNumber={} \\'.format(build_number) guest_build_sh += '--configuration={} \\'.format(configuration) guest_build_sh += '--configurationPath=$HOME/telegram-build-input/configuration.json \\' diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 9400083f13..77840ac7fa 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -2545,13 +2545,25 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController guard let strongSelf, currentValues.contains(.setupPasskey) else { return } - if let navigationController = strongSelf.navigationController as? NavigationController { - let controller = strongSelf.context.sharedContext.makePasskeySetupController(context: strongSelf.context, displaySkip: true, navigationController: navigationController, completion: { - let _ = context.engine.notices.dismissServerProvidedSuggestion(suggestion: ServerProvidedSuggestion.setupPasskey.id).startStandalone() - }, dismiss: { - let _ = context.engine.notices.dismissServerProvidedSuggestion(suggestion: ServerProvidedSuggestion.setupPasskey.id).startStandalone() - }) - navigationController.pushViewController(controller) + + Task { @MainActor [weak strongSelf] in + guard let strongSelf else { + return + } + + let passkeysData = await strongSelf.context.engine.auth.passkeysData().get() + if !passkeysData.isEmpty { + return + } + + if let navigationController = strongSelf.navigationController as? NavigationController { + let controller = strongSelf.context.sharedContext.makePasskeySetupController(context: strongSelf.context, displaySkip: true, navigationController: navigationController, completion: { + let _ = context.engine.notices.dismissServerProvidedSuggestion(suggestion: ServerProvidedSuggestion.setupPasskey.id).startStandalone() + }, dismiss: { + let _ = context.engine.notices.dismissServerProvidedSuggestion(suggestion: ServerProvidedSuggestion.setupPasskey.id).startStandalone() + }) + navigationController.pushViewController(controller) + } } }) diff --git a/submodules/Postbox/Sources/DeletedMessagesView.swift b/submodules/Postbox/Sources/DeletedMessagesView.swift index 7f3b4edaaf..b1ab425f9c 100644 --- a/submodules/Postbox/Sources/DeletedMessagesView.swift +++ b/submodules/Postbox/Sources/DeletedMessagesView.swift @@ -15,7 +15,7 @@ final class MutableDeletedMessagesView: MutablePostboxView { for operation in operations { switch operation { case let .Remove(indices): - for (index, _) in indices { + for (index, _, _) in indices { testMessageIds.append(index.id) } default: diff --git a/submodules/Postbox/Sources/HistoryTagInfoView.swift b/submodules/Postbox/Sources/HistoryTagInfoView.swift index 912b4a86b0..9b9e0adc3c 100644 --- a/submodules/Postbox/Sources/HistoryTagInfoView.swift +++ b/submodules/Postbox/Sources/HistoryTagInfoView.swift @@ -32,7 +32,7 @@ final class MutableHistoryTagInfoView: MutablePostboxView { } case let .Remove(indicesAndTags): if self.currentIndex != nil { - for (index, tags) in indicesAndTags { + for (index, tags, _) in indicesAndTags { if tags.contains(self.tag) { if index == self.currentIndex { self.currentIndex = nil diff --git a/submodules/Postbox/Sources/MessageHistoryOperation.swift b/submodules/Postbox/Sources/MessageHistoryOperation.swift index 71e7e84de8..c4537b58e7 100644 --- a/submodules/Postbox/Sources/MessageHistoryOperation.swift +++ b/submodules/Postbox/Sources/MessageHistoryOperation.swift @@ -2,7 +2,7 @@ import Foundation enum MessageHistoryOperation { case InsertMessage(IntermediateMessage) - case Remove([(MessageIndex, MessageTags)]) + case Remove([(MessageIndex, MessageTags, Int64?)]) case UpdateReadState(PeerId, CombinedPeerReadState) case UpdateEmbeddedMedia(MessageIndex, ReadBuffer) case UpdateTimestamp(MessageIndex, Int32) diff --git a/submodules/Postbox/Sources/MessageHistoryTable.swift b/submodules/Postbox/Sources/MessageHistoryTable.swift index 2d290a7545..cd004d82cc 100644 --- a/submodules/Postbox/Sources/MessageHistoryTable.swift +++ b/submodules/Postbox/Sources/MessageHistoryTable.swift @@ -197,19 +197,19 @@ final class MessageHistoryTable: Table { let buckets = self.continuousIndexIntervalsForRemoving(accumulatedRemoveIndices) for bucket in buckets { - var indicesWithMetadata: [(MessageIndex, MessageTags)] = [] + var indicesWithMetadata: [(MessageIndex, MessageTags, Int64?)] = [] var globalIndicesWithMetadata: [(GlobalMessageTags, MessageIndex)] = [] for index in bucket { let tagsAndGlobalTags = self.justRemove(index, unsentMessageOperations: &unsentMessageOperations, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, localTagsOperations: &localTagsOperations, timestampBasedMessageAttributesOperations: ×tampBasedMessageAttributesOperations) - if let (tags, globalTags) = tagsAndGlobalTags { - indicesWithMetadata.append((index, tags)) + if let (tags, globalTags, threadId) = tagsAndGlobalTags { + indicesWithMetadata.append((index, tags, threadId)) if !globalTags.isEmpty { globalIndicesWithMetadata.append((globalTags, index)) } } else { - indicesWithMetadata.append((index, MessageTags())) + indicesWithMetadata.append((index, MessageTags(), nil)) } } assert(bucket.count == indicesWithMetadata.count) @@ -352,8 +352,8 @@ final class MessageHistoryTable: Table { processIndexOperationsCommitAccumulatedRemoveIndices(peerId: peerId, accumulatedRemoveIndices: &accumulatedRemoveIndices, updatedCombinedState: &updatedCombinedState, invalidateReadState: &invalidateReadState, unsentMessageOperations: &unsentMessageOperations, outputOperations: &outputOperations, globalTagsOperations: &globalTagsOperations, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, localTagsOperations: &localTagsOperations, timestampBasedMessageAttributesOperations: ×tampBasedMessageAttributesOperations) var updatedGroupInfos: [MessageId: MessageGroupInfo] = [:] - if let (message, previousTags) = self.justUpdate(storeMessage.index, message: storeMessage, keepLocalTags: true, sharedKey: sharedKey, sharedBuffer: sharedBuffer, sharedEncoder: sharedEncoder, unsentMessageOperations: &unsentMessageOperations, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, updatedGroupInfos: &updatedGroupInfos, localTagsOperations: &localTagsOperations, timestampBasedMessageAttributesOperations: ×tampBasedMessageAttributesOperations, updatedMedia: &updatedMedia) { - outputOperations.append(.Remove([(storeMessage.index, previousTags)])) + if let (message, previousTags, previousThreadId) = self.justUpdate(storeMessage.index, message: storeMessage, keepLocalTags: true, sharedKey: sharedKey, sharedBuffer: sharedBuffer, sharedEncoder: sharedEncoder, unsentMessageOperations: &unsentMessageOperations, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, updatedGroupInfos: &updatedGroupInfos, localTagsOperations: &localTagsOperations, timestampBasedMessageAttributesOperations: ×tampBasedMessageAttributesOperations, updatedMedia: &updatedMedia) { + outputOperations.append(.Remove([(storeMessage.index, previousTags, previousThreadId)])) outputOperations.append(.InsertMessage(message)) if !updatedGroupInfos.isEmpty { outputOperations.append(.UpdateGroupInfos(updatedGroupInfos)) @@ -367,8 +367,8 @@ final class MessageHistoryTable: Table { processIndexOperationsCommitAccumulatedRemoveIndices(peerId: peerId, accumulatedRemoveIndices: &accumulatedRemoveIndices, updatedCombinedState: &updatedCombinedState, invalidateReadState: &invalidateReadState, unsentMessageOperations: &unsentMessageOperations, outputOperations: &outputOperations, globalTagsOperations: &globalTagsOperations, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, localTagsOperations: &localTagsOperations, timestampBasedMessageAttributesOperations: ×tampBasedMessageAttributesOperations) var updatedGroupInfos: [MessageId: MessageGroupInfo] = [:] - if let (message, previousTags) = self.justUpdate(index, message: storeMessage, keepLocalTags: false, sharedKey: sharedKey, sharedBuffer: sharedBuffer, sharedEncoder: sharedEncoder, unsentMessageOperations: &unsentMessageOperations, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, updatedGroupInfos: &updatedGroupInfos, localTagsOperations: &localTagsOperations, timestampBasedMessageAttributesOperations: ×tampBasedMessageAttributesOperations, updatedMedia: &updatedMedia) { - outputOperations.append(.Remove([(index, previousTags)])) + if let (message, previousTags, previousThreadId) = self.justUpdate(index, message: storeMessage, keepLocalTags: false, sharedKey: sharedKey, sharedBuffer: sharedBuffer, sharedEncoder: sharedEncoder, unsentMessageOperations: &unsentMessageOperations, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, updatedGroupInfos: &updatedGroupInfos, localTagsOperations: &localTagsOperations, timestampBasedMessageAttributesOperations: ×tampBasedMessageAttributesOperations, updatedMedia: &updatedMedia) { + outputOperations.append(.Remove([(index, previousTags, previousThreadId)])) outputOperations.append(.InsertMessage(message)) if !updatedGroupInfos.isEmpty { outputOperations.append(.UpdateGroupInfos(updatedGroupInfos)) @@ -944,7 +944,7 @@ final class MessageHistoryTable: Table { self.storeIntermediateMessage(updatedMessage, sharedKey: self.key(MessageIndex.absoluteLowerBound())) let operations: [MessageHistoryOperation] = [ - .Remove([(index, message.tags)]), + .Remove([(index, message.tags, message.threadId)]), .InsertMessage(updatedMessage) ] if operationsByPeerId[message.id.peerId] == nil { @@ -1352,7 +1352,7 @@ final class MessageHistoryTable: Table { return result } - private func justRemove(_ index: MessageIndex, unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], pendingActionsOperations: inout [PendingMessageActionsOperation], updatedMessageActionsSummaries: inout [PendingMessageActionsSummaryKey: Int32], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation]) -> (MessageTags, GlobalMessageTags)? { + private func justRemove(_ index: MessageIndex, unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], pendingActionsOperations: inout [PendingMessageActionsOperation], updatedMessageActionsSummaries: inout [PendingMessageActionsSummaryKey: Int32], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation]) -> (MessageTags, GlobalMessageTags, Int64?)? { let key = self.key(index) if let value = self.valueBox.get(self.table, key: key) { let resultTags: MessageTags @@ -1440,7 +1440,7 @@ final class MessageHistoryTable: Table { resultGlobalTags = message.globalTags self.valueBox.remove(self.table, key: key, secure: true) - return (resultTags, resultGlobalTags) + return (resultTags, resultGlobalTags, message.threadId) } else { return nil } @@ -1544,7 +1544,7 @@ final class MessageHistoryTable: Table { }) } - private func justUpdate(_ index: MessageIndex, message: InternalStoreMessage, keepLocalTags: Bool, sharedKey: ValueBoxKey, sharedBuffer: WriteBuffer, sharedEncoder: PostboxEncoder, unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], updatedGroupInfos: inout [MessageId: MessageGroupInfo], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation], updatedMedia: inout [MediaId: Media?]) -> (IntermediateMessage, MessageTags)? { + private func justUpdate(_ index: MessageIndex, message: InternalStoreMessage, keepLocalTags: Bool, sharedKey: ValueBoxKey, sharedBuffer: WriteBuffer, sharedEncoder: PostboxEncoder, unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], updatedGroupInfos: inout [MessageId: MessageGroupInfo], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation], updatedMedia: inout [MediaId: Media?]) -> (IntermediateMessage, MessageTags, Int64?)? { if let previousMessage = self.getMessage(index) { var mediaToUpdate: [Media] = [] @@ -2037,7 +2037,7 @@ final class MessageHistoryTable: Table { self.valueBox.set(self.table, key: self.key(message.index, key: sharedKey), value: sharedBuffer) - let result = (IntermediateMessage(stableId: stableId, stableVersion: stableVersion, id: message.id, globallyUniqueId: message.globallyUniqueId, groupingKey: message.groupingKey, groupInfo: groupInfo, threadId: message.threadId, timestamp: message.timestamp, flags: flags, tags: tags, globalTags: message.globalTags, localTags: updatedLocalTags, customTags: message.customTags, forwardInfo: intermediateForwardInfo, authorId: message.authorId, text: message.text, attributesData: attributesBuffer.makeReadBufferAndReset(), embeddedMediaData: embeddedMediaBuffer.makeReadBufferAndReset(), referencedMedia: referencedMedia), previousMessage.tags) + let result = (IntermediateMessage(stableId: stableId, stableVersion: stableVersion, id: message.id, globallyUniqueId: message.globallyUniqueId, groupingKey: message.groupingKey, groupInfo: groupInfo, threadId: message.threadId, timestamp: message.timestamp, flags: flags, tags: tags, globalTags: message.globalTags, localTags: updatedLocalTags, customTags: message.customTags, forwardInfo: intermediateForwardInfo, authorId: message.authorId, text: message.text, attributesData: attributesBuffer.makeReadBufferAndReset(), embeddedMediaData: embeddedMediaBuffer.makeReadBufferAndReset(), referencedMedia: referencedMedia), previousMessage.tags, previousMessage.threadId) for media in mediaToUpdate { if let id = media.id { diff --git a/submodules/Postbox/Sources/MessageHistoryView.swift b/submodules/Postbox/Sources/MessageHistoryView.swift index a8b000f97d..eb2591835a 100644 --- a/submodules/Postbox/Sources/MessageHistoryView.swift +++ b/submodules/Postbox/Sources/MessageHistoryView.swift @@ -676,7 +676,7 @@ final class MutableMessageHistoryView: MutablePostboxView { } } case let .Remove(indicesAndTags): - for (index, _) in indicesAndTags { + for (index, _, _) in indicesAndTags { if self.namespaces.contains(index.id.namespace) { if loadedState.remove(index: index) { hasChanges = true @@ -821,7 +821,7 @@ final class MutableMessageHistoryView: MutablePostboxView { } case let .Remove(indices): if !self.topTaggedMessages.isEmpty { - for (index, _) in indices { + for (index, _, _) in indices { if let maybeCurrentTopMessage = self.topTaggedMessages[index.id.namespace], let currentTopMessage = maybeCurrentTopMessage, index.id == currentTopMessage.id { let item: MessageHistoryTopTaggedMessage? = nil self.topTaggedMessages[index.id.namespace] = item @@ -873,7 +873,7 @@ final class MutableMessageHistoryView: MutablePostboxView { break findOperation } case let .Remove(indices): - for (index, _) in indices { + for (index, _, _) in indices { if currentIds.contains(index.id) { updateMessage = true break findOperation @@ -956,7 +956,7 @@ final class MutableMessageHistoryView: MutablePostboxView { break outer } case let .Remove(indicesWithTags): - for (index, _) in indicesWithTags { + for (index, _, _) in indicesWithTags { if cachedData.messageIds.contains(index.id) { updatedCachedPeerDataMessages = true break outer diff --git a/submodules/Postbox/Sources/MessageView.swift b/submodules/Postbox/Sources/MessageView.swift index 1ae3ed291f..483125841f 100644 --- a/submodules/Postbox/Sources/MessageView.swift +++ b/submodules/Postbox/Sources/MessageView.swift @@ -18,7 +18,7 @@ final class MutableMessageView { case let .Remove(indices): if let message = self.message { let messageIndex = message.index - for (index, _) in indices { + for (index, _, _) in indices { if index == messageIndex { self.message = nil updated = true diff --git a/submodules/Postbox/Sources/PeerChatTopIndexableMessageIds.swift b/submodules/Postbox/Sources/PeerChatTopIndexableMessageIds.swift index ed89866671..84e6c9969d 100644 --- a/submodules/Postbox/Sources/PeerChatTopIndexableMessageIds.swift +++ b/submodules/Postbox/Sources/PeerChatTopIndexableMessageIds.swift @@ -1,7 +1,7 @@ import Foundation private struct PeerChatTopTaggedUpdateRecord: Equatable, Hashable { - let peerId: PeerId + let peerAndThreadId: PeerAndThreadId let namespace: MessageId.Namespace } @@ -10,71 +10,85 @@ final class PeerChatTopTaggedMessageIdsTable: Table { return ValueBoxTable(id: id, keyType: .binary, compactValuesOnCreation: true) } - private var cachedTopIds: [PeerId: [MessageId.Namespace: MessageId?]] = [:] + private var cachedTopIds: [PeerAndThreadId: [MessageId.Namespace: MessageId?]] = [:] private var updatedPeerIds = Set() - private let sharedKey = ValueBoxKey(length: 8 + 4) + private let sharedKeyNoThreadId = ValueBoxKey(length: 8 + 4) + private let sharedKeyWithThreadId = ValueBoxKey(length: 8 + 4 + 8) - private func key(peerId: PeerId, namespace: MessageId.Namespace) -> ValueBoxKey { - self.sharedKey.setInt64(0, value: peerId.toInt64()) - self.sharedKey.setInt32(8, value: namespace) - return self.sharedKey + private func key(combinedId: PeerAndThreadId, namespace: MessageId.Namespace) -> ValueBoxKey { + if let threadId = combinedId.threadId { + self.sharedKeyWithThreadId.setInt64(0, value: combinedId.peerId.toInt64()) + self.sharedKeyWithThreadId.setInt32(8, value: namespace) + self.sharedKeyWithThreadId.setInt64(8 + 4, value: threadId) + + return self.sharedKeyWithThreadId + } else { + self.sharedKeyNoThreadId.setInt64(0, value: combinedId.peerId.toInt64()) + self.sharedKeyNoThreadId.setInt32(8, value: namespace) + + return self.sharedKeyNoThreadId + } } - func get(peerId: PeerId, namespace: MessageId.Namespace) -> MessageId? { - if let cachedDict = self.cachedTopIds[peerId] { + func get(peerId: PeerId, threadId: Int64?, namespace: MessageId.Namespace) -> MessageId? { + let combinedId = PeerAndThreadId(peerId: peerId, threadId: threadId) + + if let cachedDict = self.cachedTopIds[combinedId] { if let maybeCachedId = cachedDict[namespace] { return maybeCachedId } else { - if let value = self.valueBox.get(self.table, key: self.key(peerId: peerId, namespace: namespace)) { + if let value = self.valueBox.get(self.table, key: self.key(combinedId: combinedId, namespace: namespace)) { var messageIdId: Int32 = 0 value.read(&messageIdId, offset: 0, length: 4) - self.cachedTopIds[peerId]![namespace] = MessageId(peerId: peerId, namespace: namespace, id: messageIdId) + self.cachedTopIds[combinedId]![namespace] = MessageId(peerId: peerId, namespace: namespace, id: messageIdId) return MessageId(peerId: peerId, namespace: namespace, id: messageIdId) } else { let item: MessageId? = nil - self.cachedTopIds[peerId]![namespace] = item + self.cachedTopIds[combinedId]![namespace] = item return nil } } } else { - if let value = self.valueBox.get(self.table, key: self.key(peerId: peerId, namespace: namespace)) { + if let value = self.valueBox.get(self.table, key: self.key(combinedId: combinedId, namespace: namespace)) { var messageIdId: Int32 = 0 value.read(&messageIdId, offset: 0, length: 4) - self.cachedTopIds[peerId] = [namespace: MessageId(peerId: peerId, namespace: namespace, id: messageIdId)] + self.cachedTopIds[combinedId] = [namespace: MessageId(peerId: peerId, namespace: namespace, id: messageIdId)] return MessageId(peerId: peerId, namespace: namespace, id: messageIdId) } else { let item: MessageId? = nil - self.cachedTopIds[peerId] = [namespace: item] + self.cachedTopIds[combinedId] = [namespace: item] return nil } } } - private func set(peerId: PeerId, namespace: MessageId.Namespace, id: MessageId?) { - if let _ = self.cachedTopIds[peerId] { - self.cachedTopIds[peerId]![namespace] = id + private func set(peerId: PeerId, threadId: Int64?, namespace: MessageId.Namespace, id: MessageId?) { + let combinedId = PeerAndThreadId(peerId: peerId, threadId: threadId) + + if let _ = self.cachedTopIds[combinedId] { + self.cachedTopIds[combinedId]![namespace] = id } else { - self.cachedTopIds[peerId] = [namespace: id] + self.cachedTopIds[combinedId] = [namespace: id] } - self.updatedPeerIds.insert(PeerChatTopTaggedUpdateRecord(peerId: peerId, namespace: namespace)) + self.updatedPeerIds.insert(PeerChatTopTaggedUpdateRecord(peerAndThreadId: combinedId, namespace: namespace)) } - func replay(historyOperationsByPeerId: [PeerId : [MessageHistoryOperation]]) { + func replay(historyOperationsByPeerId: [PeerId: [MessageHistoryOperation]]) { for (_, operations) in historyOperationsByPeerId { for operation in operations { switch operation { case let .InsertMessage(message): if message.flags.contains(.TopIndexable) { - let currentTopMessageId = self.get(peerId: message.id.peerId, namespace: message.id.namespace) + let currentTopMessageId = self.get(peerId: message.id.peerId, threadId: message.threadId, namespace: message.id.namespace) if currentTopMessageId == nil || currentTopMessageId! < message.id { - self.set(peerId: message.id.peerId, namespace: message.id.namespace, id: message.id) + self.set(peerId: message.id.peerId, threadId: message.threadId, namespace: message.id.namespace, id: message.id) } } case let .Remove(indices): - for (index, _) in indices { - if let messageId = self.get(peerId: index.id.peerId, namespace: index.id.namespace), index.id == messageId { - self.set(peerId: index.id.peerId, namespace: index.id.namespace, id: nil) + for (index, _, threadId) in indices { + if let messageId = self.get(peerId: index.id.peerId, threadId: threadId, namespace: index.id.namespace), index.id == messageId { + self.set(peerId: index.id.peerId, threadId: threadId, namespace: index.id.namespace, id: nil) } } default: @@ -92,12 +106,12 @@ final class PeerChatTopTaggedMessageIdsTable: Table { override func beforeCommit() { if !self.updatedPeerIds.isEmpty { for record in self.updatedPeerIds { - if let cachedDict = self.cachedTopIds[record.peerId], let maybeMessageId = cachedDict[record.namespace] { + if let cachedDict = self.cachedTopIds[record.peerAndThreadId], let maybeMessageId = cachedDict[record.namespace] { if let maybeMessageId = maybeMessageId { var messageIdId: Int32 = maybeMessageId.id - self.valueBox.set(self.table, key: self.key(peerId: record.peerId, namespace: record.namespace), value: MemoryBuffer(memory: &messageIdId, capacity: 4, length: 4, freeWhenDone: false)) + self.valueBox.set(self.table, key: self.key(combinedId: record.peerAndThreadId, namespace: record.namespace), value: MemoryBuffer(memory: &messageIdId, capacity: 4, length: 4, freeWhenDone: false)) } else { - self.valueBox.remove(self.table, key: self.key(peerId: record.peerId, namespace: record.namespace), secure: false) + self.valueBox.remove(self.table, key: self.key(combinedId: record.peerAndThreadId, namespace: record.namespace), secure: false) } } } diff --git a/submodules/Postbox/Sources/PeerView.swift b/submodules/Postbox/Sources/PeerView.swift index f7ff4c114e..d0fa0b4f59 100644 --- a/submodules/Postbox/Sources/PeerView.swift +++ b/submodules/Postbox/Sources/PeerView.swift @@ -247,7 +247,7 @@ final class MutablePeerView: MutablePostboxView { break outer } case let .Remove(indicesWithTags): - for (index, _) in indicesWithTags { + for (index, _, _) in indicesWithTags { if cachedData.messageIds.contains(index.id) { updateMessages = true break outer diff --git a/submodules/Postbox/Sources/Postbox.swift b/submodules/Postbox/Sources/Postbox.swift index 7f8e92ac4c..396fe12a46 100644 --- a/submodules/Postbox/Sources/Postbox.swift +++ b/submodules/Postbox/Sources/Postbox.swift @@ -3494,20 +3494,20 @@ final class PostboxImpl { useRootInterfaceStateForThread: Bool ) -> Disposable { var topTaggedMessages: [MessageId.Namespace: MessageHistoryTopTaggedMessage?] = [:] - var mainPeerIdForTopTaggedMessages: PeerId? - switch peerIds { + var mainPeerIdForTopTaggedMessages: (peerId: PeerId, threadId: Int64?)? + if tag == nil { + switch peerIds { case let .single(id, threadId): - if threadId == nil { - mainPeerIdForTopTaggedMessages = id - } + mainPeerIdForTopTaggedMessages = (id, threadId) case let .associated(id, _): - mainPeerIdForTopTaggedMessages = id + mainPeerIdForTopTaggedMessages = (id, nil) case .external: mainPeerIdForTopTaggedMessages = nil + } } if let peerId = mainPeerIdForTopTaggedMessages { for namespace in topTaggedMessageIdNamespaces { - if let messageId = self.peerChatTopTaggedMessageIdsTable.get(peerId: peerId, namespace: namespace) { + if let messageId = self.peerChatTopTaggedMessageIdsTable.get(peerId: peerId.peerId, threadId: peerId.threadId, namespace: namespace) { if let index = self.messageHistoryIndexTable.getIndex(messageId) { if let message = self.messageHistoryTable.getMessage(index) { topTaggedMessages[namespace] = MessageHistoryTopTaggedMessage.intermediate(message) diff --git a/submodules/TelegramCore/Sources/State/AccountViewTracker.swift b/submodules/TelegramCore/Sources/State/AccountViewTracker.swift index e775e854b5..ae88fa3c6a 100644 --- a/submodules/TelegramCore/Sources/State/AccountViewTracker.swift +++ b/submodules/TelegramCore/Sources/State/AccountViewTracker.swift @@ -2173,7 +2173,7 @@ public final class AccountViewTracker { fixedCombinedReadStates: .peer([peerId: CombinedPeerReadState(states: [ (Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: Int32.max - 1, maxOutgoingReadId: Int32.max - 1, maxKnownId: Int32.max - 1, count: 0, markedUnread: false)) ])]), - topTaggedMessageIdNamespaces: [], + topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tag: tag, appendMessagesFromTheSameGroup: false, namespaces: .not(Namespaces.Message.allNonRegular), @@ -2201,7 +2201,7 @@ public final class AccountViewTracker { count: count, trackHoles: trackHoles, fixedCombinedReadStates: nil, - topTaggedMessageIdNamespaces: [], + topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tag: tag, appendMessagesFromTheSameGroup: false, namespaces: .not(Namespaces.Message.allNonRegular), diff --git a/submodules/TelegramUI/Components/Chat/ChatHistoryEntry/Sources/ChatHistoryEntry.swift b/submodules/TelegramUI/Components/Chat/ChatHistoryEntry/Sources/ChatHistoryEntry.swift index 274a2d2868..f200978243 100644 --- a/submodules/TelegramUI/Components/Chat/ChatHistoryEntry/Sources/ChatHistoryEntry.swift +++ b/submodules/TelegramUI/Components/Chat/ChatHistoryEntry/Sources/ChatHistoryEntry.swift @@ -59,45 +59,50 @@ public enum ChatHistoryEntry: Identifiable, Comparable { public var stableId: UInt64 { switch self { - case let .MessageEntry(message, _, _, _, _, attributes): - let type: UInt64 - switch attributes.contentTypeHint { - case .generic: - type = 2 - case .largeEmoji: - type = 3 - case .animatedEmoji: - type = 4 - } - return UInt64(message.stableId) | ((type << 40)) - case let .MessageGroupEntry(groupInfo, _, _): - return UInt64(bitPattern: groupInfo) | ((UInt64(2) << 40)) - case .UnreadEntry: - return UInt64(4) << 40 - case .ReplyCountEntry: - return UInt64(5) << 40 - case .ChatInfoEntry: + case let .MessageEntry(message, _, _, _, _, attributes): + let type: UInt64 + switch attributes.contentTypeHint { + case .generic: + type = 2 + case .largeEmoji: + type = 3 + case .animatedEmoji: + type = 4 + } + return UInt64(message.stableId) | ((type << 40)) + case let .MessageGroupEntry(groupInfo, _, _): + return UInt64(bitPattern: groupInfo) | ((UInt64(2) << 40)) + case .UnreadEntry: + return UInt64(4) << 40 + case .ReplyCountEntry: + return UInt64(5) << 40 + case let .ChatInfoEntry(infoData, _): + switch infoData { + case .newThreadInfo: + return UInt64(7) << 40 + default: return UInt64(6) << 40 + } } } public var index: MessageIndex { switch self { - case let .MessageEntry(message, _, _, _, _, _): - return message.index - case let .MessageGroupEntry(_, messages, _): - return messages[messages.count - 1].0.index - case let .UnreadEntry(index, _): - return index - case let .ReplyCountEntry(index, _, _, _): - return index - case let .ChatInfoEntry(infoData, _): - switch infoData { - case .newThreadInfo: - return MessageIndex.absoluteUpperBound() - default: - return MessageIndex.absoluteLowerBound() - } + case let .MessageEntry(message, _, _, _, _, _): + return message.index + case let .MessageGroupEntry(_, messages, _): + return messages[messages.count - 1].0.index + case let .UnreadEntry(index, _): + return index + case let .ReplyCountEntry(index, _, _, _): + return index + case let .ChatInfoEntry(infoData, _): + switch infoData { + case .newThreadInfo: + return MessageIndex.absoluteUpperBound() + default: + return MessageIndex.absoluteLowerBound() + } } } diff --git a/submodules/TelegramUI/Components/ChatTitleView/Sources/ChatTitleComponent.swift b/submodules/TelegramUI/Components/ChatTitleView/Sources/ChatTitleComponent.swift index ac424cf01b..9b62a00244 100644 --- a/submodules/TelegramUI/Components/ChatTitleView/Sources/ChatTitleComponent.swift +++ b/submodules/TelegramUI/Components/ChatTitleView/Sources/ChatTitleComponent.swift @@ -254,6 +254,7 @@ public final class ChatTitleComponent: Component { private let contentContainer: UIView private let title = ComponentView() private var subtitleNode: ChatTitleActivityNode? + private var activityMeasureSubtitleNode: ChatTitleActivityNode? private var leftIcon: ComponentView? private var rightIcon: ComponentView? private var credibilityIcon: ComponentView? @@ -1003,9 +1004,25 @@ public final class ChatTitleComponent: Component { let _ = subtitleNode.transitionToState(state, animation: transition.animation.isImmediate ? .none : .slide) let subtitleSize = subtitleNode.updateLayout(CGSize(width: availableSize.width - containerSideInset * 2.0, height: 100.0), alignment: .center) + var minSubtitleWidth: CGFloat? + let activityMeasureSubtitleNode: ChatTitleActivityNode + if let current = self.activityMeasureSubtitleNode { + activityMeasureSubtitleNode = current + } else { + activityMeasureSubtitleNode = ChatTitleActivityNode() + self.activityMeasureSubtitleNode = activityMeasureSubtitleNode + } + let measureTypingTextString = NSAttributedString(string: component.strings.Conversation_typing, font: subtitleFont, textColor: .black) + let _ = activityMeasureSubtitleNode.transitionToState(.typingText(measureTypingTextString, .black), animation: .none) + let activityMeasureSubtitleSize = activityMeasureSubtitleNode.updateLayout(CGSize(width: availableSize.width - containerSideInset * 2.0, height: 100.0), alignment: .center) + minSubtitleWidth = activityMeasureSubtitleSize.width + var contentSize = titleSize contentSize.width += titleLeftIconsWidth + titleRightIconsWidth contentSize.width = max(contentSize.width, subtitleSize.width) + if let minSubtitleWidth { + contentSize.width = max(contentSize.width, minSubtitleWidth) + } contentSize.height += subtitleSize.height let containerSize = CGSize(width: contentSize.width + containerSideInset * 2.0, height: 44.0) diff --git a/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift b/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift index 6c38725c19..ce27144179 100644 --- a/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift +++ b/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift @@ -807,7 +807,7 @@ public extension GlassBackgroundView { } } - addShadow(context, true, CGPoint(), 30.0, 0.0, UIColor(white: 0.0, alpha: 0.075), .normal) + addShadow(context, true, CGPoint(), 30.0, 0.0, UIColor(white: 0.0, alpha: 0.045), .normal) addShadow(context, true, CGPoint(), 20.0, 0.0, UIColor(white: 0.0, alpha: 0.01), .normal) var a: CGFloat = 0.0 diff --git a/submodules/TelegramUI/Components/HeaderPanelContainerComponent/Sources/HeaderPanelContainerComponent.swift b/submodules/TelegramUI/Components/HeaderPanelContainerComponent/Sources/HeaderPanelContainerComponent.swift index 87b6aaf2f2..b48bdf91b5 100644 --- a/submodules/TelegramUI/Components/HeaderPanelContainerComponent/Sources/HeaderPanelContainerComponent.swift +++ b/submodules/TelegramUI/Components/HeaderPanelContainerComponent/Sources/HeaderPanelContainerComponent.swift @@ -239,13 +239,17 @@ public final class HeaderPanelContainerComponent: Component { self.panelViews.removeValue(forKey: key) } - transition.setFrame(view: self.backgroundContainer, frame: CGRect(origin: CGPoint(), size: size)) - self.backgroundContainer.update(size: size, isDark: component.theme.overallDarkAppearance, transition: transition) + let backgroundSize = CGSize(width: size.width, height: max(40.0, size.height)) - let backgroundFrame = CGRect(origin: CGPoint(x: sideInset, y: 0.0), size: CGSize(width: size.width - sideInset * 2.0, height: size.height)) + transition.setFrame(view: self.backgroundContainer, frame: CGRect(origin: CGPoint(), size: backgroundSize)) + self.backgroundContainer.update(size: backgroundSize, isDark: component.theme.overallDarkAppearance, transition: transition) + + let backgroundFrame = CGRect(origin: CGPoint(x: sideInset, y: 0.0), size: CGSize(width: size.width - sideInset * 2.0, height: backgroundSize.height)) transition.setFrame(view: self.backgroundView, frame: backgroundFrame) self.backgroundView.update(size: backgroundFrame.size, cornerRadius: 20.0, isDark: component.theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: UIColor(white: component.theme.overallDarkAppearance ? 0.0 : 1.0, alpha: 0.6)), isInteractive: true, transition: transition) + transition.setAlpha(view: self.backgroundContainer, alpha: (component.tabs != nil || !component.panels.isEmpty) ? 1.0 : 0.0) + transition.setFrame(view: self.contentContainer, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size)) self.contentContainer.layer.cornerRadius = 20.0 diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoChatPaneNode/Sources/PeerInfoChatPaneNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoChatPaneNode/Sources/PeerInfoChatPaneNode.swift index 4b7d6c5e55..f591cb186f 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoChatPaneNode/Sources/PeerInfoChatPaneNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoChatPaneNode/Sources/PeerInfoChatPaneNode.swift @@ -182,8 +182,6 @@ public final class PeerInfoChatPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScro self.addSubnode(self.chatController.displayNode) self.chatController.displayNode.clipsToBounds = true - self.view.addSubview(self.coveringView) - self.chatController.stateUpdated = { [weak self] transition in guard let self else { return @@ -276,9 +274,9 @@ public final class PeerInfoChatPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScro public func update(size: CGSize, topInset: CGFloat, sideInset: CGFloat, bottomInset: CGFloat, deviceMetrics: DeviceMetrics, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, expandProgress: CGFloat, navigationHeight: CGFloat, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) { self.currentParams = (size, topInset, sideInset, bottomInset, visibleHeight, isScrollingLockedAtTop, expandProgress, presentationData) - let fullHeight = navigationHeight + size.height + let fullHeight = size.height - topInset - let chatFrame = CGRect(origin: CGPoint(x: 0.0, y: -navigationHeight), size: CGSize(width: size.width, height: fullHeight)) + let chatFrame = CGRect(origin: CGPoint(x: 0.0, y: topInset), size: CGSize(width: size.width, height: fullHeight)) if !self.chatController.displayNode.bounds.isEmpty { if let contextController = self.chatController.visibleContextController as? ContextController { @@ -293,7 +291,7 @@ public final class PeerInfoChatPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScro let combinedBottomInset = bottomInset transition.updateFrame(node: self.chatController.displayNode, frame: chatFrame) self.chatController.updateIsScrollingLockedAtTop(isScrollingLockedAtTop: isScrollingLockedAtTop) - self.chatController.containerLayoutUpdated(ContainerViewLayout(size: chatFrame.size, metrics: LayoutMetrics(widthClass: .compact, heightClass: .compact, orientation: nil), deviceMetrics: deviceMetrics, intrinsicInsets: UIEdgeInsets(top: topInset + navigationHeight, left: sideInset, bottom: combinedBottomInset, right: sideInset), safeInsets: UIEdgeInsets(top: navigationHeight + topInset + 4.0, left: sideInset, bottom: combinedBottomInset, right: sideInset), additionalInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: transition) + self.chatController.containerLayoutUpdated(ContainerViewLayout(size: chatFrame.size, metrics: LayoutMetrics(widthClass: .compact, heightClass: .compact, orientation: nil), deviceMetrics: deviceMetrics, intrinsicInsets: UIEdgeInsets(top: 0.0, left: sideInset, bottom: combinedBottomInset, right: sideInset), safeInsets: UIEdgeInsets(top: 0.0 + 4.0, left: sideInset, bottom: combinedBottomInset, right: sideInset), additionalInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: transition) } override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift index 46697293d8..d9a85eb9f0 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift @@ -823,7 +823,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr var scrollOffset: CGFloat = max(0.0, size.height - params.visibleHeight) let effectiveBottomInset = max(buttonInsets.bottom, bottomInset) - var bottomPanelHeight = effectiveBottomInset + panelButtonSize.height + 8.0 + let bottomPanelHeight = effectiveBottomInset + panelButtonSize.height + 8.0 if params.visibleHeight < 110.0 { scrollOffset -= bottomPanelHeight } @@ -838,8 +838,6 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr panelTransition.setFrame(view: panelContentContainer, frame: CGRect(origin: CGPoint(x: 0.0, y: size.height - bottomPanelHeight), size: CGSize(width: size.width, height: bottomPanelHeight))) if self.canManage { - bottomPanelHeight -= 9.0 - let panelCheck: ComponentView if let current = self.panelCheck { panelCheck = current @@ -904,7 +902,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr if panelCheckView.superview == nil { panelContentContainer.addSubview(panelCheckView) } - panelCheckView.frame = CGRect(origin: CGPoint(x: floor((size.width - panelCheckSize.width) / 2.0), y: 16.0), size: panelCheckSize) + panelCheckView.frame = CGRect(origin: CGPoint(x: floor((size.width - panelCheckSize.width) / 2.0), y: 16.0 + 16.0), size: panelCheckSize) } if let panelButtonView = panelButton.view { panelButtonView.isHidden = true diff --git a/submodules/TelegramUI/Components/Settings/PasskeysScreen/Sources/PasskeysScreen.swift b/submodules/TelegramUI/Components/Settings/PasskeysScreen/Sources/PasskeysScreen.swift index 01f69b0b3e..02ee5142e8 100644 --- a/submodules/TelegramUI/Components/Settings/PasskeysScreen/Sources/PasskeysScreen.swift +++ b/submodules/TelegramUI/Components/Settings/PasskeysScreen/Sources/PasskeysScreen.swift @@ -404,7 +404,7 @@ public final class PasskeysScreen: ViewControllerComponentContainer { public init(context: AccountContext, displaySkip: Bool, initialPasskeysData: [TelegramPasskey]?, passkeysDataUpdated: @escaping ([TelegramPasskey]) -> Void, completion: @escaping () -> Void, cancel: @escaping () -> Void) { self.context = context - super.init(context: context, component: PasskeysScreenComponent(context: context, displaySkip: displaySkip, initialPasskeysData: initialPasskeysData, passkeysDataUpdated: passkeysDataUpdated, completion: completion, cancel: cancel), navigationBarAppearance: .default) + super.init(context: context, component: PasskeysScreenComponent(context: context, displaySkip: displaySkip, initialPasskeysData: initialPasskeysData, passkeysDataUpdated: passkeysDataUpdated, completion: completion, cancel: cancel), navigationBarAppearance: .transparent) } required public init(coder aDecoder: NSCoder) { diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerOpenPeer.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerOpenPeer.swift index a97982eb39..1c93cb42fd 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerOpenPeer.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerOpenPeer.swift @@ -357,7 +357,9 @@ extension ChatControllerImpl { }))) } - items.append(.separator) + if !items.isEmpty { + items.append(.separator) + } items.append(.action(ContextMenuActionItem(text: strings.Conversation_Search, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Search"), color: theme.contextMenu.primaryColor) }, action: { [weak self] action in diff --git a/submodules/TelegramUI/Sources/ChatHistoryEntriesForView.swift b/submodules/TelegramUI/Sources/ChatHistoryEntriesForView.swift index 7f30ffde06..44097d730c 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryEntriesForView.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryEntriesForView.swift @@ -37,6 +37,7 @@ func chatHistoryEntriesForView( currentState: ChatHistoryEntriesForViewState, context: AccountContext, location: ChatLocation, + subject: ChatControllerSubject?, view: MessageHistoryView, includeUnreadEntry: Bool, includeEmptyEntry: Bool, @@ -331,7 +332,10 @@ func chatHistoryEntriesForView( } } var attributes = attributes - attributes.displayContinueThreadFooter = true + if let subject, case .pinnedMessages = subject { + } else { + attributes.displayContinueThreadFooter = true + } entries[i] = .MessageEntry(message, presentationData, isRead, location, selection, attributes) break outer default: @@ -507,7 +511,12 @@ func chatHistoryEntriesForView( entries.insert(.ChatInfoEntry(.botInfo(title: "", text: presentationData.strings.VerificationCodes_DescriptionText, photo: nil, video: nil), presentationData), at: 0) } else if let cachedPeerData = cachedPeerData as? CachedUserData { if let botInfo = cachedPeerData.botInfo, !botInfo.description.isEmpty { - entries.insert(.ChatInfoEntry(.botInfo(title: presentationData.strings.Bot_DescriptionTitle, text: botInfo.description, photo: botInfo.photo, video: botInfo.video), presentationData), at: 0) + if location.threadId == nil { + if let subject, case .pinnedMessages = subject { + } else { + entries.insert(.ChatInfoEntry(.botInfo(title: presentationData.strings.Bot_DescriptionTitle, text: botInfo.description, photo: botInfo.photo, video: botInfo.video), presentationData), at: 0) + } + } } else if let peerStatusSettings = cachedPeerData.peerStatusSettings, peerStatusSettings.registrationDate != nil || peerStatusSettings.phoneCountry != nil { if peerStatusSettings.flags.contains(.canAddContact) || peerStatusSettings.flags.contains(.canReport) || peerStatusSettings.flags.contains(.canBlock) { @@ -681,7 +690,10 @@ func chatHistoryEntriesForView( } } if addBotForumHeader { - entries.append(.ChatInfoEntry(.newThreadInfo, presentationData)) + if let subject, case .pinnedMessages = subject { + } else { + entries.append(.ChatInfoEntry(.newThreadInfo, presentationData)) + } } if includeEmbeddedSavedChatInfo, let peerId = location.peerId { if !view.isLoading && view.laterId == nil { diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index d6134e835c..eec79b5ee3 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -2090,6 +2090,7 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto currentState: previousChatHistoryEntriesForViewState, context: context, location: chatLocation, + subject: subject, view: view, includeUnreadEntry: mode == .bubbles, includeEmptyEntry: mode == .bubbles && tag == nil, @@ -2323,6 +2324,9 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto } var keyboardButtonsMessage = view.topTaggedMessages.first + if keyboardButtonsMessage != nil && keyboardButtonsMessage?.threadId != chatLocation.threadId { + keyboardButtonsMessage = nil + } if let keyboardButtonsMessageValue = keyboardButtonsMessage, keyboardButtonsMessageValue.isRestricted(platform: "ios", contentSettings: context.currentContentSettings.with({ $0 })) { keyboardButtonsMessage = nil } diff --git a/submodules/TelegramUI/Sources/ChatHistoryNavigationButtonNode.swift b/submodules/TelegramUI/Sources/ChatHistoryNavigationButtonNode.swift index 57811058af..616a8f9493 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryNavigationButtonNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryNavigationButtonNode.swift @@ -20,21 +20,21 @@ enum ChatHistoryNavigationButtonType { class ChatHistoryNavigationButtonNode: ContextControllerSourceNode { let containerNode: ContextExtractedContentContainingNode - let buttonNode: HighlightTrackingButtonNode private let backgroundView: GlassBackgroundView let imageView: GlassBackgroundView.ContentImageView private let badgeBackgroundView: GlassBackgroundView private let badgeTextNode: ImmediateAnimatedCountLabelNode + private var tapRecognizer: UITapGestureRecognizer? var tapped: (() -> Void)? { didSet { - if (oldValue != nil) != (self.tapped != nil) { - if self.tapped != nil { - self.buttonNode.addTarget(self, action: #selector(self.onTap), forControlEvents: .touchUpInside) - } else { - self.buttonNode.removeTarget(self, action: #selector(self.onTap), forControlEvents: .touchUpInside) - } - } + self.tapRecognizer?.isEnabled = self.tapped != nil && self.isEnabled + } + } + + var isEnabled: Bool = true { + didSet { + self.tapRecognizer?.isEnabled = self.tapped != nil && self.isEnabled } } @@ -54,7 +54,6 @@ class ChatHistoryNavigationButtonNode: ContextControllerSourceNode { self.type = type self.containerNode = ContextExtractedContentContainingNode() - self.buttonNode = HighlightTrackingButtonNode() self.backgroundView = GlassBackgroundView() @@ -80,7 +79,10 @@ class ChatHistoryNavigationButtonNode: ContextControllerSourceNode { super.init() - self.targetNodeForActivationProgress = self.buttonNode + let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.onTapGesture(_:))) + self.tapRecognizer = tapRecognizer + self.backgroundView.contentView.addGestureRecognizer(tapRecognizer) + tapRecognizer.isEnabled = false self.addSubnode(self.containerNode) @@ -89,18 +91,16 @@ class ChatHistoryNavigationButtonNode: ContextControllerSourceNode { self.containerNode.contentNode.frame = CGRect(origin: CGPoint(), size: size) self.containerNode.contentRect = CGRect(origin: CGPoint(), size: size) - self.buttonNode.frame = CGRect(origin: CGPoint(), size: size) - self.containerNode.contentNode.addSubnode(self.buttonNode) + self.containerNode.contentNode.view.addSubview(self.backgroundView) - self.buttonNode.view.addSubview(self.backgroundView) self.backgroundView.frame = CGRect(origin: CGPoint(), size: size) - self.backgroundView.update(size: size, cornerRadius: size.height * 0.5, isDark: theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7)), transition: .immediate) + self.backgroundView.update(size: size, cornerRadius: size.height * 0.5, isDark: theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7)), isInteractive: true, transition: .immediate) self.imageView.tintColor = theme.chat.inputPanel.panelControlColor self.backgroundView.contentView.addSubview(self.imageView) self.imageView.frame = CGRect(origin: CGPoint(), size: size) - self.buttonNode.view.addSubview(self.badgeBackgroundView) + self.containerNode.contentNode.view.addSubview(self.badgeBackgroundView) self.badgeBackgroundView.contentView.addSubview(self.badgeTextNode.view) self.frame = CGRect(origin: CGPoint(), size: size) @@ -143,9 +143,11 @@ class ChatHistoryNavigationButtonNode: ContextControllerSourceNode { self.absoluteRect = (rect, containerSize) } - @objc func onTap() { - if let tapped = self.tapped { - tapped() + @objc private func onTapGesture(_ recognizer: UITapGestureRecognizer) { + if case .ended = recognizer.state { + if let tapped = self.tapped { + tapped() + } } } diff --git a/submodules/TelegramUI/Sources/ChatHistoryNavigationButtons.swift b/submodules/TelegramUI/Sources/ChatHistoryNavigationButtons.swift index 190d7b524b..c860391d1f 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryNavigationButtons.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryNavigationButtons.swift @@ -183,7 +183,7 @@ final class ChatHistoryNavigationButtons: ASDisplayNode { if let down = self.directionButtonState.down { self.downButton.imageView.alpha = down.isEnabled ? 1.0 : 0.5 - self.downButton.buttonNode.isEnabled = down.isEnabled + self.downButton.isEnabled = down.isEnabled mentionsOffset += buttonSize.height + 12.0 upOffset += buttonSize.height + 12.0 @@ -203,7 +203,7 @@ final class ChatHistoryNavigationButtons: ASDisplayNode { if let up = self.directionButtonState.up { self.upButton.imageView.alpha = up.isEnabled ? 1.0 : 0.5 - self.upButton.buttonNode.isEnabled = up.isEnabled + self.upButton.isEnabled = up.isEnabled mentionsOffset += buttonSize.height + 12.0 diff --git a/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift b/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift index 02f540cad1..685ee744ad 100644 --- a/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift +++ b/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift @@ -1044,7 +1044,7 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou public private(set) var isDark: Bool? public var isDarkUpdated: (() -> Void)? - private func updateIsDark(_ isDark: Bool) { + private func updateIsDark(_ isDark: Bool?) { if self.isDark != isDark { self.isDark = isDark self.isDarkUpdated?() @@ -1206,7 +1206,11 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou if case let .file(file) = wallpaper, file.isPattern { let intensity = CGFloat(file.settings.intensity ?? 50) / 100.0 - self.updateIsDark(intensity < 0) + if intensity > 0 { + self.updateIsDark(nil) + } else { + self.updateIsDark(calculateWallpaperBrightness(from: gradientColors) <= 0.3) + } } else { self.updateIsDark(calculateWallpaperBrightness(from: gradientColors) <= 0.3) } diff --git a/submodules/WallpaperBackgroundNode/Sources/WallpaperEdgeEffectNodeImpl.swift b/submodules/WallpaperBackgroundNode/Sources/WallpaperEdgeEffectNodeImpl.swift index c3e8b3e92a..65e671345f 100644 --- a/submodules/WallpaperBackgroundNode/Sources/WallpaperEdgeEffectNodeImpl.swift +++ b/submodules/WallpaperBackgroundNode/Sources/WallpaperEdgeEffectNodeImpl.swift @@ -116,6 +116,7 @@ final class WallpaperEdgeEffectNodeImpl: ASDisplayNode, WallpaperEdgeEffectNode return } self.contentNode.contents = parentNode.contentNode.contents + self.contentNode.backgroundColor = parentNode.contentNode.backgroundColor self.contentNode.alpha = parentNode.contentNode.alpha self.contentNode.isHidden = parentNode.contentNode.isHidden }