mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
[WIP] Topics
This commit is contained in:
parent
dc9c076e45
commit
0378e1c5c4
@ -1267,7 +1267,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration,
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
//debugSaveState(basePath: basePath, name: "previous1")
|
||||
debugSaveState(basePath: basePath, name: "previous1")
|
||||
//debugRestoreState(basePath: basePath, name: "previous1")
|
||||
#endif
|
||||
|
||||
|
@ -1328,6 +1328,49 @@ public final class AccountStateManager {
|
||||
}
|
||||
}
|
||||
|
||||
func resolveNotificationSettings(list: [TelegramPeerNotificationSettings], defaultSettings: MessageNotificationSettings) -> (sound: PeerMessageSound, notify: Bool, displayContents: Bool) {
|
||||
var sound: PeerMessageSound = defaultSettings.sound
|
||||
|
||||
var notify = defaultSettings.enabled
|
||||
var displayContents = defaultSettings.displayPreviews
|
||||
|
||||
for item in list.reversed() {
|
||||
if case .default = item.messageSound {
|
||||
} else {
|
||||
sound = item.messageSound
|
||||
}
|
||||
|
||||
switch item.displayPreviews {
|
||||
case .default:
|
||||
break
|
||||
case .show:
|
||||
displayContents = true
|
||||
case .hide:
|
||||
displayContents = false
|
||||
}
|
||||
|
||||
switch item.muteState {
|
||||
case .default:
|
||||
break
|
||||
case .unmuted:
|
||||
notify = true
|
||||
case let .muted(deadline):
|
||||
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
|
||||
if deadline > timestamp {
|
||||
notify = false
|
||||
} else {
|
||||
notify = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if case .default = sound {
|
||||
sound = defaultCloudPeerNotificationSound
|
||||
}
|
||||
|
||||
return (sound, notify, displayContents)
|
||||
}
|
||||
|
||||
public func messagesForNotification(transaction: Transaction, id: MessageId, alwaysReturnMessage: Bool) -> (messages: [Message], notify: Bool, sound: PeerMessageSound, displayContents: Bool, threadData: MessageHistoryThreadData?) {
|
||||
guard let message = transaction.getMessage(id) else {
|
||||
Logger.shared.log("AccountStateManager", "notification message doesn't exist")
|
||||
@ -1335,7 +1378,6 @@ public func messagesForNotification(transaction: Transaction, id: MessageId, alw
|
||||
}
|
||||
|
||||
var notify = true
|
||||
var sound: PeerMessageSound = defaultCloudPeerNotificationSound
|
||||
var muted = false
|
||||
var displayContents = true
|
||||
var threadData: MessageHistoryThreadData?
|
||||
@ -1365,8 +1407,6 @@ public func messagesForNotification(transaction: Transaction, id: MessageId, alw
|
||||
}
|
||||
}
|
||||
|
||||
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
|
||||
|
||||
var notificationPeerId = id.peerId
|
||||
let peer = transaction.getPeer(id.peerId)
|
||||
if let peer = peer, let associatedPeerId = peer.associatedPeerId {
|
||||
@ -1376,47 +1416,38 @@ public func messagesForNotification(transaction: Transaction, id: MessageId, alw
|
||||
notificationPeerId = author.id
|
||||
}
|
||||
|
||||
var notificationSettingsStack: [TelegramPeerNotificationSettings] = []
|
||||
|
||||
if let threadId = message.threadId, let threadData = transaction.getMessageHistoryThreadInfo(peerId: message.id.peerId, threadId: threadId)?.data.get(MessageHistoryThreadData.self) {
|
||||
notificationSettingsStack.append(threadData.notificationSettings)
|
||||
}
|
||||
|
||||
if let notificationSettings = transaction.getPeerNotificationSettings(id: notificationPeerId) as? TelegramPeerNotificationSettings {
|
||||
var defaultSound: PeerMessageSound = defaultCloudPeerNotificationSound
|
||||
var defaultNotify: Bool = true
|
||||
if let globalNotificationSettings = transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications)?.get(GlobalNotificationSettings.self) {
|
||||
if id.peerId.namespace == Namespaces.Peer.CloudUser {
|
||||
defaultNotify = globalNotificationSettings.effective.privateChats.enabled
|
||||
defaultSound = globalNotificationSettings.effective.privateChats.sound
|
||||
displayContents = globalNotificationSettings.effective.privateChats.displayPreviews
|
||||
} else if id.peerId.namespace == Namespaces.Peer.SecretChat {
|
||||
defaultNotify = globalNotificationSettings.effective.privateChats.enabled
|
||||
defaultSound = globalNotificationSettings.effective.privateChats.sound
|
||||
displayContents = false
|
||||
} else if id.peerId.namespace == Namespaces.Peer.CloudChannel, let peer = peer as? TelegramChannel, case .broadcast = peer.info {
|
||||
defaultNotify = globalNotificationSettings.effective.channels.enabled
|
||||
defaultSound = globalNotificationSettings.effective.channels.sound
|
||||
displayContents = globalNotificationSettings.effective.channels.displayPreviews
|
||||
} else {
|
||||
defaultNotify = globalNotificationSettings.effective.groupChats.enabled
|
||||
defaultSound = globalNotificationSettings.effective.groupChats.sound
|
||||
displayContents = globalNotificationSettings.effective.groupChats.displayPreviews
|
||||
}
|
||||
}
|
||||
switch notificationSettings.muteState {
|
||||
case .default:
|
||||
if !defaultNotify {
|
||||
notify = false
|
||||
}
|
||||
case let .muted(until):
|
||||
if until >= timestamp {
|
||||
notify = false
|
||||
}
|
||||
case .unmuted:
|
||||
break
|
||||
}
|
||||
if case .default = notificationSettings.messageSound {
|
||||
sound = defaultSound
|
||||
} else {
|
||||
sound = notificationSettings.messageSound
|
||||
}
|
||||
notificationSettingsStack.append(notificationSettings)
|
||||
}
|
||||
|
||||
let globalNotificationSettings = transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications)?.get(GlobalNotificationSettings.self) ?? GlobalNotificationSettings.defaultSettings
|
||||
|
||||
let defaultNotificationSettings: MessageNotificationSettings
|
||||
if id.peerId.namespace == Namespaces.Peer.CloudUser {
|
||||
defaultNotificationSettings = globalNotificationSettings.effective.privateChats
|
||||
} else if id.peerId.namespace == Namespaces.Peer.SecretChat {
|
||||
defaultNotificationSettings = globalNotificationSettings.effective.privateChats
|
||||
displayContents = false
|
||||
} else if id.peerId.namespace == Namespaces.Peer.CloudChannel, let peer = peer as? TelegramChannel, case .broadcast = peer.info {
|
||||
defaultNotificationSettings = globalNotificationSettings.effective.channels
|
||||
} else {
|
||||
Logger.shared.log("AccountStateManager", "notification settings for \(notificationPeerId) are undefined")
|
||||
defaultNotificationSettings = globalNotificationSettings.effective.groupChats
|
||||
}
|
||||
|
||||
let (resolvedSound, resolvedNotify, resolvedDisplayContents) = resolveNotificationSettings(list: notificationSettingsStack, defaultSettings: defaultNotificationSettings)
|
||||
|
||||
var sound = resolvedSound
|
||||
if !resolvedNotify {
|
||||
notify = false
|
||||
}
|
||||
if !resolvedDisplayContents {
|
||||
displayContents = false
|
||||
}
|
||||
|
||||
if muted {
|
||||
@ -1425,10 +1456,10 @@ public func messagesForNotification(transaction: Transaction, id: MessageId, alw
|
||||
|
||||
if let channel = message.peers[message.id.peerId] as? TelegramChannel {
|
||||
switch channel.participationStatus {
|
||||
case .kicked, .left:
|
||||
return ([], false, sound, false, threadData)
|
||||
case .member:
|
||||
break
|
||||
case .kicked, .left:
|
||||
return ([], false, sound, false, threadData)
|
||||
case .member:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -270,14 +270,17 @@ private class AdMessagesHistoryContextImpl {
|
||||
struct CachedState: Codable, PostboxCoding {
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case timestamp
|
||||
case interPostInterval
|
||||
case messages
|
||||
}
|
||||
|
||||
var timestamp: Int32
|
||||
var interPostInterval: Int32?
|
||||
var messages: [CachedMessage]
|
||||
|
||||
init(timestamp: Int32, messages: [CachedMessage]) {
|
||||
init(timestamp: Int32, interPostInterval: Int32?, messages: [CachedMessage]) {
|
||||
self.timestamp = timestamp
|
||||
self.interPostInterval = interPostInterval
|
||||
self.messages = messages
|
||||
}
|
||||
|
||||
@ -285,6 +288,7 @@ private class AdMessagesHistoryContextImpl {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
self.timestamp = try container.decode(Int32.self, forKey: .timestamp)
|
||||
self.interPostInterval = try container.decodeIfPresent(Int32.self, forKey: .interPostInterval)
|
||||
self.messages = try container.decode([CachedMessage].self, forKey: .messages)
|
||||
}
|
||||
|
||||
@ -292,11 +296,13 @@ private class AdMessagesHistoryContextImpl {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
try container.encode(self.timestamp, forKey: .timestamp)
|
||||
try container.encodeIfPresent(self.interPostInterval, forKey: .interPostInterval)
|
||||
try container.encode(self.messages, forKey: .messages)
|
||||
}
|
||||
|
||||
init(decoder: PostboxDecoder) {
|
||||
self.timestamp = decoder.decodeInt32ForKey("timestamp", orElse: 0)
|
||||
self.interPostInterval = decoder.decodeOptionalInt32ForKey("interPostInterval")
|
||||
if let messagesData = decoder.decodeOptionalDataArrayForKey("messages") {
|
||||
self.messages = messagesData.compactMap { data -> CachedMessage? in
|
||||
return try? AdaptedPostboxDecoder().decode(CachedMessage.self, from: data)
|
||||
@ -308,6 +314,11 @@ private class AdMessagesHistoryContextImpl {
|
||||
|
||||
func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeInt32(self.timestamp, forKey: "timestamp")
|
||||
if let interPostInterval = self.interPostInterval {
|
||||
encoder.encodeInt32(interPostInterval, forKey: "interPostInterval")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "interPostInterval")
|
||||
}
|
||||
encoder.encodeDataArray(self.messages.compactMap { message -> Data? in
|
||||
return try? AdaptedPostboxEncoder().encode(message)
|
||||
}, forKey: "messages")
|
||||
@ -338,9 +349,13 @@ private class AdMessagesHistoryContextImpl {
|
||||
}
|
||||
|
||||
struct State: Equatable {
|
||||
var interPostInterval: Int32?
|
||||
var messages: [Message]
|
||||
|
||||
static func ==(lhs: State, rhs: State) -> Bool {
|
||||
if lhs.interPostInterval != rhs.interPostInterval {
|
||||
return false
|
||||
}
|
||||
if lhs.messages.count != rhs.messages.count {
|
||||
return false
|
||||
}
|
||||
@ -372,43 +387,41 @@ private class AdMessagesHistoryContextImpl {
|
||||
self.account = account
|
||||
self.peerId = peerId
|
||||
|
||||
self.stateValue = State(messages: [])
|
||||
self.stateValue = State(interPostInterval: nil, messages: [])
|
||||
|
||||
self.state.set(CachedState.getCached(postbox: account.postbox, peerId: peerId)
|
||||
|> mapToSignal { cachedState -> Signal<State, NoError> in
|
||||
if let cachedState = cachedState, cachedState.timestamp >= Int32(Date().timeIntervalSince1970) - 5 * 60 {
|
||||
return account.postbox.transaction { transaction -> State in
|
||||
return State(messages: cachedState.messages.compactMap { message -> Message? in
|
||||
return State(interPostInterval: cachedState.interPostInterval, messages: cachedState.messages.compactMap { message -> Message? in
|
||||
return message.toMessage(peerId: peerId, transaction: transaction)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
return .single(State(messages: []))
|
||||
return .single(State(interPostInterval: nil, messages: []))
|
||||
}
|
||||
})
|
||||
|
||||
let signal: Signal<[Message], NoError> = account.postbox.transaction { transaction -> Api.InputChannel? in
|
||||
let signal: Signal<(interPostInterval: Int32?, messages: [Message]), NoError> = account.postbox.transaction { transaction -> Api.InputChannel? in
|
||||
return transaction.getPeer(peerId).flatMap(apiInputChannel)
|
||||
}
|
||||
|> mapToSignal { inputChannel -> Signal<[Message], NoError> in
|
||||
|> mapToSignal { inputChannel -> Signal<(interPostInterval: Int32?, messages: [Message]), NoError> in
|
||||
guard let inputChannel = inputChannel else {
|
||||
return .single([])
|
||||
return .single((nil, []))
|
||||
}
|
||||
return account.network.request(Api.functions.channels.getSponsoredMessages(channel: inputChannel))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.messages.SponsoredMessages?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<[Message], NoError> in
|
||||
|> mapToSignal { result -> Signal<(interPostInterval: Int32?, messages: [Message]), NoError> in
|
||||
guard let result = result else {
|
||||
return .single([])
|
||||
return .single((nil, []))
|
||||
}
|
||||
|
||||
return account.postbox.transaction { transaction -> [Message] in
|
||||
return account.postbox.transaction { transaction -> (interPostInterval: Int32?, messages: [Message]) in
|
||||
switch result {
|
||||
case let .sponsoredMessages(_, postsBetween, messages, chats, users):
|
||||
let _ = postsBetween
|
||||
|
||||
var peers: [Peer] = []
|
||||
var peerPresences: [PeerId: Api.User] = [:]
|
||||
|
||||
@ -501,24 +514,24 @@ private class AdMessagesHistoryContextImpl {
|
||||
}
|
||||
}
|
||||
|
||||
CachedState.setCached(transaction: transaction, peerId: peerId, state: CachedState(timestamp: Int32(Date().timeIntervalSince1970), messages: parsedMessages))
|
||||
CachedState.setCached(transaction: transaction, peerId: peerId, state: CachedState(timestamp: Int32(Date().timeIntervalSince1970), interPostInterval: postsBetween, messages: parsedMessages))
|
||||
|
||||
return parsedMessages.compactMap { message -> Message? in
|
||||
return (postsBetween, parsedMessages.compactMap { message -> Message? in
|
||||
return message.toMessage(peerId: peerId, transaction: transaction)
|
||||
}
|
||||
})
|
||||
case .sponsoredMessagesEmpty:
|
||||
return []
|
||||
return (nil, [])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.disposable.set((signal
|
||||
|> deliverOn(self.queue)).start(next: { [weak self] messages in
|
||||
|> deliverOn(self.queue)).start(next: { [weak self] interPostInterval, messages in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.stateValue = State(messages: messages)
|
||||
strongSelf.stateValue = State(interPostInterval: interPostInterval, messages: messages)
|
||||
}))
|
||||
}
|
||||
|
||||
@ -549,13 +562,13 @@ public class AdMessagesHistoryContext {
|
||||
private let queue = Queue()
|
||||
private let impl: QueueLocalObject<AdMessagesHistoryContextImpl>
|
||||
|
||||
public var state: Signal<[Message], NoError> {
|
||||
public var state: Signal<(interPostInterval: Int32?, messages: [Message]), NoError> {
|
||||
return Signal { subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
self.impl.with { impl in
|
||||
let stateDisposable = impl.state.get().start(next: { state in
|
||||
subscriber.putNext(state.messages)
|
||||
subscriber.putNext((state.interPostInterval, state.messages))
|
||||
})
|
||||
disposable.set(stateDisposable)
|
||||
}
|
||||
|
@ -324,7 +324,7 @@ final class AuthorizedApplicationContext {
|
||||
|
||||
var chatIsVisible = false
|
||||
if let topController = strongSelf.rootController.topViewController as? ChatControllerImpl, topController.traceVisibility() {
|
||||
if topController.chatLocation.peerId == firstMessage.id.peerId {
|
||||
if topController.chatLocation.peerId == firstMessage.id.peerId, (topController.chatLocation.threadId == nil || topController.chatLocation.threadId == firstMessage.threadId) {
|
||||
chatIsVisible = true
|
||||
}
|
||||
}
|
||||
@ -335,7 +335,7 @@ final class AuthorizedApplicationContext {
|
||||
|
||||
if !chatIsVisible {
|
||||
strongSelf.mainWindow.forEachViewController({ controller in
|
||||
if let controller = controller as? ChatControllerImpl, controller.chatLocation.peerId == chatLocation.peerId, controller.chatLocation.threadId == chatLocation.threadId {
|
||||
if let controller = controller as? ChatControllerImpl, controller.chatLocation.peerId == chatLocation.peerId, (chatLocation.threadId == nil || chatLocation.threadId == controller.chatLocation.threadId) {
|
||||
chatIsVisible = true
|
||||
return false
|
||||
}
|
||||
@ -415,14 +415,14 @@ final class AuthorizedApplicationContext {
|
||||
return true
|
||||
}
|
||||
|
||||
if let topController = strongSelf.rootController.topViewController as? ChatControllerImpl, topController.chatLocation.peerId == chatLocation.peerId, topController.chatLocation.threadId == chatLocation.threadId {
|
||||
if let topController = strongSelf.rootController.topViewController as? ChatControllerImpl, topController.chatLocation.peerId == chatLocation.peerId, (topController.chatLocation.threadId == nil || topController.chatLocation.threadId == chatLocation.threadId) {
|
||||
strongSelf.notificationController.removeItemsWithGroupingKey(firstMessage.id.peerId)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
for controller in strongSelf.rootController.viewControllers {
|
||||
if let controller = controller as? ChatControllerImpl, controller.chatLocation.peerId == chatLocation.peerId, controller.chatLocation.threadId == chatLocation.threadId {
|
||||
if let controller = controller as? ChatControllerImpl, controller.chatLocation.peerId == chatLocation.peerId, (controller.chatLocation.threadId == nil || controller.chatLocation.threadId == chatLocation.threadId) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -5565,9 +5565,23 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
|
||||
private func topPinnedMessageSignal(latest: Bool) -> Signal<ChatPinnedMessage?, NoError> {
|
||||
let topPinnedMessage: Signal<ChatPinnedMessage?, NoError>
|
||||
var pinnedPeerId: EnginePeer.Id?
|
||||
let threadId = self.chatLocation.threadId
|
||||
|
||||
switch self.chatLocation {
|
||||
case let .peer(peerId):
|
||||
case let .peer(id):
|
||||
pinnedPeerId = id
|
||||
case let .replyThread(message):
|
||||
if message.isForumPost {
|
||||
pinnedPeerId = self.chatLocation.peerId
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
if let peerId = pinnedPeerId {
|
||||
let topPinnedMessage: Signal<ChatPinnedMessage?, NoError>
|
||||
|
||||
struct ReferenceMessage {
|
||||
var id: MessageId
|
||||
var isScrolled: Bool
|
||||
@ -5611,7 +5625,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
location = .Initial(count: count)
|
||||
}
|
||||
|
||||
return (chatHistoryViewForLocation(ChatHistoryLocationInput(content: location, id: 0), ignoreMessagesInTimestampRange: nil, context: context, chatLocation: .peer(id: peerId), chatLocationContextHolder: Atomic<ChatLocationContextHolder?>(value: nil), scheduled: false, fixedCombinedReadStates: nil, tagMask: MessageTags.pinned, appendMessagesFromTheSameGroup: false, additionalData: [], orderStatistics: .combinedLocation)
|
||||
let chatLocation: ChatLocation
|
||||
if let threadId {
|
||||
chatLocation = .replyThread(message: ChatReplyThreadMessage(messageId: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false))
|
||||
} else {
|
||||
chatLocation = .peer(id: peerId)
|
||||
}
|
||||
|
||||
return (chatHistoryViewForLocation(ChatHistoryLocationInput(content: location, id: 0), ignoreMessagesInTimestampRange: nil, context: context, chatLocation: chatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>(value: nil), scheduled: false, fixedCombinedReadStates: nil, tagMask: MessageTags.pinned, appendMessagesFromTheSameGroup: false, additionalData: [], orderStatistics: .combinedLocation)
|
||||
|> castError(Bool.self)
|
||||
|> mapToSignal { update -> Signal<ChatHistoryViewUpdate, Bool> in
|
||||
switch update {
|
||||
@ -5831,10 +5852,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return message
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
case .replyThread, .feed:
|
||||
|
||||
return topPinnedMessage
|
||||
} else {
|
||||
return .single(nil)
|
||||
}
|
||||
return topPinnedMessage
|
||||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
@ -6241,7 +6263,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
switch strongSelf.chatLocation {
|
||||
case let .replyThread(replyThreadMessage):
|
||||
if isForum {
|
||||
pinnedMessageId = nil
|
||||
pinnedMessageId = topPinnedMessage?.message.id
|
||||
pinnedMessage = topPinnedMessage
|
||||
} else {
|
||||
if isTopReplyThreadMessageShown {
|
||||
pinnedMessageId = nil
|
||||
@ -8325,7 +8348,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}, unblockPeer: { [weak self] in
|
||||
self?.unblockPeer()
|
||||
}, pinMessage: { [weak self] messageId, contextController in
|
||||
if let strongSelf = self, case let .peer(currentPeerId) = strongSelf.chatLocation {
|
||||
if let strongSelf = self, let currentPeerId = strongSelf.chatLocation.peerId {
|
||||
if let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer {
|
||||
if strongSelf.canManagePin() {
|
||||
let pinAction: (Bool, Bool) -> Void = { notify, forThisPeerOnlyIfPossible in
|
||||
|
@ -1052,13 +1052,15 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
var extraTransition = transition
|
||||
if let titleAccessoryPanelNode = titlePanelForChatPresentationInterfaceState(self.chatPresentationInterfaceState, context: self.context, currentPanel: self.titleAccessoryPanelNode, controllerInteraction: self.controllerInteraction, interfaceInteraction: self.interfaceInteraction) {
|
||||
if self.titleAccessoryPanelNode != titleAccessoryPanelNode {
|
||||
dismissedTitleAccessoryPanelNode = self.titleAccessoryPanelNode
|
||||
dismissedTitleAccessoryPanelNode = self.titleAccessoryPanelNode
|
||||
self.titleAccessoryPanelNode = titleAccessoryPanelNode
|
||||
immediatelyLayoutTitleAccessoryPanelNodeAndAnimateAppearance = true
|
||||
self.titleAccessoryPanelContainer.addSubnode(titleAccessoryPanelNode)
|
||||
|
||||
titleAccessoryPanelNode.clipsToBounds = true
|
||||
extraTransition = .animated(duration: 0.2, curve: .easeInOut)
|
||||
if transition.isAnimated {
|
||||
extraTransition = .animated(duration: 0.2, curve: .easeInOut)
|
||||
}
|
||||
}
|
||||
|
||||
let layoutResult = titleAccessoryPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, transition: immediatelyLayoutTitleAccessoryPanelNodeAndAnimateAppearance ? .immediate : transition, interfaceState: self.chatPresentationInterfaceState)
|
||||
|
@ -25,7 +25,7 @@ func chatHistoryEntriesForView(
|
||||
customChannelDiscussionReadState: MessageId?,
|
||||
customThreadOutgoingReadState: MessageId?,
|
||||
cachedData: CachedPeerData?,
|
||||
adMessages: [Message]
|
||||
adMessages: (interPostInterval: Int32?, messages: [Message])
|
||||
) -> [ChatHistoryEntry] {
|
||||
if historyAppearsCleared {
|
||||
return []
|
||||
@ -329,9 +329,9 @@ func chatHistoryEntriesForView(
|
||||
}
|
||||
|
||||
if view.laterId == nil && !view.isLoading {
|
||||
if !entries.isEmpty, case let .MessageEntry(lastMessage, _, _, _, _, _) = entries[entries.count - 1], !adMessages.isEmpty {
|
||||
if !entries.isEmpty, case let .MessageEntry(lastMessage, _, _, _, _, _) = entries[entries.count - 1], !adMessages.messages.isEmpty {
|
||||
var nextAdMessageId: Int32 = 1
|
||||
for message in adMessages {
|
||||
if let message = adMessages.messages.first {
|
||||
let updatedMessage = Message(
|
||||
stableId: UInt32.max - 1 - UInt32(nextAdMessageId),
|
||||
stableVersion: message.stableVersion,
|
||||
|
@ -638,14 +638,14 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
default:
|
||||
break
|
||||
}
|
||||
var adMessages: Signal<[Message], NoError>
|
||||
var adMessages: Signal<(interPostInterval: Int32?, messages: [Message]), NoError>
|
||||
if case .bubbles = mode, let peerId = displayAdPeer {
|
||||
let adMessagesContext = context.engine.messages.adMessages(peerId: peerId)
|
||||
self.adMessagesContext = adMessagesContext
|
||||
adMessages = adMessagesContext.state
|
||||
} else {
|
||||
self.adMessagesContext = nil
|
||||
adMessages = .single([])
|
||||
adMessages = .single((nil, []))
|
||||
}
|
||||
|
||||
/*if case .bubbles = mode, let peerId = sparseScrollPeerId {
|
||||
@ -661,7 +661,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
super.init()
|
||||
|
||||
adMessages = adMessages
|
||||
|> afterNext { [weak self] messages in
|
||||
|> afterNext { [weak self] interPostInterval, messages in
|
||||
Queue.mainQueue().async {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
|
@ -1250,7 +1250,17 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
}
|
||||
}
|
||||
|
||||
if data.canPin && !isMigrated, case .peer = chatPresentationInterfaceState.chatLocation {
|
||||
var canPin = data.canPin
|
||||
if case let .replyThread(message) = chatPresentationInterfaceState.chatLocation {
|
||||
if !message.isForumPost {
|
||||
canPin = false
|
||||
}
|
||||
}
|
||||
if isMigrated {
|
||||
canPin = false
|
||||
}
|
||||
|
||||
if canPin {
|
||||
var pinnedSelectedMessageId: MessageId?
|
||||
for message in messages {
|
||||
if message.tags.contains(.pinned) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user