mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
[WIP] Saved messages
This commit is contained in:
parent
a4e2c4f398
commit
b5029991f2
@ -1345,7 +1345,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
if let threadId = threadId {
|
if let threadId = threadId {
|
||||||
let source: ContextContentSource
|
let source: ContextContentSource
|
||||||
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .replyThread(message: ChatReplyThreadMessage(
|
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .replyThread(message: ChatReplyThreadMessage(
|
||||||
messageId: MessageId(peerId: peer.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
|
messageId: MessageId(peerId: peer.peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false
|
||||||
)), subject: nil, botStart: nil, mode: .standard(previewing: true))
|
)), subject: nil, botStart: nil, mode: .standard(previewing: true))
|
||||||
chatController.canReadHistory.set(false)
|
chatController.canReadHistory.set(false)
|
||||||
source = .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController))
|
source = .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController))
|
||||||
@ -1381,7 +1381,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
let source: ContextContentSource
|
let source: ContextContentSource
|
||||||
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .replyThread(message: ChatReplyThreadMessage(
|
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .replyThread(message: ChatReplyThreadMessage(
|
||||||
messageId: MessageId(peerId: peer.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
|
messageId: MessageId(peerId: peer.peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false
|
||||||
)), subject: nil, botStart: nil, mode: .standard(previewing: true))
|
)), subject: nil, botStart: nil, mode: .standard(previewing: true))
|
||||||
chatController.canReadHistory.set(false)
|
chatController.canReadHistory.set(false)
|
||||||
source = .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController))
|
source = .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController))
|
||||||
|
@ -1899,8 +1899,10 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
var peerText: String?
|
var peerText: String?
|
||||||
if case .savedMessagesChats = item.chatListLocation {
|
if case .savedMessagesChats = item.chatListLocation {
|
||||||
if let message = messages.last, let forwardInfo = message.forwardInfo, let author = forwardInfo.author {
|
if let message = messages.last, let forwardInfo = message.forwardInfo, let author = forwardInfo.author {
|
||||||
|
if author.id != itemPeer.chatMainPeer?.id {
|
||||||
peerText = EnginePeer(author).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)
|
peerText = EnginePeer(author).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if case .groupReference = item.content {
|
} else if case .groupReference = item.content {
|
||||||
if let messagePeer = itemPeer.chatMainPeer {
|
if let messagePeer = itemPeer.chatMainPeer {
|
||||||
peerText = messagePeer.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)
|
peerText = messagePeer.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)
|
||||||
|
@ -341,19 +341,41 @@ func chatListViewForLocation(chatListLocation: ChatListControllerLocation, locat
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
let sourceId = PeerId(threadId)
|
let sourceId = PeerId(threadId)
|
||||||
guard let source = message.peers[sourceId] else {
|
var sourcePeer = message.peers[sourceId]
|
||||||
|
if sourcePeer == nil, let forwardInfo = message.forwardInfo, let authorSignature = forwardInfo.authorSignature {
|
||||||
|
sourcePeer = TelegramUser(
|
||||||
|
id: PeerId(namespace: Namespaces.Peer.Empty, id: PeerId.Id._internalFromInt64Value(1)),
|
||||||
|
accessHash: nil,
|
||||||
|
firstName: authorSignature,
|
||||||
|
lastName: nil,
|
||||||
|
username: nil,
|
||||||
|
phone: nil,
|
||||||
|
photo: [],
|
||||||
|
botInfo: nil,
|
||||||
|
restrictionInfo: nil,
|
||||||
|
flags: [],
|
||||||
|
emojiStatus: nil,
|
||||||
|
usernames: [],
|
||||||
|
storiesHidden: nil,
|
||||||
|
nameColor: nil,
|
||||||
|
backgroundEmojiId: nil,
|
||||||
|
profileColor: nil,
|
||||||
|
profileBackgroundEmojiId: nil
|
||||||
|
)
|
||||||
|
}
|
||||||
|
guard let sourcePeer else {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
let mappedMessageIndex = MessageIndex(id: MessageId(peerId: source.id, namespace: message.index.id.namespace, id: message.index.id.id), timestamp: message.index.timestamp)
|
let mappedMessageIndex = MessageIndex(id: MessageId(peerId: sourceId, namespace: message.index.id.namespace, id: message.index.id.id), timestamp: message.index.timestamp)
|
||||||
items.append(EngineChatList.Item(
|
items.append(EngineChatList.Item(
|
||||||
id: .chatList(source.id),
|
id: .chatList(sourceId),
|
||||||
index: .chatList(ChatListIndex(pinningIndex: nil, messageIndex: mappedMessageIndex)),
|
index: .chatList(ChatListIndex(pinningIndex: nil, messageIndex: mappedMessageIndex)),
|
||||||
messages: [EngineMessage(message)],
|
messages: [EngineMessage(message)],
|
||||||
readCounters: nil,
|
readCounters: nil,
|
||||||
isMuted: false,
|
isMuted: false,
|
||||||
draft: nil,
|
draft: nil,
|
||||||
threadData: nil,
|
threadData: nil,
|
||||||
renderedPeer: EngineRenderedPeer(peer: EnginePeer(source)),
|
renderedPeer: EngineRenderedPeer(peer: EnginePeer(sourcePeer)),
|
||||||
presence: nil,
|
presence: nil,
|
||||||
hasUnseenMentions: false,
|
hasUnseenMentions: false,
|
||||||
hasUnseenReactions: false,
|
hasUnseenReactions: false,
|
||||||
|
@ -555,6 +555,7 @@ public struct ChatReplyThreadMessage: Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public var messageId: MessageId
|
public var messageId: MessageId
|
||||||
|
public var threadId: Int64
|
||||||
public var channelMessageId: MessageId?
|
public var channelMessageId: MessageId?
|
||||||
public var isChannelPost: Bool
|
public var isChannelPost: Bool
|
||||||
public var isForumPost: Bool
|
public var isForumPost: Bool
|
||||||
@ -566,8 +567,9 @@ public struct ChatReplyThreadMessage: Equatable {
|
|||||||
public var initialAnchor: Anchor
|
public var initialAnchor: Anchor
|
||||||
public var isNotAvailable: Bool
|
public var isNotAvailable: Bool
|
||||||
|
|
||||||
public init(messageId: MessageId, channelMessageId: MessageId?, isChannelPost: Bool, isForumPost: Bool, maxMessage: MessageId?, maxReadIncomingMessageId: MessageId?, maxReadOutgoingMessageId: MessageId?, unreadCount: Int, initialFilledHoles: IndexSet, initialAnchor: Anchor, isNotAvailable: Bool) {
|
public init(messageId: MessageId, threadId: Int64, channelMessageId: MessageId?, isChannelPost: Bool, isForumPost: Bool, maxMessage: MessageId?, maxReadIncomingMessageId: MessageId?, maxReadOutgoingMessageId: MessageId?, unreadCount: Int, initialFilledHoles: IndexSet, initialAnchor: Anchor, isNotAvailable: Bool) {
|
||||||
self.messageId = messageId
|
self.messageId = messageId
|
||||||
|
self.threadId = threadId
|
||||||
self.channelMessageId = channelMessageId
|
self.channelMessageId = channelMessageId
|
||||||
self.isChannelPost = isChannelPost
|
self.isChannelPost = isChannelPost
|
||||||
self.isForumPost = isForumPost
|
self.isForumPost = isForumPost
|
||||||
@ -582,7 +584,7 @@ public struct ChatReplyThreadMessage: Equatable {
|
|||||||
|
|
||||||
public var normalized: ChatReplyThreadMessage {
|
public var normalized: ChatReplyThreadMessage {
|
||||||
if self.isForumPost {
|
if self.isForumPost {
|
||||||
return ChatReplyThreadMessage(messageId: self.messageId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false)
|
return ChatReplyThreadMessage(messageId: self.messageId, threadId: self.threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false)
|
||||||
} else {
|
} else {
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
@ -936,6 +938,7 @@ func _internal_fetchChannelReplyThreadMessage(account: Account, messageId: Messa
|
|||||||
|
|
||||||
return .single(ChatReplyThreadMessage(
|
return .single(ChatReplyThreadMessage(
|
||||||
messageId: discussionMessage.messageId,
|
messageId: discussionMessage.messageId,
|
||||||
|
threadId: Int64(discussionMessage.messageId.id),
|
||||||
channelMessageId: discussionMessage.channelMessageId,
|
channelMessageId: discussionMessage.channelMessageId,
|
||||||
isChannelPost: discussionMessage.isChannelPost,
|
isChannelPost: discussionMessage.isChannelPost,
|
||||||
isForumPost: discussionMessage.isForumPost,
|
isForumPost: discussionMessage.isForumPost,
|
||||||
|
@ -98,6 +98,7 @@ public final class PeerInfoChatListPaneNode: ASDisplayNode, PeerInfoPaneNode, UI
|
|||||||
peerId: self.context.account.peerId,
|
peerId: self.context.account.peerId,
|
||||||
threadId: peer.id.toInt64()
|
threadId: peer.id.toInt64()
|
||||||
),
|
),
|
||||||
|
threadId: peer.id.toInt64(),
|
||||||
channelMessageId: nil,
|
channelMessageId: nil,
|
||||||
isChannelPost: false,
|
isChannelPost: false,
|
||||||
isForumPost: false,
|
isForumPost: false,
|
||||||
|
@ -187,6 +187,7 @@ final class TelegramGlobalSettings {
|
|||||||
final class PeerInfoScreenData {
|
final class PeerInfoScreenData {
|
||||||
let peer: Peer?
|
let peer: Peer?
|
||||||
let chatPeer: Peer?
|
let chatPeer: Peer?
|
||||||
|
let savedMessagesPeer: Peer?
|
||||||
let cachedData: CachedPeerData?
|
let cachedData: CachedPeerData?
|
||||||
let status: PeerInfoStatusData?
|
let status: PeerInfoStatusData?
|
||||||
let peerNotificationSettings: TelegramPeerNotificationSettings?
|
let peerNotificationSettings: TelegramPeerNotificationSettings?
|
||||||
@ -221,6 +222,7 @@ final class PeerInfoScreenData {
|
|||||||
init(
|
init(
|
||||||
peer: Peer?,
|
peer: Peer?,
|
||||||
chatPeer: Peer?,
|
chatPeer: Peer?,
|
||||||
|
savedMessagesPeer: Peer?,
|
||||||
cachedData: CachedPeerData?,
|
cachedData: CachedPeerData?,
|
||||||
status: PeerInfoStatusData?,
|
status: PeerInfoStatusData?,
|
||||||
peerNotificationSettings: TelegramPeerNotificationSettings?,
|
peerNotificationSettings: TelegramPeerNotificationSettings?,
|
||||||
@ -244,6 +246,7 @@ final class PeerInfoScreenData {
|
|||||||
) {
|
) {
|
||||||
self.peer = peer
|
self.peer = peer
|
||||||
self.chatPeer = chatPeer
|
self.chatPeer = chatPeer
|
||||||
|
self.savedMessagesPeer = savedMessagesPeer
|
||||||
self.cachedData = cachedData
|
self.cachedData = cachedData
|
||||||
self.status = status
|
self.status = status
|
||||||
self.peerNotificationSettings = peerNotificationSettings
|
self.peerNotificationSettings = peerNotificationSettings
|
||||||
@ -626,6 +629,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
|||||||
return PeerInfoScreenData(
|
return PeerInfoScreenData(
|
||||||
peer: peer,
|
peer: peer,
|
||||||
chatPeer: peer,
|
chatPeer: peer,
|
||||||
|
savedMessagesPeer: nil,
|
||||||
cachedData: peerView.cachedData,
|
cachedData: peerView.cachedData,
|
||||||
status: nil,
|
status: nil,
|
||||||
peerNotificationSettings: nil,
|
peerNotificationSettings: nil,
|
||||||
@ -660,6 +664,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
return .single(PeerInfoScreenData(
|
return .single(PeerInfoScreenData(
|
||||||
peer: nil,
|
peer: nil,
|
||||||
chatPeer: nil,
|
chatPeer: nil,
|
||||||
|
savedMessagesPeer: nil,
|
||||||
cachedData: nil,
|
cachedData: nil,
|
||||||
status: nil,
|
status: nil,
|
||||||
peerNotificationSettings: nil,
|
peerNotificationSettings: nil,
|
||||||
@ -794,6 +799,13 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
}
|
}
|
||||||
|> distinctUntilChanged
|
|> distinctUntilChanged
|
||||||
|
|
||||||
|
let savedMessagesPeer: Signal<EnginePeer?, NoError>
|
||||||
|
if peerId == context.account.peerId, case let .replyThread(replyThreadMessage) = chatLocation {
|
||||||
|
savedMessagesPeer = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: PeerId(replyThreadMessage.threadId)))
|
||||||
|
} else {
|
||||||
|
savedMessagesPeer = .single(nil)
|
||||||
|
}
|
||||||
|
|
||||||
return combineLatest(
|
return combineLatest(
|
||||||
context.account.viewTracker.peerView(peerId, updateData: true),
|
context.account.viewTracker.peerView(peerId, updateData: true),
|
||||||
peerInfoAvailableMediaPanes(context: context, peerId: peerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder),
|
peerInfoAvailableMediaPanes(context: context, peerId: peerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder),
|
||||||
@ -801,9 +813,10 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
secretChatKeyFingerprint,
|
secretChatKeyFingerprint,
|
||||||
status,
|
status,
|
||||||
hasStories,
|
hasStories,
|
||||||
accountIsPremium
|
accountIsPremium,
|
||||||
|
savedMessagesPeer
|
||||||
)
|
)
|
||||||
|> map { peerView, availablePanes, globalNotificationSettings, encryptionKeyFingerprint, status, hasStories, accountIsPremium -> PeerInfoScreenData in
|
|> map { peerView, availablePanes, globalNotificationSettings, encryptionKeyFingerprint, status, hasStories, accountIsPremium, savedMessagesPeer -> PeerInfoScreenData in
|
||||||
var availablePanes = availablePanes
|
var availablePanes = availablePanes
|
||||||
|
|
||||||
if let hasStories {
|
if let hasStories {
|
||||||
@ -817,23 +830,19 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if peerId == context.account.peerId {
|
if peerId == context.account.peerId, case .peer = chatLocation {
|
||||||
availablePanes?.insert(.savedMessagesChats, at: 0)
|
availablePanes?.insert(.savedMessagesChats, at: 0)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
availablePanes = nil
|
availablePanes = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var peer: Peer?
|
let peer = peerView.peers[userPeerId]
|
||||||
peer = peerView.peers[userPeerId]
|
|
||||||
|
|
||||||
/*if let user = peer as? TelegramUser, let profileColor = user.nameColor {
|
|
||||||
peer = user.withUpdatedProfileColor(PeerNameColor(rawValue: profileColor.rawValue)).withUpdatedProfileBackgroundEmojiId(user.backgroundEmojiId)
|
|
||||||
}*/
|
|
||||||
|
|
||||||
return PeerInfoScreenData(
|
return PeerInfoScreenData(
|
||||||
peer: peer,
|
peer: peer,
|
||||||
chatPeer: peerView.peers[peerId],
|
chatPeer: peerView.peers[peerId],
|
||||||
|
savedMessagesPeer: savedMessagesPeer?._asPeer(),
|
||||||
cachedData: peerView.cachedData,
|
cachedData: peerView.cachedData,
|
||||||
status: status,
|
status: status,
|
||||||
peerNotificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings,
|
peerNotificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings,
|
||||||
@ -946,6 +955,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
return PeerInfoScreenData(
|
return PeerInfoScreenData(
|
||||||
peer: peerView.peers[peerId],
|
peer: peerView.peers[peerId],
|
||||||
chatPeer: peerView.peers[peerId],
|
chatPeer: peerView.peers[peerId],
|
||||||
|
savedMessagesPeer: nil,
|
||||||
cachedData: peerView.cachedData,
|
cachedData: peerView.cachedData,
|
||||||
status: status,
|
status: status,
|
||||||
peerNotificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings,
|
peerNotificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings,
|
||||||
@ -1071,7 +1081,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
|
|
||||||
let threadData: Signal<MessageHistoryThreadData?, NoError>
|
let threadData: Signal<MessageHistoryThreadData?, NoError>
|
||||||
if case let .replyThread(message) = chatLocation {
|
if case let .replyThread(message) = chatLocation {
|
||||||
let threadId = Int64(message.messageId.id)
|
let threadId = message.threadId
|
||||||
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: peerId, threadId: threadId)
|
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: peerId, threadId: threadId)
|
||||||
threadData = context.account.postbox.combinedView(keys: [viewKey])
|
threadData = context.account.postbox.combinedView(keys: [viewKey])
|
||||||
|> map { views -> MessageHistoryThreadData? in
|
|> map { views -> MessageHistoryThreadData? in
|
||||||
@ -1158,6 +1168,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
return .single(PeerInfoScreenData(
|
return .single(PeerInfoScreenData(
|
||||||
peer: peerView.peers[groupId],
|
peer: peerView.peers[groupId],
|
||||||
chatPeer: peerView.peers[groupId],
|
chatPeer: peerView.peers[groupId],
|
||||||
|
savedMessagesPeer: nil,
|
||||||
cachedData: peerView.cachedData,
|
cachedData: peerView.cachedData,
|
||||||
status: status,
|
status: status,
|
||||||
peerNotificationSettings: peerNotificationSettings,
|
peerNotificationSettings: peerNotificationSettings,
|
||||||
|
@ -435,6 +435,11 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
|
|
||||||
private var currentPanelStatusData: PeerInfoStatusData?
|
private var currentPanelStatusData: PeerInfoStatusData?
|
||||||
func update(width: CGFloat, containerHeight: CGFloat, containerInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, isMediaOnly: Bool, contentOffset: CGFloat, paneContainerY: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, threadData: MessageHistoryThreadData?, peerNotificationSettings: TelegramPeerNotificationSettings?, threadNotificationSettings: TelegramPeerNotificationSettings?, globalNotificationSettings: EngineGlobalNotificationSettings?, statusData: PeerInfoStatusData?, panelStatusData: (PeerInfoStatusData?, PeerInfoStatusData?, CGFloat?), isSecretChat: Bool, isContact: Bool, isSettings: Bool, state: PeerInfoState, metrics: LayoutMetrics, deviceMetrics: DeviceMetrics, transition: ContainedViewLayoutTransition, additive: Bool, animateHeader: Bool) -> CGFloat {
|
func update(width: CGFloat, containerHeight: CGFloat, containerInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, isMediaOnly: Bool, contentOffset: CGFloat, paneContainerY: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, threadData: MessageHistoryThreadData?, peerNotificationSettings: TelegramPeerNotificationSettings?, threadNotificationSettings: TelegramPeerNotificationSettings?, globalNotificationSettings: EngineGlobalNotificationSettings?, statusData: PeerInfoStatusData?, panelStatusData: (PeerInfoStatusData?, PeerInfoStatusData?, CGFloat?), isSecretChat: Bool, isContact: Bool, isSettings: Bool, state: PeerInfoState, metrics: LayoutMetrics, deviceMetrics: DeviceMetrics, transition: ContainedViewLayoutTransition, additive: Bool, animateHeader: Bool) -> CGFloat {
|
||||||
|
var threadData = threadData
|
||||||
|
if case let .replyThread(replyThreadMessage) = self.chatLocation, replyThreadMessage.messageId.peerId == self.context.account.peerId {
|
||||||
|
threadData = nil
|
||||||
|
}
|
||||||
|
|
||||||
self.state = state
|
self.state = state
|
||||||
self.peer = peer
|
self.peer = peer
|
||||||
self.threadData = threadData
|
self.threadData = threadData
|
||||||
@ -880,8 +885,6 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
var title: String
|
var title: String
|
||||||
if peer.id == self.context.account.peerId && !self.isSettings {
|
if peer.id == self.context.account.peerId && !self.isSettings {
|
||||||
title = presentationData.strings.Conversation_SavedMessages
|
title = presentationData.strings.Conversation_SavedMessages
|
||||||
} else if peer.id == self.context.account.peerId && !self.isSettings {
|
|
||||||
title = presentationData.strings.DialogList_Replies
|
|
||||||
} else if let threadData = threadData {
|
} else if let threadData = threadData {
|
||||||
title = threadData.info.title
|
title = threadData.info.title
|
||||||
} else {
|
} else {
|
||||||
@ -968,6 +971,17 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
smallSubtitleAttributes = MultiScaleTextState.Attributes(font: Font.regular(16.0), color: .white, shadowColor: titleShadowColor)
|
smallSubtitleAttributes = MultiScaleTextState.Attributes(font: Font.regular(16.0), color: .white, shadowColor: titleShadowColor)
|
||||||
|
|
||||||
usernameString = ("", MultiScaleTextState.Attributes(font: Font.regular(16.0), color: .white))
|
usernameString = ("", MultiScaleTextState.Attributes(font: Font.regular(16.0), color: .white))
|
||||||
|
|
||||||
|
let (maybePanelStatusData, _, _) = panelStatusData
|
||||||
|
if let panelStatusData = maybePanelStatusData {
|
||||||
|
let subtitleColor: UIColor
|
||||||
|
if panelStatusData.isActivity {
|
||||||
|
subtitleColor = UIColor.white
|
||||||
|
} else {
|
||||||
|
subtitleColor = UIColor.white
|
||||||
|
}
|
||||||
|
panelSubtitleString = (panelStatusData.text, MultiScaleTextState.Attributes(font: Font.regular(17.0), color: subtitleColor))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
titleStringText = " "
|
titleStringText = " "
|
||||||
@ -1490,7 +1504,9 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
if self.isSettings {
|
if self.isSettings {
|
||||||
expandablePart += 20.0
|
expandablePart += 20.0
|
||||||
} else {
|
} else {
|
||||||
if peer?.id == self.context.account.peerId {
|
if case let .replyThread(replyThreadMessage) = self.chatLocation, replyThreadMessage.messageId.peerId == self.context.account.peerId {
|
||||||
|
expandablePart = 0.0
|
||||||
|
} else if peer?.id == self.context.account.peerId {
|
||||||
expandablePart = 0.0
|
expandablePart = 0.0
|
||||||
} else {
|
} else {
|
||||||
expandablePart += 99.0
|
expandablePart += 99.0
|
||||||
|
@ -1240,7 +1240,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
|||||||
|
|
||||||
var threadId: Int64 = 0
|
var threadId: Int64 = 0
|
||||||
if case let .replyThread(message) = chatLocation {
|
if case let .replyThread(message) = chatLocation {
|
||||||
threadId = Int64(message.messageId.id)
|
threadId = message.threadId
|
||||||
}
|
}
|
||||||
|
|
||||||
let linkText = "https://t.me/\(mainUsername)/\(threadId)"
|
let linkText = "https://t.me/\(mainUsername)/\(threadId)"
|
||||||
@ -2273,7 +2273,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
|
|
||||||
var forumTopicThreadId: Int64?
|
var forumTopicThreadId: Int64?
|
||||||
if case let .replyThread(message) = chatLocation {
|
if case let .replyThread(message) = chatLocation {
|
||||||
forumTopicThreadId = Int64(message.messageId.id)
|
forumTopicThreadId = message.threadId
|
||||||
}
|
}
|
||||||
self.headerNode = PeerInfoHeaderNode(context: context, controller: controller, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, isMediaOnly: self.isMediaOnly, isSettings: isSettings, forumTopicThreadId: forumTopicThreadId, chatLocation: self.chatLocation)
|
self.headerNode = PeerInfoHeaderNode(context: context, controller: controller, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, isMediaOnly: self.isMediaOnly, isSettings: isSettings, forumTopicThreadId: forumTopicThreadId, chatLocation: self.chatLocation)
|
||||||
self.paneContainerNode = PeerInfoPaneContainerNode(context: context, updatedPresentationData: controller.updatedPresentationData, peerId: peerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, isMediaOnly: self.isMediaOnly, initialPaneKey: initialPaneKey)
|
self.paneContainerNode = PeerInfoPaneContainerNode(context: context, updatedPresentationData: controller.updatedPresentationData, peerId: peerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, isMediaOnly: self.isMediaOnly, initialPaneKey: initialPaneKey)
|
||||||
@ -3324,7 +3324,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
strongSelf.controller?.dismiss()
|
strongSelf.controller?.dismiss()
|
||||||
case .edit:
|
case .edit:
|
||||||
if case let .replyThread(message) = strongSelf.chatLocation {
|
if case let .replyThread(message) = strongSelf.chatLocation {
|
||||||
let threadId = Int64(message.messageId.id)
|
let threadId = message.threadId
|
||||||
if let threadData = strongSelf.data?.threadData {
|
if let threadData = strongSelf.data?.threadData {
|
||||||
let controller = ForumCreateTopicScreen(context: strongSelf.context, peerId: strongSelf.peerId, mode: .edit(threadId: threadId, threadInfo: threadData.info, isHidden: threadData.isHidden))
|
let controller = ForumCreateTopicScreen(context: strongSelf.context, peerId: strongSelf.peerId, mode: .edit(threadId: threadId, threadInfo: threadData.info, isHidden: threadData.isHidden))
|
||||||
controller.navigationPresentation = .modal
|
controller.navigationPresentation = .modal
|
||||||
@ -8409,7 +8409,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
|
|
||||||
var threadId: Int64?
|
var threadId: Int64?
|
||||||
if case let .replyThread(message) = self.chatLocation {
|
if case let .replyThread(message) = self.chatLocation {
|
||||||
threadId = Int64(message.messageId.id)
|
threadId = message.threadId
|
||||||
}
|
}
|
||||||
|
|
||||||
var temporary = false
|
var temporary = false
|
||||||
@ -9616,7 +9616,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
}
|
}
|
||||||
let headerInset = sectionInset
|
let headerInset = sectionInset
|
||||||
|
|
||||||
let headerHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : self.scrollNode.view.contentOffset.y, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, threadData: self.data?.threadData, peerNotificationSettings: self.data?.peerNotificationSettings, threadNotificationSettings: self.data?.threadNotificationSettings, globalNotificationSettings: self.data?.globalNotificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, transition: transition, additive: additive, animateHeader: transition.isAnimated)
|
let headerHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : self.scrollNode.view.contentOffset.y, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.savedMessagesPeer ?? self.data?.peer, cachedData: self.data?.cachedData, threadData: self.data?.threadData, peerNotificationSettings: self.data?.peerNotificationSettings, threadNotificationSettings: self.data?.threadNotificationSettings, globalNotificationSettings: self.data?.globalNotificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, transition: transition, additive: additive, animateHeader: transition.isAnimated)
|
||||||
let headerFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: layout.size.width, height: headerHeight))
|
let headerFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: layout.size.width, height: headerHeight))
|
||||||
if additive {
|
if additive {
|
||||||
transition.updateFrameAdditive(node: self.headerNode, frame: headerFrame)
|
transition.updateFrameAdditive(node: self.headerNode, frame: headerFrame)
|
||||||
@ -9979,7 +9979,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
}
|
}
|
||||||
let headerInset = sectionInset
|
let headerInset = sectionInset
|
||||||
|
|
||||||
let _ = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : offsetY, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, threadData: self.data?.threadData, peerNotificationSettings: self.data?.peerNotificationSettings, threadNotificationSettings: self.data?.threadNotificationSettings, globalNotificationSettings: self.data?.globalNotificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, transition: transition, additive: additive, animateHeader: animateHeader)
|
let _ = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : offsetY, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.savedMessagesPeer ?? self.data?.peer, cachedData: self.data?.cachedData, threadData: self.data?.threadData, peerNotificationSettings: self.data?.peerNotificationSettings, threadNotificationSettings: self.data?.threadNotificationSettings, globalNotificationSettings: self.data?.globalNotificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, transition: transition, additive: additive, animateHeader: animateHeader)
|
||||||
}
|
}
|
||||||
|
|
||||||
let paneAreaExpansionDistance: CGFloat = 32.0
|
let paneAreaExpansionDistance: CGFloat = 32.0
|
||||||
@ -10029,7 +10029,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
if self.state.selectedMessageIds == nil {
|
if self.state.selectedMessageIds == nil {
|
||||||
if let currentPaneKey = self.paneContainerNode.currentPaneKey {
|
if let currentPaneKey = self.paneContainerNode.currentPaneKey {
|
||||||
switch currentPaneKey {
|
switch currentPaneKey {
|
||||||
case .files, .music, .links, .members, .savedMessagesChats:
|
case .files, .music, .links, .members:
|
||||||
rightNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .search, isForExpandedView: true))
|
rightNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .search, isForExpandedView: true))
|
||||||
case .media:
|
case .media:
|
||||||
rightNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .more, isForExpandedView: true))
|
rightNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .more, isForExpandedView: true))
|
||||||
@ -10863,7 +10863,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
|||||||
let navigateChatLocation: NavigateToChatControllerParams.Location
|
let navigateChatLocation: NavigateToChatControllerParams.Location
|
||||||
if let threadId = item.threadId {
|
if let threadId = item.threadId {
|
||||||
navigateChatLocation = .replyThread(ChatReplyThreadMessage(
|
navigateChatLocation = .replyThread(ChatReplyThreadMessage(
|
||||||
messageId: MessageId(peerId: item.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
|
messageId: MessageId(peerId: item.peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
navigateChatLocation = .peer(itemPeer)
|
navigateChatLocation = .peer(itemPeer)
|
||||||
@ -11295,7 +11295,7 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig
|
|||||||
}
|
}
|
||||||
let headerInset = sectionInset
|
let headerInset = sectionInset
|
||||||
|
|
||||||
topHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: topNavigationBar.bounds.height, isModalOverlay: layout.isModalOverlay, isMediaOnly: false, contentOffset: 0.0, paneContainerY: 0.0, presentationData: self.presentationData, peer: self.screenNode.data?.peer, cachedData: self.screenNode.data?.cachedData, threadData: self.screenNode.data?.threadData, peerNotificationSettings: self.screenNode.data?.peerNotificationSettings, threadNotificationSettings: self.screenNode.data?.threadNotificationSettings, globalNotificationSettings: self.screenNode.data?.globalNotificationSettings, statusData: self.screenNode.data?.status, panelStatusData: (nil, nil, nil), isSecretChat: self.screenNode.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.screenNode.data?.isContact ?? false, isSettings: self.screenNode.isSettings, state: self.screenNode.state, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, transition: transition, additive: false, animateHeader: true)
|
topHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: topNavigationBar.bounds.height, isModalOverlay: layout.isModalOverlay, isMediaOnly: false, contentOffset: 0.0, paneContainerY: 0.0, presentationData: self.presentationData, peer: self.screenNode.data?.savedMessagesPeer ?? self.screenNode.data?.peer, cachedData: self.screenNode.data?.cachedData, threadData: self.screenNode.data?.threadData, peerNotificationSettings: self.screenNode.data?.peerNotificationSettings, threadNotificationSettings: self.screenNode.data?.threadNotificationSettings, globalNotificationSettings: self.screenNode.data?.globalNotificationSettings, statusData: self.screenNode.data?.status, panelStatusData: (nil, nil, nil), isSecretChat: self.screenNode.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.screenNode.data?.isContact ?? false, isSettings: self.screenNode.isSettings, state: self.screenNode.state, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, transition: transition, additive: false, animateHeader: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
let titleScale = (fraction * previousTitleNode.view.bounds.height + (1.0 - fraction) * self.headerNode.titleNodeRawContainer.bounds.height) / previousTitleNode.view.bounds.height
|
let titleScale = (fraction * previousTitleNode.view.bounds.height + (1.0 - fraction) * self.headerNode.titleNodeRawContainer.bounds.height) / previousTitleNode.view.bounds.height
|
||||||
|
@ -1211,7 +1211,7 @@ public final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode,
|
|||||||
|
|
||||||
var threadId: Int64?
|
var threadId: Int64?
|
||||||
if case let .replyThread(message) = chatLocation {
|
if case let .replyThread(message) = chatLocation {
|
||||||
threadId = Int64(message.messageId.id)
|
threadId = message.threadId
|
||||||
}
|
}
|
||||||
|
|
||||||
self.listSource = self.context.engine.messages.sparseMessageList(peerId: self.peerId, threadId: threadId, tag: tagMaskForType(self.contentType))
|
self.listSource = self.context.engine.messages.sparseMessageList(peerId: self.peerId, threadId: threadId, tag: tagMaskForType(self.contentType))
|
||||||
@ -1673,7 +1673,7 @@ public final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode,
|
|||||||
|
|
||||||
var threadId: Int64?
|
var threadId: Int64?
|
||||||
if case let .replyThread(message) = chatLocation {
|
if case let .replyThread(message) = chatLocation {
|
||||||
threadId = Int64(message.messageId.id)
|
threadId = message.threadId
|
||||||
}
|
}
|
||||||
|
|
||||||
self.listSource = self.context.engine.messages.sparseMessageList(peerId: self.peerId, threadId: threadId, tag: tagMaskForType(self.contentType))
|
self.listSource = self.context.engine.messages.sparseMessageList(peerId: self.peerId, threadId: threadId, tag: tagMaskForType(self.contentType))
|
||||||
|
@ -2563,7 +2563,7 @@ final class StorageUsageScreenComponent: Component {
|
|||||||
|
|
||||||
var chatLocation: NavigateToChatControllerParams.Location = .peer(peer)
|
var chatLocation: NavigateToChatControllerParams.Location = .peer(peer)
|
||||||
if case let .channel(channel) = peer, channel.flags.contains(.isForum), let threadId = message.threadId {
|
if case let .channel(channel) = peer, channel.flags.contains(.isForum), let threadId = message.threadId {
|
||||||
chatLocation = .replyThread(ChatReplyThreadMessage(messageId: MessageId(peerId: peer.id, 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))
|
chatLocation = .replyThread(ChatReplyThreadMessage(messageId: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false))
|
||||||
}
|
}
|
||||||
|
|
||||||
component.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(
|
component.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(
|
||||||
@ -2666,7 +2666,7 @@ final class StorageUsageScreenComponent: Component {
|
|||||||
|
|
||||||
var chatLocation: NavigateToChatControllerParams.Location = .peer(peer)
|
var chatLocation: NavigateToChatControllerParams.Location = .peer(peer)
|
||||||
if case let .channel(channel) = peer, channel.flags.contains(.isForum), let threadId = message.threadId {
|
if case let .channel(channel) = peer, channel.flags.contains(.isForum), let threadId = message.threadId {
|
||||||
chatLocation = .replyThread(ChatReplyThreadMessage(messageId: MessageId(peerId: peer.id, 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))
|
chatLocation = .replyThread(ChatReplyThreadMessage(messageId: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false))
|
||||||
}
|
}
|
||||||
|
|
||||||
component.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(
|
component.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(
|
||||||
|
@ -313,7 +313,7 @@ final class AuthorizedApplicationContext {
|
|||||||
let chatLocation: NavigateToChatControllerParams.Location
|
let chatLocation: NavigateToChatControllerParams.Location
|
||||||
if let _ = threadData, let threadId = firstMessage.threadId {
|
if let _ = threadData, let threadId = firstMessage.threadId {
|
||||||
chatLocation = .replyThread(ChatReplyThreadMessage(
|
chatLocation = .replyThread(ChatReplyThreadMessage(
|
||||||
messageId: MessageId(peerId: firstMessage.id.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
|
messageId: MessageId(peerId: firstMessage.id.peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false
|
||||||
).normalized)
|
).normalized)
|
||||||
} else {
|
} else {
|
||||||
guard let peer = firstMessage.peers[firstMessage.id.peerId] else {
|
guard let peer = firstMessage.peers[firstMessage.id.peerId] else {
|
||||||
@ -905,7 +905,7 @@ final class AuthorizedApplicationContext {
|
|||||||
let chatLocation: NavigateToChatControllerParams.Location
|
let chatLocation: NavigateToChatControllerParams.Location
|
||||||
if let threadId = threadId {
|
if let threadId = threadId {
|
||||||
chatLocation = .replyThread(ChatReplyThreadMessage(
|
chatLocation = .replyThread(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
|
messageId: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
chatLocation = .peer(peer)
|
chatLocation = .peer(peer)
|
||||||
|
@ -127,7 +127,7 @@ extension ChatControllerImpl {
|
|||||||
|
|
||||||
let navigateToLocation: NavigateToChatControllerParams.Location
|
let navigateToLocation: NavigateToChatControllerParams.Location
|
||||||
if let message = messages.first, let threadId = message.threadId, let channel = message.peers[message.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum) {
|
if let message = messages.first, let threadId = message.threadId, let channel = message.peers[message.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum) {
|
||||||
navigateToLocation = .replyThread(ChatReplyThreadMessage(messageId: MessageId(peerId: peer.id, 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))
|
navigateToLocation = .replyThread(ChatReplyThreadMessage(messageId: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false))
|
||||||
} else {
|
} else {
|
||||||
navigateToLocation = .peer(peer)
|
navigateToLocation = .peer(peer)
|
||||||
}
|
}
|
||||||
@ -145,7 +145,7 @@ extension ChatControllerImpl {
|
|||||||
if let navigationController = self.effectiveNavigationController {
|
if let navigationController = self.effectiveNavigationController {
|
||||||
var chatLocation: NavigateToChatControllerParams.Location = .peer(peer)
|
var chatLocation: NavigateToChatControllerParams.Location = .peer(peer)
|
||||||
if case let .channel(channel) = peer, channel.flags.contains(.isForum), let message = message, let threadId = message.threadId {
|
if case let .channel(channel) = peer, channel.flags.contains(.isForum), let message = message, let threadId = message.threadId {
|
||||||
chatLocation = .replyThread(ChatReplyThreadMessage(messageId: MessageId(peerId: peer.id, 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))
|
chatLocation = .replyThread(ChatReplyThreadMessage(messageId: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false))
|
||||||
}
|
}
|
||||||
|
|
||||||
var quote: ChatControllerSubject.MessageHighlight.Quote?
|
var quote: ChatControllerSubject.MessageHighlight.Quote?
|
||||||
|
@ -5630,10 +5630,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
replyThreadType = .replies
|
replyThreadType = .replies
|
||||||
case let .replyThread(replyThreadMessage):
|
case let .replyThread(replyThreadMessage):
|
||||||
if replyThreadMessage.messageId.peerId == context.account.peerId {
|
if replyThreadMessage.messageId.peerId == context.account.peerId {
|
||||||
replyThreadId = Int64(replyThreadMessage.messageId.id)
|
replyThreadId = replyThreadMessage.threadId
|
||||||
replyThreadType = .replies
|
replyThreadType = .replies
|
||||||
} else {
|
} else {
|
||||||
replyThreadId = Int64(replyThreadMessage.messageId.id)
|
replyThreadId = replyThreadMessage.threadId
|
||||||
if replyThreadMessage.isChannelPost {
|
if replyThreadMessage.isChannelPost {
|
||||||
replyThreadType = .comments
|
replyThreadType = .comments
|
||||||
} else {
|
} else {
|
||||||
@ -5692,11 +5692,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
|
|
||||||
var messageCount = 0
|
var messageCount = 0
|
||||||
if let summaryView = views.views[countViewKey] as? MessageHistoryTagSummaryView, let count = summaryView.count {
|
if let summaryView = views.views[countViewKey] as? MessageHistoryTagSummaryView, let count = summaryView.count {
|
||||||
if replyThreadId == 1 {
|
|
||||||
messageCount += Int(count)
|
messageCount += Int(count)
|
||||||
} else {
|
|
||||||
messageCount += max(Int(count) - 1, 0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (peer, messageCount)
|
return (peer, messageCount)
|
||||||
@ -5822,7 +5818,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
peerPresences: [:],
|
peerPresences: [:],
|
||||||
cachedData: nil
|
cachedData: nil
|
||||||
)
|
)
|
||||||
strongSelf.chatTitleView?.titleContent = .peer(peerView: mappedPeerData, customTitle: nil, onlineMemberCount: nil, isScheduledMessages: false, isMuted: false, customMessageCount: savedMessagesPeer?.messageCount == 0 ? nil : savedMessagesPeer?.messageCount, isEnabled: true)
|
strongSelf.chatTitleView?.titleContent = .peer(peerView: mappedPeerData, customTitle: nil, onlineMemberCount: nil, isScheduledMessages: false, isMuted: false, customMessageCount: savedMessagesPeer?.messageCount ?? 0, isEnabled: true)
|
||||||
|
|
||||||
strongSelf.peerView = peerView
|
strongSelf.peerView = peerView
|
||||||
|
|
||||||
@ -6785,7 +6781,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
|
|
||||||
let chatLocation: ChatLocation
|
let chatLocation: ChatLocation
|
||||||
if let threadId {
|
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))
|
chatLocation = .replyThread(message: ChatReplyThreadMessage(messageId: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false))
|
||||||
} else {
|
} else {
|
||||||
chatLocation = .peer(id: peerId)
|
chatLocation = .peer(id: peerId)
|
||||||
}
|
}
|
||||||
@ -7090,7 +7086,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
strongSelf.chatDisplayNode.messageTransitionNode.addContentOffset(offset: offset, itemNode: itemNode)
|
strongSelf.chatDisplayNode.messageTransitionNode.addContentOffset(offset: offset, itemNode: itemNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var closeOnEmpty = false
|
||||||
if case .pinnedMessages = self.presentationInterfaceState.subject {
|
if case .pinnedMessages = self.presentationInterfaceState.subject {
|
||||||
|
closeOnEmpty = true
|
||||||
|
} else if case let .replyThread(replyThreadMessage) = self.chatLocation, replyThreadMessage.messageId.peerId == self.context.account.peerId {
|
||||||
|
closeOnEmpty = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if closeOnEmpty {
|
||||||
self.chatDisplayNode.historyNode.setLoadStateUpdated({ [weak self] state, _ in
|
self.chatDisplayNode.historyNode.setLoadStateUpdated({ [weak self] state, _ in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
@ -12314,7 +12317,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
case .replyThread:
|
case .replyThread:
|
||||||
if let channel = self.presentationInterfaceState.renderedPeer?.peer as? TelegramChannel, channel.flags.contains(.isForum), case let .replyThread(message) = self.chatLocation {
|
if let peer = self.presentationInterfaceState.renderedPeer?.peer, case let .replyThread(replyThreadMessage) = self.chatLocation, replyThreadMessage.messageId.peerId == self.context.account.peerId {
|
||||||
|
if let infoController = self.context.sharedContext.makePeerInfoController(context: self.context, updatedPresentationData: self.updatedPresentationData, peer: peer, mode: .forumTopic(thread: replyThreadMessage), avatarInitiallyExpanded: false, fromChat: true, requestsContext: nil) {
|
||||||
|
self.effectiveNavigationController?.pushViewController(infoController)
|
||||||
|
}
|
||||||
|
} else if let channel = self.presentationInterfaceState.renderedPeer?.peer as? TelegramChannel, channel.flags.contains(.isForum), case let .replyThread(message) = self.chatLocation {
|
||||||
if let infoController = self.context.sharedContext.makePeerInfoController(context: self.context, updatedPresentationData: self.updatedPresentationData, peer: channel, mode: .forumTopic(thread: message), avatarInitiallyExpanded: false, fromChat: true, requestsContext: self.inviteRequestsContext) {
|
if let infoController = self.context.sharedContext.makePeerInfoController(context: self.context, updatedPresentationData: self.updatedPresentationData, peer: channel, mode: .forumTopic(thread: message), avatarInitiallyExpanded: false, fromChat: true, requestsContext: self.inviteRequestsContext) {
|
||||||
self.effectiveNavigationController?.pushViewController(infoController)
|
self.effectiveNavigationController?.pushViewController(infoController)
|
||||||
}
|
}
|
||||||
|
@ -3484,7 +3484,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
|
|
||||||
var replyThreadId: Int64?
|
var replyThreadId: Int64?
|
||||||
if case let .replyThread(replyThreadMessage) = self.chatPresentationInterfaceState.chatLocation {
|
if case let .replyThread(replyThreadMessage) = self.chatPresentationInterfaceState.chatLocation {
|
||||||
replyThreadId = Int64(replyThreadMessage.messageId.id)
|
replyThreadId = replyThreadMessage.threadId
|
||||||
}
|
}
|
||||||
|
|
||||||
for id in forwardMessageIds.sorted() {
|
for id in forwardMessageIds.sorted() {
|
||||||
|
@ -1973,6 +1973,7 @@ private func peerInfoControllerImpl(context: AccountContext, updatedPresentation
|
|||||||
var reactionSourceMessageId: MessageId?
|
var reactionSourceMessageId: MessageId?
|
||||||
var callMessages: [Message] = []
|
var callMessages: [Message] = []
|
||||||
var hintGroupInCommon: PeerId?
|
var hintGroupInCommon: PeerId?
|
||||||
|
var forumTopicThread: ChatReplyThreadMessage?
|
||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
case let .nearbyPeer(distance):
|
case let .nearbyPeer(distance):
|
||||||
@ -1985,12 +1986,12 @@ private func peerInfoControllerImpl(context: AccountContext, updatedPresentation
|
|||||||
hintGroupInCommon = id
|
hintGroupInCommon = id
|
||||||
case let .reaction(messageId):
|
case let .reaction(messageId):
|
||||||
reactionSourceMessageId = messageId
|
reactionSourceMessageId = messageId
|
||||||
case .forumTopic:
|
case let .forumTopic(thread):
|
||||||
break
|
forumTopicThread = thread
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nearbyPeerDistance, reactionSourceMessageId: reactionSourceMessageId, callMessages: callMessages, hintGroupInCommon: hintGroupInCommon)
|
return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nearbyPeerDistance, reactionSourceMessageId: reactionSourceMessageId, callMessages: callMessages, hintGroupInCommon: hintGroupInCommon, forumTopicThread: forumTopicThread)
|
||||||
} else if peer is TelegramSecretChat {
|
} else if peer is TelegramSecretChat {
|
||||||
return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nil, reactionSourceMessageId: nil, callMessages: [])
|
return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nil, reactionSourceMessageId: nil, callMessages: [])
|
||||||
}
|
}
|
||||||
|
@ -716,7 +716,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl)
|
|||||||
return .progress
|
return .progress
|
||||||
case let .result(info):
|
case let .result(info):
|
||||||
if let _ = info {
|
if let _ = info {
|
||||||
return .result(.replyThreadMessage(replyThreadMessage: ChatReplyThreadMessage(messageId: MessageId(peerId: channel.id, 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), messageId: messageId))
|
return .result(.replyThreadMessage(replyThreadMessage: ChatReplyThreadMessage(messageId: MessageId(peerId: channel.id, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false), messageId: messageId))
|
||||||
} else {
|
} else {
|
||||||
return .result(.peer(peer._asPeer(), .chat(textInputState: nil, subject: nil, peekData: nil)))
|
return .result(.peer(peer._asPeer(), .chat(textInputState: nil, subject: nil, peekData: nil)))
|
||||||
}
|
}
|
||||||
@ -741,7 +741,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl)
|
|||||||
return .progress
|
return .progress
|
||||||
case let .result(info):
|
case let .result(info):
|
||||||
if let _ = info {
|
if let _ = info {
|
||||||
return .result(.replyThreadMessage(replyThreadMessage: ChatReplyThreadMessage(messageId: MessageId(peerId: channel.id, namespace: Namespaces.Message.Cloud, id: Int32(clamping: replyThreadMessageId.id)), channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false), messageId: MessageId(peerId: channel.id, namespace: Namespaces.Message.Cloud, id: replyId)))
|
return .result(.replyThreadMessage(replyThreadMessage: ChatReplyThreadMessage(messageId: MessageId(peerId: channel.id, namespace: Namespaces.Message.Cloud, id: Int32(clamping: replyThreadMessageId.id)), threadId: Int64(replyThreadMessageId.id), channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false), messageId: MessageId(peerId: channel.id, namespace: Namespaces.Message.Cloud, id: replyId)))
|
||||||
} else {
|
} else {
|
||||||
return .result(.peer(peer._asPeer(), .chat(textInputState: nil, subject: nil, peekData: nil)))
|
return .result(.peer(peer._asPeer(), .chat(textInputState: nil, subject: nil, peekData: nil)))
|
||||||
}
|
}
|
||||||
@ -822,7 +822,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl)
|
|||||||
return .progress
|
return .progress
|
||||||
case let .result(info):
|
case let .result(info):
|
||||||
if let _ = info {
|
if let _ = info {
|
||||||
return .result(.replyThreadMessage(replyThreadMessage: ChatReplyThreadMessage(messageId: MessageId(peerId: channel.id, 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), messageId: messageId))
|
return .result(.replyThreadMessage(replyThreadMessage: ChatReplyThreadMessage(messageId: MessageId(peerId: channel.id, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: Int64(threadId), channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false), messageId: messageId))
|
||||||
} else {
|
} else {
|
||||||
return .result(.peer(peer?._asPeer(), .chat(textInputState: nil, subject: nil, peekData: nil)))
|
return .result(.peer(peer?._asPeer(), .chat(textInputState: nil, subject: nil, peekData: nil)))
|
||||||
}
|
}
|
||||||
@ -843,7 +843,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl)
|
|||||||
return .progress
|
return .progress
|
||||||
case let .result(info):
|
case let .result(info):
|
||||||
if let _ = info {
|
if let _ = info {
|
||||||
return .result(.replyThreadMessage(replyThreadMessage: ChatReplyThreadMessage(messageId: MessageId(peerId: channel.id, 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), messageId: messageId))
|
return .result(.replyThreadMessage(replyThreadMessage: ChatReplyThreadMessage(messageId: MessageId(peerId: channel.id, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false), messageId: messageId))
|
||||||
} else {
|
} else {
|
||||||
return .result(.peer(peer?._asPeer(), .chat(textInputState: nil, subject: nil, peekData: nil)))
|
return .result(.peer(peer?._asPeer(), .chat(textInputState: nil, subject: nil, peekData: nil)))
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user