mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 09:20:08 +00:00
[WIP] Monoforums
This commit is contained in:
parent
28f246749f
commit
a39313a4bb
@ -23,6 +23,7 @@ swift_library(
|
|||||||
"//submodules/Components/BlurredBackgroundComponent",
|
"//submodules/Components/BlurredBackgroundComponent",
|
||||||
"//submodules/TelegramUI/Components/EmojiStatusComponent",
|
"//submodules/TelegramUI/Components/EmojiStatusComponent",
|
||||||
"//submodules/Components/BundleIconComponent",
|
"//submodules/Components/BundleIconComponent",
|
||||||
|
"//submodules/AvatarNode",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import AccountContext
|
|||||||
import BlurredBackgroundComponent
|
import BlurredBackgroundComponent
|
||||||
import EmojiStatusComponent
|
import EmojiStatusComponent
|
||||||
import BundleIconComponent
|
import BundleIconComponent
|
||||||
|
import AvatarNode
|
||||||
|
|
||||||
public final class ChatSidePanelEnvironment: Equatable {
|
public final class ChatSidePanelEnvironment: Equatable {
|
||||||
public let insets: UIEdgeInsets
|
public let insets: UIEdgeInsets
|
||||||
@ -111,6 +112,7 @@ public final class ChatSideTopicsPanel: Component {
|
|||||||
private let containerButton: HighlightTrackingButton
|
private let containerButton: HighlightTrackingButton
|
||||||
|
|
||||||
private let icon = ComponentView<Empty>()
|
private let icon = ComponentView<Empty>()
|
||||||
|
private var avatarNode: AvatarNode?
|
||||||
private let title = ComponentView<Empty>()
|
private let title = ComponentView<Empty>()
|
||||||
|
|
||||||
init(context: AccountContext, action: @escaping (() -> Void), contextGesture: @escaping (ContextGesture, ContextExtractedContentContainingNode) -> Void) {
|
init(context: AccountContext, action: @escaping (() -> Void), contextGesture: @escaping (ContextGesture, ContextExtractedContentContainingNode) -> Void) {
|
||||||
@ -204,7 +206,7 @@ public final class ChatSideTopicsPanel: Component {
|
|||||||
containerSize: CGSize(width: 30.0, height: 30.0)
|
containerSize: CGSize(width: 30.0, height: 30.0)
|
||||||
)
|
)
|
||||||
|
|
||||||
let titleText: String = item.item.threadData?.info.title ?? "Topic"
|
let titleText: String = item.item.renderedPeer.chatMainPeer?.compactDisplayTitle ?? " "
|
||||||
let titleSize = self.title.update(
|
let titleSize = self.title.update(
|
||||||
transition: .immediate,
|
transition: .immediate,
|
||||||
component: AnyComponent(MultilineTextComponent(
|
component: AnyComponent(MultilineTextComponent(
|
||||||
@ -228,6 +230,33 @@ public final class ChatSideTopicsPanel: Component {
|
|||||||
self.containerButton.addSubview(iconView)
|
self.containerButton.addSubview(iconView)
|
||||||
}
|
}
|
||||||
iconView.frame = iconFrame
|
iconView.frame = iconFrame
|
||||||
|
|
||||||
|
if "".isEmpty {
|
||||||
|
iconView.isHidden = true
|
||||||
|
|
||||||
|
let avatarNode: AvatarNode
|
||||||
|
if let current = self.avatarNode {
|
||||||
|
avatarNode = current
|
||||||
|
} else {
|
||||||
|
avatarNode = AvatarNode(font: avatarPlaceholderFont(size: 11.0))
|
||||||
|
self.avatarNode = avatarNode
|
||||||
|
self.containerButton.addSubview(avatarNode.view)
|
||||||
|
}
|
||||||
|
avatarNode.frame = iconFrame
|
||||||
|
avatarNode.updateSize(size: iconFrame.size)
|
||||||
|
|
||||||
|
if let peer = item.item.renderedPeer.chatMainPeer {
|
||||||
|
if peer.smallProfileImage != nil {
|
||||||
|
avatarNode.setPeerV2(context: context, theme: theme, peer: peer, overrideImage: nil, emptyColor: .gray, clipStyle: .round, synchronousLoad: false, displayDimensions: iconFrame.size)
|
||||||
|
} else {
|
||||||
|
avatarNode.setPeer(context: context, theme: theme, peer: peer, overrideImage: nil, emptyColor: .gray, clipStyle: .round, synchronousLoad: false, displayDimensions: iconFrame.size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if let avatarNode = self.avatarNode {
|
||||||
|
self.avatarNode = nil
|
||||||
|
avatarNode.view.removeFromSuperview()
|
||||||
|
iconView.isHidden = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let titleView = self.title.view {
|
if let titleView = self.title.view {
|
||||||
@ -572,123 +601,54 @@ public final class ChatSideTopicsPanel: Component {
|
|||||||
self.state = state
|
self.state = state
|
||||||
|
|
||||||
if self.component == nil {
|
if self.component == nil {
|
||||||
let viewKey: PostboxViewKey = .messageHistoryThreadIndex(
|
let viewKey: PostboxViewKey = .savedMessagesIndex(peerId: component.peerId)
|
||||||
id: component.peerId,
|
let interfaceStateKey: PostboxViewKey = .chatInterfaceState(peerId: component.peerId)
|
||||||
summaryComponents: ChatListEntrySummaryComponents(
|
|
||||||
components: [
|
|
||||||
ChatListEntryMessageTagSummaryKey(
|
|
||||||
tag: .unseenPersonalMessage,
|
|
||||||
actionType: PendingMessageActionType.consumeUnseenPersonalMessage
|
|
||||||
): ChatListEntrySummaryComponents.Component(
|
|
||||||
tagSummary: ChatListEntryMessageTagSummaryComponent(namespace: Namespaces.Message.Cloud),
|
|
||||||
actionsSummary: ChatListEntryPendingMessageActionsSummaryComponent(namespace: Namespaces.Message.Cloud)
|
|
||||||
),
|
|
||||||
ChatListEntryMessageTagSummaryKey(
|
|
||||||
tag: .unseenReaction,
|
|
||||||
actionType: PendingMessageActionType.readReaction
|
|
||||||
): ChatListEntrySummaryComponents.Component(
|
|
||||||
tagSummary: ChatListEntryMessageTagSummaryComponent(namespace: Namespaces.Message.Cloud),
|
|
||||||
actionsSummary: ChatListEntryPendingMessageActionsSummaryComponent(namespace: Namespaces.Message.Cloud)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
let readStateKey: PostboxViewKey = .combinedReadState(peerId: component.peerId, handleThreads: false)
|
let accountPeerId = component.context.account.peerId
|
||||||
|
let threadListSignal: Signal<EngineChatList, NoError> = component.context.account.postbox.combinedView(keys: [viewKey, interfaceStateKey])
|
||||||
let threadListSignal: Signal<EngineChatList, NoError> = component.context.account.postbox.combinedView(keys: [viewKey, readStateKey])
|
|
||||||
|> map { views -> EngineChatList in
|
|> map { views -> EngineChatList in
|
||||||
guard let view = views.views[viewKey] as? MessageHistoryThreadIndexView else {
|
guard let view = views.views[viewKey] as? MessageHistorySavedMessagesIndexView else {
|
||||||
preconditionFailure()
|
preconditionFailure()
|
||||||
}
|
}
|
||||||
guard let readStateView = views.views[readStateKey] as? CombinedReadStateView else {
|
|
||||||
preconditionFailure()
|
|
||||||
}
|
|
||||||
|
|
||||||
var maxReadId: Int32 = 0
|
|
||||||
if let state = readStateView.state?.states.first(where: { $0.0 == Namespaces.Message.Cloud }) {
|
|
||||||
if case let .idBased(maxIncomingReadId, _, _, _, _) = state.1 {
|
|
||||||
maxReadId = maxIncomingReadId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var items: [EngineChatList.Item] = []
|
|
||||||
for item in view.items {
|
|
||||||
guard let peer = view.peer else {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
guard let data = item.info.get(MessageHistoryThreadData.self) else {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
let defaultPeerNotificationSettings: TelegramPeerNotificationSettings = (view.peerNotificationSettings as? TelegramPeerNotificationSettings) ?? .defaultSettings
|
|
||||||
|
|
||||||
var hasUnseenMentions = false
|
|
||||||
|
|
||||||
var isMuted = false
|
|
||||||
switch data.notificationSettings.muteState {
|
|
||||||
case .muted:
|
|
||||||
isMuted = true
|
|
||||||
case .unmuted:
|
|
||||||
isMuted = false
|
|
||||||
case .default:
|
|
||||||
if case .default = data.notificationSettings.muteState {
|
|
||||||
if case .muted = defaultPeerNotificationSettings.muteState {
|
|
||||||
isMuted = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let info = item.tagSummaryInfo[ChatListEntryMessageTagSummaryKey(
|
|
||||||
tag: .unseenPersonalMessage,
|
|
||||||
actionType: PendingMessageActionType.consumeUnseenPersonalMessage
|
|
||||||
)] {
|
|
||||||
hasUnseenMentions = (info.tagSummaryCount ?? 0) > (info.actionsSummaryCount ?? 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
var hasUnseenReactions = false
|
|
||||||
if let info = item.tagSummaryInfo[ChatListEntryMessageTagSummaryKey(
|
|
||||||
tag: .unseenReaction,
|
|
||||||
actionType: PendingMessageActionType.readReaction
|
|
||||||
)] {
|
|
||||||
hasUnseenReactions = (info.tagSummaryCount ?? 0) != 0// > (info.actionsSummaryCount ?? 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
let pinnedIndex: EngineChatList.Item.PinnedIndex
|
|
||||||
if let index = item.pinnedIndex {
|
|
||||||
pinnedIndex = .index(index)
|
|
||||||
} else {
|
|
||||||
pinnedIndex = .none
|
|
||||||
}
|
|
||||||
|
|
||||||
var topicMaxIncomingReadId = data.maxIncomingReadId
|
|
||||||
if data.maxIncomingReadId == 0 && maxReadId != 0 && Int64(maxReadId) <= item.id {
|
|
||||||
topicMaxIncomingReadId = max(topicMaxIncomingReadId, maxReadId)
|
|
||||||
}
|
|
||||||
|
|
||||||
let readCounters = EnginePeerReadCounters(state: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, .idBased(maxIncomingReadId: topicMaxIncomingReadId, maxOutgoingReadId: data.maxOutgoingReadId, maxKnownId: 1, count: data.incomingUnreadCount, markedUnread: false))]), isMuted: false)
|
|
||||||
|
|
||||||
var draft: EngineChatList.Draft?
|
var draft: EngineChatList.Draft?
|
||||||
if let embeddedState = item.embeddedInterfaceState, let _ = embeddedState.overrideChatTimestamp {
|
if let interfaceStateView = views.views[interfaceStateKey] as? ChatInterfaceStateView {
|
||||||
|
if let embeddedState = interfaceStateView.value, let _ = embeddedState.overrideChatTimestamp {
|
||||||
if let opaqueState = _internal_decodeStoredChatInterfaceState(state: embeddedState) {
|
if let opaqueState = _internal_decodeStoredChatInterfaceState(state: embeddedState) {
|
||||||
if let text = opaqueState.synchronizeableInputState?.text {
|
if let text = opaqueState.synchronizeableInputState?.text {
|
||||||
draft = EngineChatList.Draft(text: text, entities: opaqueState.synchronizeableInputState?.entities ?? [])
|
draft = EngineChatList.Draft(text: text, entities: opaqueState.synchronizeableInputState?.entities ?? [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var items: [EngineChatList.Item] = []
|
||||||
|
for item in view.items {
|
||||||
|
guard let sourcePeer = item.peer else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
let sourceId = PeerId(item.id)
|
||||||
|
|
||||||
|
var messages: [EngineMessage] = []
|
||||||
|
if let topMessage = item.topMessage {
|
||||||
|
messages.append(EngineMessage(topMessage))
|
||||||
|
}
|
||||||
|
|
||||||
|
let mappedMessageIndex = MessageIndex(id: MessageId(peerId: sourceId, namespace: item.index.id.namespace, id: item.index.id.id), timestamp: item.index.timestamp)
|
||||||
|
|
||||||
items.append(EngineChatList.Item(
|
items.append(EngineChatList.Item(
|
||||||
id: .forum(item.id),
|
id: .chatList(sourceId),
|
||||||
index: .forum(pinnedIndex: pinnedIndex, timestamp: item.index.timestamp, threadId: item.id, namespace: item.index.id.namespace, id: item.index.id.id),
|
index: .chatList(ChatListIndex(pinningIndex: item.pinnedIndex.flatMap(UInt16.init), messageIndex: mappedMessageIndex)),
|
||||||
messages: item.topMessage.flatMap { [EngineMessage($0)] } ?? [],
|
messages: messages,
|
||||||
readCounters: readCounters,
|
readCounters: nil,
|
||||||
isMuted: isMuted,
|
isMuted: false,
|
||||||
draft: draft,
|
draft: sourceId == accountPeerId ? draft : nil,
|
||||||
threadData: data,
|
threadData: nil,
|
||||||
renderedPeer: EngineRenderedPeer(peer: EnginePeer(peer)),
|
renderedPeer: EngineRenderedPeer(peer: EnginePeer(sourcePeer)),
|
||||||
presence: nil,
|
presence: nil,
|
||||||
hasUnseenMentions: hasUnseenMentions,
|
hasUnseenMentions: false,
|
||||||
hasUnseenReactions: hasUnseenReactions,
|
hasUnseenReactions: false,
|
||||||
forumTopicData: nil,
|
forumTopicData: nil,
|
||||||
topForumTopicItems: [],
|
topForumTopicItems: [],
|
||||||
hasFailed: false,
|
hasFailed: false,
|
||||||
@ -709,6 +669,7 @@ public final class ChatSideTopicsPanel: Component {
|
|||||||
hasLater: false,
|
hasLater: false,
|
||||||
isLoading: view.isLoading
|
isLoading: view.isLoading
|
||||||
)
|
)
|
||||||
|
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -884,9 +845,7 @@ public final class ChatSideTopicsPanel: Component {
|
|||||||
guard let self, let component = self.component else {
|
guard let self, let component = self.component else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guard case let .forum(topicId) = chatListItem.id else {
|
let topicId = chatListItem.renderedPeer.peerId.toInt64()
|
||||||
return
|
|
||||||
}
|
|
||||||
component.updateTopicId(topicId)
|
component.updateTopicId(topicId)
|
||||||
}, contextGesture: { gesture, sourceNode in
|
}, contextGesture: { gesture, sourceNode in
|
||||||
})
|
})
|
||||||
@ -895,7 +854,7 @@ public final class ChatSideTopicsPanel: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var isSelected = false
|
var isSelected = false
|
||||||
if case let .forum(topicId) = item.item.id, component.topicId == topicId {
|
if component.topicId == item.item.renderedPeer.peerId.toInt64() {
|
||||||
isSelected = true
|
isSelected = true
|
||||||
}
|
}
|
||||||
let itemSize = itemView.update(context: component.context, item: item, isSelected: isSelected, theme: component.theme, width: panelWidth, transition: .immediate)
|
let itemSize = itemView.update(context: component.context, item: item, isSelected: isSelected, theme: component.theme, width: panelWidth, transition: .immediate)
|
||||||
|
|||||||
@ -1133,7 +1133,7 @@ extension ChatControllerImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let savedMessagesPeerId: PeerId?
|
let savedMessagesPeerId: PeerId?
|
||||||
if case let .replyThread(replyThreadMessage) = chatLocation, replyThreadMessage.peerId == context.account.peerId {
|
if case let .replyThread(replyThreadMessage) = chatLocation, (replyThreadMessage.peerId == context.account.peerId || replyThreadMessage.isMonoforum) {
|
||||||
savedMessagesPeerId = PeerId(replyThreadMessage.threadId)
|
savedMessagesPeerId = PeerId(replyThreadMessage.threadId)
|
||||||
} else {
|
} else {
|
||||||
savedMessagesPeerId = nil
|
savedMessagesPeerId = nil
|
||||||
@ -1350,9 +1350,9 @@ extension ChatControllerImpl {
|
|||||||
let imageOverride: AvatarNodeImageOverride?
|
let imageOverride: AvatarNodeImageOverride?
|
||||||
if strongSelf.context.account.peerId == savedMessagesPeerId {
|
if strongSelf.context.account.peerId == savedMessagesPeerId {
|
||||||
imageOverride = .myNotesIcon
|
imageOverride = .myNotesIcon
|
||||||
} else if savedMessagesPeerId.isReplies {
|
} else if let peer = savedMessagesPeer?.peer, peer.id.isReplies {
|
||||||
imageOverride = .repliesIcon
|
imageOverride = .repliesIcon
|
||||||
} else if savedMessagesPeerId.isAnonymousSavedMessages {
|
} else if let peer = savedMessagesPeer?.peer, peer.id.isAnonymousSavedMessages {
|
||||||
imageOverride = .anonymousSavedMessagesIcon(isColored: true)
|
imageOverride = .anonymousSavedMessagesIcon(isColored: true)
|
||||||
} else if let peer = savedMessagesPeer?.peer, peer.isDeleted {
|
} else if let peer = savedMessagesPeer?.peer, peer.isDeleted {
|
||||||
imageOverride = .deletedIcon
|
imageOverride = .deletedIcon
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import Postbox
|
|||||||
import EmojiStatusComponent
|
import EmojiStatusComponent
|
||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import BundleIconComponent
|
import BundleIconComponent
|
||||||
|
import AvatarNode
|
||||||
|
|
||||||
final class ChatTopicListTitleAccessoryPanelNode: ChatTitleAccessoryPanelNode, ChatControllerCustomNavigationPanelNode, ASScrollViewDelegate {
|
final class ChatTopicListTitleAccessoryPanelNode: ChatTitleAccessoryPanelNode, ChatControllerCustomNavigationPanelNode, ASScrollViewDelegate {
|
||||||
private struct Params: Equatable {
|
private struct Params: Equatable {
|
||||||
@ -79,6 +80,7 @@ final class ChatTopicListTitleAccessoryPanelNode: ChatTitleAccessoryPanelNode, C
|
|||||||
private let containerButton: HighlightTrackingButton
|
private let containerButton: HighlightTrackingButton
|
||||||
|
|
||||||
private let icon = ComponentView<Empty>()
|
private let icon = ComponentView<Empty>()
|
||||||
|
private var avatarNode: AvatarNode?
|
||||||
private let title = ComponentView<Empty>()
|
private let title = ComponentView<Empty>()
|
||||||
|
|
||||||
init(context: AccountContext, action: @escaping (() -> Void), contextGesture: @escaping (ContextGesture, ContextExtractedContentContainingNode) -> Void) {
|
init(context: AccountContext, action: @escaping (() -> Void), contextGesture: @escaping (ContextGesture, ContextExtractedContentContainingNode) -> Void) {
|
||||||
@ -172,7 +174,7 @@ final class ChatTopicListTitleAccessoryPanelNode: ChatTitleAccessoryPanelNode, C
|
|||||||
containerSize: CGSize(width: 18.0, height: 18.0)
|
containerSize: CGSize(width: 18.0, height: 18.0)
|
||||||
)
|
)
|
||||||
|
|
||||||
let titleText: String = item.item.threadData?.info.title ?? "Topic"
|
let titleText: String = item.item.renderedPeer.chatMainPeer?.compactDisplayTitle ?? " "
|
||||||
let titleSize = self.title.update(
|
let titleSize = self.title.update(
|
||||||
transition: .immediate,
|
transition: .immediate,
|
||||||
component: AnyComponent(MultilineTextComponent(
|
component: AnyComponent(MultilineTextComponent(
|
||||||
@ -194,6 +196,33 @@ final class ChatTopicListTitleAccessoryPanelNode: ChatTitleAccessoryPanelNode, C
|
|||||||
self.containerButton.addSubview(iconView)
|
self.containerButton.addSubview(iconView)
|
||||||
}
|
}
|
||||||
iconView.frame = iconFrame
|
iconView.frame = iconFrame
|
||||||
|
|
||||||
|
if "".isEmpty {
|
||||||
|
iconView.isHidden = true
|
||||||
|
|
||||||
|
let avatarNode: AvatarNode
|
||||||
|
if let current = self.avatarNode {
|
||||||
|
avatarNode = current
|
||||||
|
} else {
|
||||||
|
avatarNode = AvatarNode(font: avatarPlaceholderFont(size: 7.0))
|
||||||
|
self.avatarNode = avatarNode
|
||||||
|
self.containerButton.addSubview(avatarNode.view)
|
||||||
|
}
|
||||||
|
avatarNode.frame = iconFrame
|
||||||
|
avatarNode.updateSize(size: iconFrame.size)
|
||||||
|
|
||||||
|
if let peer = item.item.renderedPeer.chatMainPeer {
|
||||||
|
if peer.smallProfileImage != nil {
|
||||||
|
avatarNode.setPeerV2(context: context, theme: theme, peer: peer, overrideImage: nil, emptyColor: .gray, clipStyle: .round, synchronousLoad: false, displayDimensions: iconFrame.size)
|
||||||
|
} else {
|
||||||
|
avatarNode.setPeer(context: context, theme: theme, peer: peer, overrideImage: nil, emptyColor: .gray, clipStyle: .round, synchronousLoad: false, displayDimensions: iconFrame.size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if let avatarNode = self.avatarNode {
|
||||||
|
self.avatarNode = nil
|
||||||
|
avatarNode.view.removeFromSuperview()
|
||||||
|
iconView.isHidden = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let titleView = self.title.view {
|
if let titleView = self.title.view {
|
||||||
@ -494,123 +523,54 @@ final class ChatTopicListTitleAccessoryPanelNode: ChatTitleAccessoryPanelNode, C
|
|||||||
|
|
||||||
self.scrollView.disablesInteractiveTransitionGestureRecognizer = true
|
self.scrollView.disablesInteractiveTransitionGestureRecognizer = true
|
||||||
|
|
||||||
let viewKey: PostboxViewKey = .messageHistoryThreadIndex(
|
let viewKey: PostboxViewKey = .savedMessagesIndex(peerId: peerId)
|
||||||
id: peerId,
|
let interfaceStateKey: PostboxViewKey = .chatInterfaceState(peerId: peerId)
|
||||||
summaryComponents: ChatListEntrySummaryComponents(
|
|
||||||
components: [
|
|
||||||
ChatListEntryMessageTagSummaryKey(
|
|
||||||
tag: .unseenPersonalMessage,
|
|
||||||
actionType: PendingMessageActionType.consumeUnseenPersonalMessage
|
|
||||||
): ChatListEntrySummaryComponents.Component(
|
|
||||||
tagSummary: ChatListEntryMessageTagSummaryComponent(namespace: Namespaces.Message.Cloud),
|
|
||||||
actionsSummary: ChatListEntryPendingMessageActionsSummaryComponent(namespace: Namespaces.Message.Cloud)
|
|
||||||
),
|
|
||||||
ChatListEntryMessageTagSummaryKey(
|
|
||||||
tag: .unseenReaction,
|
|
||||||
actionType: PendingMessageActionType.readReaction
|
|
||||||
): ChatListEntrySummaryComponents.Component(
|
|
||||||
tagSummary: ChatListEntryMessageTagSummaryComponent(namespace: Namespaces.Message.Cloud),
|
|
||||||
actionsSummary: ChatListEntryPendingMessageActionsSummaryComponent(namespace: Namespaces.Message.Cloud)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
let readStateKey: PostboxViewKey = .combinedReadState(peerId: peerId, handleThreads: false)
|
let accountPeerId = context.account.peerId
|
||||||
|
let threadListSignal: Signal<EngineChatList, NoError> = context.account.postbox.combinedView(keys: [viewKey, interfaceStateKey])
|
||||||
let threadListSignal: Signal<EngineChatList, NoError> = context.account.postbox.combinedView(keys: [viewKey, readStateKey])
|
|
||||||
|> map { views -> EngineChatList in
|
|> map { views -> EngineChatList in
|
||||||
guard let view = views.views[viewKey] as? MessageHistoryThreadIndexView else {
|
guard let view = views.views[viewKey] as? MessageHistorySavedMessagesIndexView else {
|
||||||
preconditionFailure()
|
preconditionFailure()
|
||||||
}
|
}
|
||||||
guard let readStateView = views.views[readStateKey] as? CombinedReadStateView else {
|
|
||||||
preconditionFailure()
|
|
||||||
}
|
|
||||||
|
|
||||||
var maxReadId: Int32 = 0
|
|
||||||
if let state = readStateView.state?.states.first(where: { $0.0 == Namespaces.Message.Cloud }) {
|
|
||||||
if case let .idBased(maxIncomingReadId, _, _, _, _) = state.1 {
|
|
||||||
maxReadId = maxIncomingReadId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var items: [EngineChatList.Item] = []
|
|
||||||
for item in view.items {
|
|
||||||
guard let peer = view.peer else {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
guard let data = item.info.get(MessageHistoryThreadData.self) else {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
let defaultPeerNotificationSettings: TelegramPeerNotificationSettings = (view.peerNotificationSettings as? TelegramPeerNotificationSettings) ?? .defaultSettings
|
|
||||||
|
|
||||||
var hasUnseenMentions = false
|
|
||||||
|
|
||||||
var isMuted = false
|
|
||||||
switch data.notificationSettings.muteState {
|
|
||||||
case .muted:
|
|
||||||
isMuted = true
|
|
||||||
case .unmuted:
|
|
||||||
isMuted = false
|
|
||||||
case .default:
|
|
||||||
if case .default = data.notificationSettings.muteState {
|
|
||||||
if case .muted = defaultPeerNotificationSettings.muteState {
|
|
||||||
isMuted = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let info = item.tagSummaryInfo[ChatListEntryMessageTagSummaryKey(
|
|
||||||
tag: .unseenPersonalMessage,
|
|
||||||
actionType: PendingMessageActionType.consumeUnseenPersonalMessage
|
|
||||||
)] {
|
|
||||||
hasUnseenMentions = (info.tagSummaryCount ?? 0) > (info.actionsSummaryCount ?? 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
var hasUnseenReactions = false
|
|
||||||
if let info = item.tagSummaryInfo[ChatListEntryMessageTagSummaryKey(
|
|
||||||
tag: .unseenReaction,
|
|
||||||
actionType: PendingMessageActionType.readReaction
|
|
||||||
)] {
|
|
||||||
hasUnseenReactions = (info.tagSummaryCount ?? 0) != 0// > (info.actionsSummaryCount ?? 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
let pinnedIndex: EngineChatList.Item.PinnedIndex
|
|
||||||
if let index = item.pinnedIndex {
|
|
||||||
pinnedIndex = .index(index)
|
|
||||||
} else {
|
|
||||||
pinnedIndex = .none
|
|
||||||
}
|
|
||||||
|
|
||||||
var topicMaxIncomingReadId = data.maxIncomingReadId
|
|
||||||
if data.maxIncomingReadId == 0 && maxReadId != 0 && Int64(maxReadId) <= item.id {
|
|
||||||
topicMaxIncomingReadId = max(topicMaxIncomingReadId, maxReadId)
|
|
||||||
}
|
|
||||||
|
|
||||||
let readCounters = EnginePeerReadCounters(state: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, .idBased(maxIncomingReadId: topicMaxIncomingReadId, maxOutgoingReadId: data.maxOutgoingReadId, maxKnownId: 1, count: data.incomingUnreadCount, markedUnread: false))]), isMuted: false)
|
|
||||||
|
|
||||||
var draft: EngineChatList.Draft?
|
var draft: EngineChatList.Draft?
|
||||||
if let embeddedState = item.embeddedInterfaceState, let _ = embeddedState.overrideChatTimestamp {
|
if let interfaceStateView = views.views[interfaceStateKey] as? ChatInterfaceStateView {
|
||||||
|
if let embeddedState = interfaceStateView.value, let _ = embeddedState.overrideChatTimestamp {
|
||||||
if let opaqueState = _internal_decodeStoredChatInterfaceState(state: embeddedState) {
|
if let opaqueState = _internal_decodeStoredChatInterfaceState(state: embeddedState) {
|
||||||
if let text = opaqueState.synchronizeableInputState?.text {
|
if let text = opaqueState.synchronizeableInputState?.text {
|
||||||
draft = EngineChatList.Draft(text: text, entities: opaqueState.synchronizeableInputState?.entities ?? [])
|
draft = EngineChatList.Draft(text: text, entities: opaqueState.synchronizeableInputState?.entities ?? [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var items: [EngineChatList.Item] = []
|
||||||
|
for item in view.items {
|
||||||
|
guard let sourcePeer = item.peer else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
let sourceId = PeerId(item.id)
|
||||||
|
|
||||||
|
var messages: [EngineMessage] = []
|
||||||
|
if let topMessage = item.topMessage {
|
||||||
|
messages.append(EngineMessage(topMessage))
|
||||||
|
}
|
||||||
|
|
||||||
|
let mappedMessageIndex = MessageIndex(id: MessageId(peerId: sourceId, namespace: item.index.id.namespace, id: item.index.id.id), timestamp: item.index.timestamp)
|
||||||
|
|
||||||
items.append(EngineChatList.Item(
|
items.append(EngineChatList.Item(
|
||||||
id: .forum(item.id),
|
id: .chatList(sourceId),
|
||||||
index: .forum(pinnedIndex: pinnedIndex, timestamp: item.index.timestamp, threadId: item.id, namespace: item.index.id.namespace, id: item.index.id.id),
|
index: .chatList(ChatListIndex(pinningIndex: item.pinnedIndex.flatMap(UInt16.init), messageIndex: mappedMessageIndex)),
|
||||||
messages: item.topMessage.flatMap { [EngineMessage($0)] } ?? [],
|
messages: messages,
|
||||||
readCounters: readCounters,
|
readCounters: nil,
|
||||||
isMuted: isMuted,
|
isMuted: false,
|
||||||
draft: draft,
|
draft: sourceId == accountPeerId ? draft : nil,
|
||||||
threadData: data,
|
threadData: nil,
|
||||||
renderedPeer: EngineRenderedPeer(peer: EnginePeer(peer)),
|
renderedPeer: EngineRenderedPeer(peer: EnginePeer(sourcePeer)),
|
||||||
presence: nil,
|
presence: nil,
|
||||||
hasUnseenMentions: hasUnseenMentions,
|
hasUnseenMentions: false,
|
||||||
hasUnseenReactions: hasUnseenReactions,
|
hasUnseenReactions: false,
|
||||||
forumTopicData: nil,
|
forumTopicData: nil,
|
||||||
topForumTopicItems: [],
|
topForumTopicItems: [],
|
||||||
hasFailed: false,
|
hasFailed: false,
|
||||||
@ -631,6 +591,7 @@ final class ChatTopicListTitleAccessoryPanelNode: ChatTitleAccessoryPanelNode, C
|
|||||||
hasLater: false,
|
hasLater: false,
|
||||||
isLoading: view.isLoading
|
isLoading: view.isLoading
|
||||||
)
|
)
|
||||||
|
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -811,9 +772,7 @@ final class ChatTopicListTitleAccessoryPanelNode: ChatTitleAccessoryPanelNode, C
|
|||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guard case let .forum(topicId) = chatListItem.id else {
|
let topicId = chatListItem.renderedPeer.peerId.toInt64()
|
||||||
return
|
|
||||||
}
|
|
||||||
self.interfaceInteraction?.updateChatLocationThread(topicId)
|
self.interfaceInteraction?.updateChatLocationThread(topicId)
|
||||||
}, contextGesture: { gesture, sourceNode in
|
}, contextGesture: { gesture, sourceNode in
|
||||||
})
|
})
|
||||||
@ -822,7 +781,7 @@ final class ChatTopicListTitleAccessoryPanelNode: ChatTitleAccessoryPanelNode, C
|
|||||||
}
|
}
|
||||||
|
|
||||||
var isSelected = false
|
var isSelected = false
|
||||||
if case let .forum(topicId) = item.item.id, params.interfaceState.chatLocation.threadId == topicId {
|
if params.interfaceState.chatLocation.threadId == item.item.renderedPeer.peerId.toInt64() {
|
||||||
isSelected = true
|
isSelected = true
|
||||||
}
|
}
|
||||||
let itemSize = itemView.update(context: self.context, item: item, isSelected: isSelected, theme: params.interfaceState.theme, height: panelHeight, transition: .immediate)
|
let itemSize = itemView.update(context: self.context, item: item, isSelected: isSelected, theme: params.interfaceState.theme, height: panelHeight, transition: .immediate)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user