mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
[WIP] Topics
This commit is contained in:
parent
d9ab563c94
commit
e0746fa0c2
@ -277,6 +277,7 @@ public enum ResolvedUrl {
|
||||
case groupBotStart(peerId: PeerId, payload: String, adminRights: ResolvedBotAdminRights?)
|
||||
case channelMessage(peer: Peer, messageId: MessageId, timecode: Double?)
|
||||
case replyThreadMessage(replyThreadMessage: ChatReplyThreadMessage, messageId: MessageId)
|
||||
case replyThread(messageId: MessageId)
|
||||
case stickerPack(name: String, type: StickerPackUrlType)
|
||||
case instantView(TelegramMediaWebpage, String?)
|
||||
case proxy(host: String, port: Int32, username: String?, password: String?, secret: Data?)
|
||||
@ -737,7 +738,7 @@ public protocol SharedAccountContext: AnyObject {
|
||||
func makePrivacyAndSecurityController(context: AccountContext) -> ViewController
|
||||
func navigateToChatController(_ params: NavigateToChatControllerParams)
|
||||
func navigateToForumChannel(context: AccountContext, peerId: EnginePeer.Id, navigationController: NavigationController)
|
||||
func navigateToForumThread(context: AccountContext, peerId: EnginePeer.Id, threadId: Int64, messageId: EngineMessage.Id?, navigationController: NavigationController, activateInput: ChatControllerActivateInput?) -> Signal<Never, NoError>
|
||||
func navigateToForumThread(context: AccountContext, peerId: EnginePeer.Id, threadId: Int64, messageId: EngineMessage.Id?, navigationController: NavigationController, activateInput: ChatControllerActivateInput?, keepStack: NavigateToChatKeepStack) -> Signal<Never, NoError>
|
||||
func chatControllerForForumThread(context: AccountContext, peerId: EnginePeer.Id, threadId: Int64) -> Signal<ChatController, NoError>
|
||||
func openStorageUsage(context: AccountContext)
|
||||
func openLocationScreen(context: AccountContext, messageId: MessageId, navigationController: NavigationController)
|
||||
|
@ -31,8 +31,9 @@ public final class ChatMessageItemAssociatedData: Equatable {
|
||||
public let isPremium: Bool
|
||||
public let forceInlineReactions: Bool
|
||||
public let accountPeer: EnginePeer?
|
||||
public let topicAuthorId: EnginePeer.Id?
|
||||
|
||||
public init(automaticDownloadPeerType: MediaAutoDownloadPeerType, automaticDownloadNetworkType: MediaAutoDownloadNetworkType, isRecentActions: Bool = false, subject: ChatControllerSubject? = nil, contactsPeerIds: Set<EnginePeer.Id> = Set(), channelDiscussionGroup: ChannelDiscussionGroupStatus = .unknown, animatedEmojiStickers: [String: [StickerPackItem]] = [:], additionalAnimatedEmojiStickers: [String: [Int: StickerPackItem]] = [:], forcedResourceStatus: FileMediaResourceStatus? = nil, currentlyPlayingMessageId: EngineMessage.Index? = nil, isCopyProtectionEnabled: Bool = false, availableReactions: AvailableReactions?, defaultReaction: MessageReaction.Reaction?, isPremium: Bool, accountPeer: EnginePeer?, forceInlineReactions: Bool = false) {
|
||||
public init(automaticDownloadPeerType: MediaAutoDownloadPeerType, automaticDownloadNetworkType: MediaAutoDownloadNetworkType, isRecentActions: Bool = false, subject: ChatControllerSubject? = nil, contactsPeerIds: Set<EnginePeer.Id> = Set(), channelDiscussionGroup: ChannelDiscussionGroupStatus = .unknown, animatedEmojiStickers: [String: [StickerPackItem]] = [:], additionalAnimatedEmojiStickers: [String: [Int: StickerPackItem]] = [:], forcedResourceStatus: FileMediaResourceStatus? = nil, currentlyPlayingMessageId: EngineMessage.Index? = nil, isCopyProtectionEnabled: Bool = false, availableReactions: AvailableReactions?, defaultReaction: MessageReaction.Reaction?, isPremium: Bool, accountPeer: EnginePeer?, forceInlineReactions: Bool = false, topicAuthorId: EnginePeer.Id? = nil) {
|
||||
self.automaticDownloadPeerType = automaticDownloadPeerType
|
||||
self.automaticDownloadNetworkType = automaticDownloadNetworkType
|
||||
self.isRecentActions = isRecentActions
|
||||
@ -49,6 +50,7 @@ public final class ChatMessageItemAssociatedData: Equatable {
|
||||
self.isPremium = isPremium
|
||||
self.accountPeer = accountPeer
|
||||
self.forceInlineReactions = forceInlineReactions
|
||||
self.topicAuthorId = topicAuthorId
|
||||
}
|
||||
|
||||
public static func == (lhs: ChatMessageItemAssociatedData, rhs: ChatMessageItemAssociatedData) -> Bool {
|
||||
@ -97,6 +99,9 @@ public final class ChatMessageItemAssociatedData: Equatable {
|
||||
if lhs.forceInlineReactions != rhs.forceInlineReactions {
|
||||
return false
|
||||
}
|
||||
if lhs.topicAuthorId != rhs.topicAuthorId {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -1372,7 +1372,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
strongSelf.context.sharedContext.navigateToForumChannel(context: strongSelf.context, peerId: channel.id, navigationController: navigationController)
|
||||
} else {
|
||||
if let threadId = threadId {
|
||||
let _ = strongSelf.context.sharedContext.navigateToForumThread(context: strongSelf.context, peerId: peer.id, threadId: threadId, messageId: nil, navigationController: navigationController, activateInput: nil).start()
|
||||
let _ = strongSelf.context.sharedContext.navigateToForumThread(context: strongSelf.context, peerId: peer.id, threadId: threadId, messageId: nil, navigationController: navigationController, activateInput: nil, keepStack: .never).start()
|
||||
strongSelf.chatListDisplayNode.containerNode.currentItemNode.clearHighlightAnimated(true)
|
||||
} else {
|
||||
var navigationAnimationOptions: NavigationAnimationOptions = []
|
||||
@ -1473,7 +1473,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
navigationAnimationOptions = .removeOnMasterDetails
|
||||
}
|
||||
if let threadId = threadId {
|
||||
let _ = strongSelf.context.sharedContext.navigateToForumThread(context: strongSelf.context, peerId: peer.id, threadId: threadId, messageId: messageId, navigationController: navigationController, activateInput: nil).start()
|
||||
let _ = strongSelf.context.sharedContext.navigateToForumThread(context: strongSelf.context, peerId: peer.id, threadId: threadId, messageId: messageId, navigationController: navigationController, activateInput: nil, keepStack: .never).start()
|
||||
} else {
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(id: actualPeerId), subject: .message(id: .id(messageId), highlight: true, timecode: nil), purposefulAction: {
|
||||
if deactivateOnAction {
|
||||
@ -1506,7 +1506,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
navigationAnimationOptions = .removeOnMasterDetails
|
||||
}
|
||||
if let threadId = threadId {
|
||||
let _ = strongSelf.context.sharedContext.navigateToForumThread(context: strongSelf.context, peerId: peer.id, threadId: threadId, messageId: nil, navigationController: navigationController, activateInput: nil).start()
|
||||
let _ = strongSelf.context.sharedContext.navigateToForumThread(context: strongSelf.context, peerId: peer.id, threadId: threadId, messageId: nil, navigationController: navigationController, activateInput: nil, keepStack: .never).start()
|
||||
} else {
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(id: peer.id), purposefulAction: { [weak self] in
|
||||
self?.deactivateSearch(animated: false)
|
||||
@ -1602,7 +1602,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
|
||||
let _ = (context.engine.peers.createForumChannelTopic(id: peerId, title: title, iconColor: ForumCreateTopicScreen.iconColors.randomElement()!, iconFileId: fileId)
|
||||
|> deliverOnMainQueue).start(next: { topicId in
|
||||
let _ = context.sharedContext.navigateToForumThread(context: context, peerId: peerId, threadId: topicId, messageId: nil, navigationController: navigationController, activateInput: .text).start()
|
||||
let _ = context.sharedContext.navigateToForumThread(context: context, peerId: peerId, threadId: topicId, messageId: nil, navigationController: navigationController, activateInput: .text, keepStack: .never).start()
|
||||
}, error: { _ in
|
||||
controller?.isInProgress = false
|
||||
})
|
||||
@ -2670,7 +2670,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
let _ = (context.engine.peers.createForumChannelTopic(id: peerId, title: title, iconColor: ForumCreateTopicScreen.iconColors.randomElement()!, iconFileId: fileId)
|
||||
|> deliverOnMainQueue).start(next: { topicId in
|
||||
if let navigationController = (sourceController.navigationController as? NavigationController) {
|
||||
let _ = context.sharedContext.navigateToForumThread(context: context, peerId: peerId, threadId: topicId, messageId: nil, navigationController: navigationController, activateInput: .text).start()
|
||||
let _ = context.sharedContext.navigateToForumThread(context: context, peerId: peerId, threadId: topicId, messageId: nil, navigationController: navigationController, activateInput: .text, keepStack: .never).start()
|
||||
}
|
||||
}, error: { _ in
|
||||
controller?.isInProgress = false
|
||||
|
@ -2534,7 +2534,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
if let currentMutedIconImage = currentMutedIconImage {
|
||||
strongSelf.mutedIconNode.image = currentMutedIconImage
|
||||
strongSelf.mutedIconNode.isHidden = false
|
||||
transition.updateFrame(node: strongSelf.mutedIconNode, frame: CGRect(origin: CGPoint(x: nextTitleIconOrigin - 5.0, y: floorToScreenPixels(titleFrame.midY - currentMutedIconImage.size.height / 2.0) - UIScreenPixel), size: currentMutedIconImage.size))
|
||||
transition.updateFrame(node: strongSelf.mutedIconNode, frame: CGRect(origin: CGPoint(x: nextTitleIconOrigin - 5.0, y: titleFrame.minY - 1.0 - UIScreenPixel), size: currentMutedIconImage.size))
|
||||
nextTitleIconOrigin += currentMutedIconImage.size.width + 1.0
|
||||
} else {
|
||||
strongSelf.mutedIconNode.image = nil
|
||||
|
@ -196,6 +196,12 @@ public func combineLatest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13
|
||||
}, initialValues: [:], queue: queue)
|
||||
}
|
||||
|
||||
public func combineLatest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, E>(queue: Queue? = nil, _ s1: Signal<T1, E>, _ s2: Signal<T2, E>, _ s3: Signal<T3, E>, _ s4: Signal<T4, E>, _ s5: Signal<T5, E>, _ s6: Signal<T6, E>, _ s7: Signal<T7, E>, _ s8: Signal<T8, E>, _ s9: Signal<T9, E>, _ s10: Signal<T10, E>, _ s11: Signal<T11, E>, _ s12: Signal<T12, E>, _ s13: Signal<T13, E>, _ s14: Signal<T14, E>, _ s15: Signal<T15, E>, _ s16: Signal<T16, E>, _ s17: Signal<T17, E>, _ s18: Signal<T18, E>, _ s19: Signal<T19, E>) -> Signal<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19), E> {
|
||||
return combineLatestAny([signalOfAny(s1), signalOfAny(s2), signalOfAny(s3), signalOfAny(s4), signalOfAny(s5), signalOfAny(s6), signalOfAny(s7), signalOfAny(s8), signalOfAny(s9), signalOfAny(s10), signalOfAny(s11), signalOfAny(s12), signalOfAny(s13), signalOfAny(s14), signalOfAny(s15), signalOfAny(s16), signalOfAny(s17), signalOfAny(s18), signalOfAny(s19)], combine: { values in
|
||||
return (values[0] as! T1, values[1] as! T2, values[2] as! T3, values[3] as! T4, values[4] as! T5, values[5] as! T6, values[6] as! T7, values[7] as! T8, values[8] as! T9, values[9] as! T10, values[10] as! T11, values[11] as! T12, values[12] as! T13, values[13] as! T14, values[14] as! T15, values[15] as! T16, values[16] as! T17, values[17] as! T18, values[18] as! T19)
|
||||
}, initialValues: [:], queue: queue)
|
||||
}
|
||||
|
||||
public func combineLatest<T, E>(queue: Queue? = nil, _ signals: [Signal<T, E>]) -> Signal<[T], E> {
|
||||
if signals.count == 0 {
|
||||
return single([T](), E.self)
|
||||
|
@ -238,6 +238,32 @@ func _internal_createForumChannelTopic(account: Account, peerId: PeerId, title:
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_fetchForumChannelTopic(account: Account, peerId: PeerId, threadId: Int64) -> Signal<EngineMessageHistoryThread.Info?, NoError> {
|
||||
return account.postbox.transaction { transaction -> (info: EngineMessageHistoryThread.Info?, inputChannel: Api.InputChannel?) in
|
||||
if let data = transaction.getMessageHistoryThreadInfo(peerId: peerId, threadId: threadId)?.data.get(MessageHistoryThreadData.self) {
|
||||
return (data.info, nil)
|
||||
} else {
|
||||
return (nil, transaction.getPeer(peerId).flatMap(apiInputChannel))
|
||||
}
|
||||
}
|
||||
|> mapToSignal { info, _ -> Signal<EngineMessageHistoryThread.Info?, NoError> in
|
||||
if let info = info {
|
||||
return .single(info)
|
||||
} else {
|
||||
return resolveForumThreads(postbox: account.postbox, network: account.network, ids: [MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId))])
|
||||
|> mapToSignal { _ -> Signal<EngineMessageHistoryThread.Info?, NoError> in
|
||||
return account.postbox.transaction { transaction -> EngineMessageHistoryThread.Info? in
|
||||
if let data = transaction.getMessageHistoryThreadInfo(peerId: peerId, threadId: threadId)?.data.get(MessageHistoryThreadData.self) {
|
||||
return data.info
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum EditForumChannelTopicError {
|
||||
case generic
|
||||
}
|
||||
|
@ -832,6 +832,10 @@ public extension TelegramEngine {
|
||||
return _internal_createForumChannelTopic(account: self.account, peerId: id, title: title, iconColor: iconColor, iconFileId: iconFileId)
|
||||
}
|
||||
|
||||
public func fetchForumChannelTopic(id: EnginePeer.Id, threadId: Int64) -> Signal<EngineMessageHistoryThread.Info?, NoError> {
|
||||
return _internal_fetchForumChannelTopic(account: self.account, peerId: id, threadId: threadId)
|
||||
}
|
||||
|
||||
public func editForumChannelTopic(id: EnginePeer.Id, threadId: Int64, title: String, iconFileId: Int64?) -> Signal<Never, EditForumChannelTopicError> {
|
||||
return _internal_editForumChannelTopic(account: self.account, peerId: id, threadId: threadId, title: title, iconFileId: iconFileId)
|
||||
}
|
||||
|
@ -314,7 +314,7 @@ private final class ChatHistoryTransactionOpaqueState {
|
||||
}
|
||||
}
|
||||
|
||||
private func extractAssociatedData(chatLocation: ChatLocation, view: MessageHistoryView, automaticDownloadNetworkType: MediaAutoDownloadNetworkType, animatedEmojiStickers: [String: [StickerPackItem]], additionalAnimatedEmojiStickers: [String: [Int: StickerPackItem]], subject: ChatControllerSubject?, currentlyPlayingMessageId: MessageIndex?, isCopyProtectionEnabled: Bool, availableReactions: AvailableReactions?, defaultReaction: MessageReaction.Reaction?, isPremium: Bool, accountPeer: EnginePeer?) -> ChatMessageItemAssociatedData {
|
||||
private func extractAssociatedData(chatLocation: ChatLocation, view: MessageHistoryView, automaticDownloadNetworkType: MediaAutoDownloadNetworkType, animatedEmojiStickers: [String: [StickerPackItem]], additionalAnimatedEmojiStickers: [String: [Int: StickerPackItem]], subject: ChatControllerSubject?, currentlyPlayingMessageId: MessageIndex?, isCopyProtectionEnabled: Bool, availableReactions: AvailableReactions?, defaultReaction: MessageReaction.Reaction?, isPremium: Bool, accountPeer: EnginePeer?, topicAuthorId: EnginePeer.Id?) -> ChatMessageItemAssociatedData {
|
||||
var automaticMediaDownloadPeerType: MediaAutoDownloadPeerType = .channel
|
||||
var contactsPeerIds: Set<PeerId> = Set()
|
||||
var channelDiscussionGroup: ChatMessageItemAssociatedData.ChannelDiscussionGroupStatus = .unknown
|
||||
@ -363,7 +363,7 @@ private func extractAssociatedData(chatLocation: ChatLocation, view: MessageHist
|
||||
}
|
||||
}
|
||||
|
||||
return ChatMessageItemAssociatedData(automaticDownloadPeerType: automaticMediaDownloadPeerType, automaticDownloadNetworkType: automaticDownloadNetworkType, isRecentActions: false, subject: subject, contactsPeerIds: contactsPeerIds, channelDiscussionGroup: channelDiscussionGroup, animatedEmojiStickers: animatedEmojiStickers, additionalAnimatedEmojiStickers: additionalAnimatedEmojiStickers, currentlyPlayingMessageId: currentlyPlayingMessageId, isCopyProtectionEnabled: isCopyProtectionEnabled, availableReactions: availableReactions, defaultReaction: defaultReaction, isPremium: isPremium, accountPeer: accountPeer)
|
||||
return ChatMessageItemAssociatedData(automaticDownloadPeerType: automaticMediaDownloadPeerType, automaticDownloadNetworkType: automaticDownloadNetworkType, isRecentActions: false, subject: subject, contactsPeerIds: contactsPeerIds, channelDiscussionGroup: channelDiscussionGroup, animatedEmojiStickers: animatedEmojiStickers, additionalAnimatedEmojiStickers: additionalAnimatedEmojiStickers, currentlyPlayingMessageId: currentlyPlayingMessageId, isCopyProtectionEnabled: isCopyProtectionEnabled, availableReactions: availableReactions, defaultReaction: defaultReaction, isPremium: isPremium, accountPeer: accountPeer, topicAuthorId: topicAuthorId)
|
||||
}
|
||||
|
||||
private extension ChatHistoryLocationInput {
|
||||
@ -1032,6 +1032,17 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|
||||
let topicAuthorId: Signal<EnginePeer.Id?, NoError>
|
||||
if let peerId = chatLocation.peerId, let threadId = chatLocation.threadId {
|
||||
topicAuthorId = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.ThreadData(id: peerId, threadId: threadId))
|
||||
|> map { data -> EnginePeer.Id? in
|
||||
return data?.author
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
} else {
|
||||
topicAuthorId = .single(nil)
|
||||
}
|
||||
|
||||
let historyViewTransitionDisposable = combineLatest(queue: messageViewQueue,
|
||||
historyViewUpdate,
|
||||
self.chatPresentationDataPromise.get(),
|
||||
@ -1050,8 +1061,9 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
adMessages,
|
||||
availableReactions,
|
||||
defaultReaction,
|
||||
accountPeer
|
||||
).start(next: { [weak self] update, chatPresentationData, selectedMessages, updatingMedia, networkType, historyAppearsCleared, pendingUnpinnedAllMessages, pendingRemovedMessages, animatedEmojiStickers, additionalAnimatedEmojiStickers, customChannelDiscussionReadState, customThreadOutgoingReadState, currentlyPlayingMessageIdAndType, scrollToMessageId, adMessages, availableReactions, defaultReaction, accountPeer in
|
||||
accountPeer,
|
||||
topicAuthorId
|
||||
).start(next: { [weak self] update, chatPresentationData, selectedMessages, updatingMedia, networkType, historyAppearsCleared, pendingUnpinnedAllMessages, pendingRemovedMessages, animatedEmojiStickers, additionalAnimatedEmojiStickers, customChannelDiscussionReadState, customThreadOutgoingReadState, currentlyPlayingMessageIdAndType, scrollToMessageId, adMessages, availableReactions, defaultReaction, accountPeer, topicAuthorId in
|
||||
let currentlyPlayingMessageId = currentlyPlayingMessageIdAndType?.0
|
||||
|
||||
func applyHole() {
|
||||
@ -1185,7 +1197,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
isPremium = true
|
||||
}
|
||||
|
||||
let associatedData = extractAssociatedData(chatLocation: chatLocation, view: view, automaticDownloadNetworkType: networkType, animatedEmojiStickers: animatedEmojiStickers, additionalAnimatedEmojiStickers: additionalAnimatedEmojiStickers, subject: subject, currentlyPlayingMessageId: currentlyPlayingMessageId, isCopyProtectionEnabled: isCopyProtectionEnabled, availableReactions: availableReactions, defaultReaction: defaultReaction, isPremium: isPremium, accountPeer: accountPeer)
|
||||
let associatedData = extractAssociatedData(chatLocation: chatLocation, view: view, automaticDownloadNetworkType: networkType, animatedEmojiStickers: animatedEmojiStickers, additionalAnimatedEmojiStickers: additionalAnimatedEmojiStickers, subject: subject, currentlyPlayingMessageId: currentlyPlayingMessageId, isCopyProtectionEnabled: isCopyProtectionEnabled, availableReactions: availableReactions, defaultReaction: defaultReaction, isPremium: isPremium, accountPeer: accountPeer, topicAuthorId: topicAuthorId)
|
||||
|
||||
let filteredEntries = chatHistoryEntriesForView(
|
||||
location: chatLocation,
|
||||
|
@ -1392,6 +1392,13 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
||||
}
|
||||
authorRank = attributes.rank
|
||||
}
|
||||
|
||||
if authorRank == nil {
|
||||
if let topicAuthorId = item.associatedData.topicAuthorId, topicAuthorId == message.author?.id {
|
||||
//TODO:localize
|
||||
authorRank = .custom("Topic Author")
|
||||
}
|
||||
}
|
||||
case .group:
|
||||
break
|
||||
}
|
||||
|
@ -1571,7 +1571,7 @@ private class QrContentNode: ASDisplayNode, ContentNode {
|
||||
codeLink = ""
|
||||
}
|
||||
if let threadId = threadId {
|
||||
codeLink += "?topic=\(threadId)"
|
||||
codeLink += "/\(threadId)"
|
||||
}
|
||||
|
||||
let codeReadyPromise = ValuePromise<Bool>()
|
||||
|
@ -901,6 +901,10 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
||||
if let navigationController = strongSelf.getNavigationController() {
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .replyThread(message: replyThreadMessage), subject: .message(id: .id(messageId), highlight: true, timecode: nil)))
|
||||
}
|
||||
case let .replyThread(messageId):
|
||||
if let navigationController = strongSelf.getNavigationController() {
|
||||
let _ = strongSelf.context.sharedContext.navigateToForumThread(context: strongSelf.context, peerId: messageId.peerId, threadId: Int64(messageId.id), messageId: nil, navigationController: navigationController, activateInput: nil, keepStack: .always).start()
|
||||
}
|
||||
case let .stickerPack(name, type):
|
||||
let _ = type
|
||||
let packReference: StickerPackReference = .name(name)
|
||||
|
@ -227,7 +227,7 @@ public func isOverlayControllerForChatNotificationOverlayPresentation(_ controll
|
||||
return false
|
||||
}
|
||||
|
||||
public func navigateToForumThreadImpl(context: AccountContext, peerId: EnginePeer.Id, threadId: Int64, messageId: EngineMessage.Id?, navigationController: NavigationController, activateInput: ChatControllerActivateInput?) -> Signal<Never, NoError> {
|
||||
public func navigateToForumThreadImpl(context: AccountContext, peerId: EnginePeer.Id, threadId: Int64, messageId: EngineMessage.Id?, navigationController: NavigationController, activateInput: ChatControllerActivateInput?, keepStack: NavigateToChatKeepStack) -> Signal<Never, NoError> {
|
||||
return fetchAndPreloadReplyThreadInfo(context: context, subject: .groupMessage(MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId))), atMessageId: messageId, preload: false)
|
||||
|> deliverOnMainQueue
|
||||
|> beforeNext { [weak context, weak navigationController] result in
|
||||
@ -248,7 +248,7 @@ public func navigateToForumThreadImpl(context: AccountContext, peerId: EnginePee
|
||||
chatLocationContextHolder: result.contextHolder,
|
||||
subject: messageId.flatMap { .message(id: .id($0), highlight: true, timecode: nil) },
|
||||
activateInput: actualActivateInput,
|
||||
keepStack: .never
|
||||
keepStack: keepStack
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -163,6 +163,10 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
|
||||
present(c, a)
|
||||
}, messageId: replyThreadMessage.messageId, isChannelPost: replyThreadMessage.isChannelPost, atMessage: messageId, displayModalProgress: true).start()
|
||||
}
|
||||
case let .replyThread(messageId):
|
||||
if let navigationController = navigationController {
|
||||
let _ = context.sharedContext.navigateToForumThread(context: context, peerId: messageId.peerId, threadId: Int64(messageId.id), messageId: nil, navigationController: navigationController, activateInput: nil, keepStack: .always).start()
|
||||
}
|
||||
case let .stickerPack(name, _):
|
||||
dismissInput()
|
||||
|
||||
|
@ -1,19 +1,22 @@
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import TelegramPresentationData
|
||||
import AppBundle
|
||||
|
||||
final class PeerInfoScreenSwitchItem: PeerInfoScreenItem {
|
||||
let id: AnyHashable
|
||||
let text: String
|
||||
let value: Bool
|
||||
let icon: UIImage?
|
||||
let isLocked: Bool
|
||||
let toggled: ((Bool) -> Void)?
|
||||
|
||||
init(id: AnyHashable, text: String, value: Bool, icon: UIImage? = nil, toggled: ((Bool) -> Void)?) {
|
||||
init(id: AnyHashable, text: String, value: Bool, icon: UIImage? = nil, isLocked: Bool = false, toggled: ((Bool) -> Void)?) {
|
||||
self.id = id
|
||||
self.text = text
|
||||
self.value = value
|
||||
self.icon = icon
|
||||
self.isLocked = isLocked
|
||||
self.toggled = toggled
|
||||
}
|
||||
|
||||
@ -28,7 +31,9 @@ private final class PeerInfoScreenSwitchItemNode: PeerInfoScreenItemNode {
|
||||
private let iconNode: ASImageNode
|
||||
private let textNode: ImmediateTextNode
|
||||
private let switchNode: SwitchNode
|
||||
private var lockedIconNode: ASImageNode?
|
||||
private let bottomSeparatorNode: ASDisplayNode
|
||||
private var lockedButtonNode: HighlightableButtonNode?
|
||||
private let activateArea: AccessibilityAreaNode
|
||||
|
||||
private var item: PeerInfoScreenSwitchItem?
|
||||
@ -91,12 +96,51 @@ private final class PeerInfoScreenSwitchItemNode: PeerInfoScreenItemNode {
|
||||
|
||||
let firstTime = self.item == nil
|
||||
|
||||
var updateLockedIconImage = false
|
||||
if item.isLocked {
|
||||
let lockedIconNode: ASImageNode
|
||||
if let current = self.lockedIconNode {
|
||||
lockedIconNode = current
|
||||
} else {
|
||||
updateLockedIconImage = true
|
||||
lockedIconNode = ASImageNode()
|
||||
self.lockedIconNode = lockedIconNode
|
||||
self.insertSubnode(lockedIconNode, aboveSubnode: self.switchNode)
|
||||
}
|
||||
|
||||
} else if let lockedIconNode = self.lockedIconNode {
|
||||
self.lockedIconNode = nil
|
||||
lockedIconNode.removeFromSupernode()
|
||||
}
|
||||
|
||||
if item.isLocked {
|
||||
self.switchNode.isUserInteractionEnabled = false
|
||||
if self.lockedButtonNode == nil {
|
||||
let lockedButtonNode = HighlightableButtonNode()
|
||||
self.lockedButtonNode = lockedButtonNode
|
||||
self.insertSubnode(lockedButtonNode, aboveSubnode: self.switchNode)
|
||||
lockedButtonNode.addTarget(self, action: #selector(self.lockedButtonPressed), forControlEvents: .touchUpInside)
|
||||
}
|
||||
} else {
|
||||
if let lockedButtonNode = self.lockedButtonNode {
|
||||
self.lockedButtonNode = nil
|
||||
lockedButtonNode.removeFromSupernode()
|
||||
}
|
||||
self.switchNode.isUserInteractionEnabled = true
|
||||
}
|
||||
|
||||
if self.theme !== presentationData.theme {
|
||||
self.theme = presentationData.theme
|
||||
|
||||
self.switchNode.frameColor = presentationData.theme.list.itemSwitchColors.frameColor
|
||||
self.switchNode.contentColor = presentationData.theme.list.itemSwitchColors.contentColor
|
||||
self.switchNode.handleColor = presentationData.theme.list.itemSwitchColors.handleColor
|
||||
|
||||
updateLockedIconImage = true
|
||||
}
|
||||
|
||||
if updateLockedIconImage, let lockedIconNode = self.lockedIconNode, let image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/TextLockIcon"), color: presentationData.theme.list.itemSecondaryTextColor) {
|
||||
lockedIconNode.image = image
|
||||
}
|
||||
|
||||
self.item = item
|
||||
@ -143,10 +187,17 @@ private final class PeerInfoScreenSwitchItemNode: PeerInfoScreenItemNode {
|
||||
}
|
||||
let switchSize = switchView.bounds.size
|
||||
|
||||
self.switchNode.frame = CGRect(origin: CGPoint(x: width - switchSize.width - 15.0 - safeInsets.right, y: floor((height - switchSize.height) / 2.0)), size: switchSize)
|
||||
let switchFrame = CGRect(origin: CGPoint(x: width - switchSize.width - 15.0 - safeInsets.right, y: floor((height - switchSize.height) / 2.0)), size: switchSize)
|
||||
self.switchNode.frame = switchFrame
|
||||
if switchView.isOn != item.value {
|
||||
switchView.setOn(item.value, animated: !firstTime)
|
||||
}
|
||||
|
||||
self.lockedButtonNode?.frame = switchFrame
|
||||
|
||||
if let lockedIconNode = self.lockedIconNode, let icon = lockedIconNode.image {
|
||||
lockedIconNode.frame = CGRect(origin: CGPoint(x: switchFrame.minX + 10.0 + UIScreenPixel, y: switchFrame.minY + 9.0), size: icon.size)
|
||||
}
|
||||
}
|
||||
|
||||
let hasCorners = hasCorners && (topItem == nil || bottomItem == nil)
|
||||
@ -168,4 +219,8 @@ private final class PeerInfoScreenSwitchItemNode: PeerInfoScreenItemNode {
|
||||
|
||||
return height
|
||||
}
|
||||
|
||||
@objc private func lockedButtonPressed() {
|
||||
self.item?.toggled?(self.switchNode.isOn)
|
||||
}
|
||||
}
|
||||
|
@ -188,6 +188,7 @@ final class PeerInfoScreenData {
|
||||
let requests: PeerInvitationImportersState?
|
||||
let requestsContext: PeerInvitationImportersContext?
|
||||
let threadData: MessageHistoryThreadData?
|
||||
let appConfiguration: AppConfiguration?
|
||||
|
||||
init(
|
||||
peer: Peer?,
|
||||
@ -206,7 +207,8 @@ final class PeerInfoScreenData {
|
||||
invitations: PeerExportedInvitationsState?,
|
||||
requests: PeerInvitationImportersState?,
|
||||
requestsContext: PeerInvitationImportersContext?,
|
||||
threadData: MessageHistoryThreadData?
|
||||
threadData: MessageHistoryThreadData?,
|
||||
appConfiguration: AppConfiguration?
|
||||
) {
|
||||
self.peer = peer
|
||||
self.chatPeer = chatPeer
|
||||
@ -225,6 +227,7 @@ final class PeerInfoScreenData {
|
||||
self.requests = requests
|
||||
self.requestsContext = requestsContext
|
||||
self.threadData = threadData
|
||||
self.appConfiguration = appConfiguration
|
||||
}
|
||||
}
|
||||
|
||||
@ -435,7 +438,8 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
||||
})
|
||||
|
||||
var enableQRLogin = false
|
||||
if let appConfiguration = accountPreferences.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self), let data = appConfiguration.data, let enableQR = data["qr_login_camera"] as? Bool, enableQR {
|
||||
let appConfiguration = accountPreferences.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self)
|
||||
if let appConfiguration, let data = appConfiguration.data, let enableQR = data["qr_login_camera"] as? Bool, enableQR {
|
||||
enableQRLogin = true
|
||||
}
|
||||
|
||||
@ -477,7 +481,8 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
||||
invitations: nil,
|
||||
requests: nil,
|
||||
requestsContext: nil,
|
||||
threadData: nil
|
||||
threadData: nil,
|
||||
appConfiguration: appConfiguration
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -504,7 +509,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
invitations: nil,
|
||||
requests: nil,
|
||||
requestsContext: nil,
|
||||
threadData: nil
|
||||
threadData: nil,
|
||||
appConfiguration: nil
|
||||
))
|
||||
case let .user(userPeerId, secretChatId, kind):
|
||||
let groupsInCommon: GroupsInCommonContext?
|
||||
@ -635,7 +641,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
invitations: nil,
|
||||
requests: nil,
|
||||
requestsContext: nil,
|
||||
threadData: nil
|
||||
threadData: nil,
|
||||
appConfiguration: nil
|
||||
)
|
||||
}
|
||||
case .channel:
|
||||
@ -711,7 +718,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
invitations: invitations,
|
||||
requests: requests,
|
||||
requestsContext: currentRequestsContext,
|
||||
threadData: nil
|
||||
threadData: nil,
|
||||
appConfiguration: nil
|
||||
)
|
||||
}
|
||||
case let .group(groupId):
|
||||
@ -840,9 +848,10 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
invitationsStatePromise.get(),
|
||||
requestsContextPromise.get(),
|
||||
requestsStatePromise.get(),
|
||||
threadData
|
||||
threadData,
|
||||
context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration])
|
||||
)
|
||||
|> map { peerView, availablePanes, globalNotificationSettings, status, membersData, currentInvitationsContext, invitations, currentRequestsContext, requests, threadData -> PeerInfoScreenData in
|
||||
|> map { peerView, availablePanes, globalNotificationSettings, status, membersData, currentInvitationsContext, invitations, currentRequestsContext, requests, threadData, preferencesView -> PeerInfoScreenData in
|
||||
var discussionPeer: Peer?
|
||||
if case let .known(maybeLinkedDiscussionPeerId) = (peerView.cachedData as? CachedChannelData)?.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId, let peer = peerView.peers[linkedDiscussionPeerId] {
|
||||
discussionPeer = peer
|
||||
@ -890,6 +899,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
notificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings
|
||||
}
|
||||
|
||||
let appConfiguration: AppConfiguration = preferencesView.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? .defaultValue
|
||||
|
||||
return PeerInfoScreenData(
|
||||
peer: peerView.peers[groupId],
|
||||
chatPeer: peerView.peers[groupId],
|
||||
@ -907,7 +918,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
invitations: invitations,
|
||||
requests: requests,
|
||||
requestsContext: currentRequestsContext,
|
||||
threadData: threadData
|
||||
threadData: threadData,
|
||||
appConfiguration: appConfiguration
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -509,6 +509,7 @@ private final class PeerInfoInteraction {
|
||||
let editingOpenReactionsSetup: () -> Void
|
||||
let dismissInput: () -> Void
|
||||
let toggleForumTopics: (Bool) -> Void
|
||||
let displayTopicsLimited: (Int) -> Void
|
||||
|
||||
init(
|
||||
openUsername: @escaping (String) -> Void,
|
||||
@ -553,7 +554,8 @@ private final class PeerInfoInteraction {
|
||||
openQrCode: @escaping () -> Void,
|
||||
editingOpenReactionsSetup: @escaping () -> Void,
|
||||
dismissInput: @escaping () -> Void,
|
||||
toggleForumTopics: @escaping (Bool) -> Void
|
||||
toggleForumTopics: @escaping (Bool) -> Void,
|
||||
displayTopicsLimited: @escaping (Int) -> Void
|
||||
) {
|
||||
self.openUsername = openUsername
|
||||
self.openPhone = openPhone
|
||||
@ -598,6 +600,7 @@ private final class PeerInfoInteraction {
|
||||
self.editingOpenReactionsSetup = editingOpenReactionsSetup
|
||||
self.dismissInput = dismissInput
|
||||
self.toggleForumTopics = toggleForumTopics
|
||||
self.displayTopicsLimited = displayTopicsLimited
|
||||
}
|
||||
}
|
||||
|
||||
@ -1094,7 +1097,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
||||
threadId = Int64(message.messageId.id)
|
||||
}
|
||||
|
||||
let linkText = "https://t.me/\(mainUsername)?topic=\(threadId)"
|
||||
let linkText = "https://t.me/\(mainUsername)/\(threadId)"
|
||||
|
||||
items[.peerInfo]!.append(
|
||||
PeerInfoScreenLabeledValueItem(
|
||||
@ -1611,12 +1614,33 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
||||
}))
|
||||
}
|
||||
|
||||
if isCreator {
|
||||
//TODO:localize
|
||||
items[.peerDataSettings]!.append(PeerInfoScreenSwitchItem(id: ItemTopics, text: "Topics", value: channel.flags.contains(.isForum), icon: UIImage(bundleImageName: "Settings/Menu/ChatListFilters"), toggled: { value in
|
||||
interaction.toggleForumTopics(value)
|
||||
}))
|
||||
items[.peerDataSettings]!.append(PeerInfoScreenCommentItem(id: ItemTopicsText, text: "The group chat will be divided into topics created by admins or users."))
|
||||
if isCreator, let appConfiguration = data.appConfiguration {
|
||||
var minParticipants = 5
|
||||
if let data = appConfiguration.data, let value = data["forum_min_participants"] as? Int {
|
||||
minParticipants = value
|
||||
}
|
||||
|
||||
var canSetupTopics = false
|
||||
var areTopicsLocked = true
|
||||
if channel.flags.contains(.isForum) {
|
||||
canSetupTopics = true
|
||||
areTopicsLocked = false
|
||||
} else if let memberCount = cachedData.participantsSummary.memberCount {
|
||||
canSetupTopics = true
|
||||
areTopicsLocked = Int(memberCount) < minParticipants
|
||||
}
|
||||
|
||||
if canSetupTopics {
|
||||
//TODO:localize
|
||||
items[.peerDataSettings]!.append(PeerInfoScreenSwitchItem(id: ItemTopics, text: "Topics", value: channel.flags.contains(.isForum), icon: UIImage(bundleImageName: "Settings/Menu/ChatListFilters"), isLocked: areTopicsLocked, toggled: { value in
|
||||
if areTopicsLocked {
|
||||
interaction.displayTopicsLimited(minParticipants)
|
||||
} else {
|
||||
interaction.toggleForumTopics(value)
|
||||
}
|
||||
}))
|
||||
items[.peerDataSettings]!.append(PeerInfoScreenCommentItem(id: ItemTopicsText, text: "The group chat will be divided into topics created by admins or users."))
|
||||
}
|
||||
}
|
||||
|
||||
var canViewAdminsAndBanned = false
|
||||
@ -2050,6 +2074,16 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
return
|
||||
}
|
||||
let _ = strongSelf.context.engine.peers.setChannelForumMode(id: strongSelf.peerId, isForum: value).start()
|
||||
},
|
||||
displayTopicsLimited: { [weak self] minCount in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
//TODO:localize
|
||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
let text = "Only groups with more than **\(minCount) members** can have topics enabled."
|
||||
self.controller?.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_mute_for", scale: 0.066, colors: [:], title: nil, text: text, customUndoText: nil), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
|
||||
}
|
||||
)
|
||||
|
||||
@ -6810,7 +6844,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
return
|
||||
}
|
||||
|
||||
var threadId: Int64 = 0
|
||||
var threadId: Int64?
|
||||
if case let .replyThread(message) = self.chatLocation {
|
||||
threadId = Int64(message.messageId.id)
|
||||
}
|
||||
|
@ -1159,8 +1159,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
navigateToForumChannelImpl(context: context, peerId: peerId, navigationController: navigationController)
|
||||
}
|
||||
|
||||
public func navigateToForumThread(context: AccountContext, peerId: EnginePeer.Id, threadId: Int64, messageId: EngineMessage.Id?, navigationController: NavigationController, activateInput: ChatControllerActivateInput?) -> Signal<Never, NoError> {
|
||||
return navigateToForumThreadImpl(context: context, peerId: peerId, threadId: threadId, messageId: messageId, navigationController: navigationController, activateInput: activateInput)
|
||||
public func navigateToForumThread(context: AccountContext, peerId: EnginePeer.Id, threadId: Int64, messageId: EngineMessage.Id?, navigationController: NavigationController, activateInput: ChatControllerActivateInput?, keepStack: NavigateToChatKeepStack) -> Signal<Never, NoError> {
|
||||
return navigateToForumThreadImpl(context: context, peerId: peerId, threadId: threadId, messageId: messageId, navigationController: navigationController, activateInput: activateInput, keepStack: keepStack)
|
||||
}
|
||||
|
||||
public func chatControllerForForumThread(context: AccountContext, peerId: EnginePeer.Id, threadId: Int64) -> Signal<ChatController, NoError> {
|
||||
|
@ -70,6 +70,10 @@ func handleTextLinkActionImpl(context: AccountContext, peerId: PeerId?, navigate
|
||||
controller?.present(c, in: .window(.root), with: a)
|
||||
}, messageId: replyThreadMessage.messageId, isChannelPost: replyThreadMessage.isChannelPost, atMessage: messageId, displayModalProgress: true).start()
|
||||
}
|
||||
case let .replyThread(messageId):
|
||||
if let navigationController = controller.navigationController as? NavigationController {
|
||||
let _ = context.sharedContext.navigateToForumThread(context: context, peerId: messageId.peerId, threadId: Int64(messageId.id), messageId: nil, navigationController: navigationController, activateInput: nil, keepStack: .always).start()
|
||||
}
|
||||
case let .stickerPack(name, _):
|
||||
let packReference: StickerPackReference = .name(name)
|
||||
controller.present(StickerPackScreen(context: context, mainStickerPack: packReference, stickerPacks: [packReference], parentNavigationController: controller.navigationController as? NavigationController), in: .window(.root))
|
||||
|
@ -275,7 +275,7 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? {
|
||||
return .invoice(component)
|
||||
}
|
||||
return .peer(.name(peerName), nil)
|
||||
} else if pathComponents.count == 2 || pathComponents.count == 3 {
|
||||
} else if pathComponents.count == 2 || pathComponents.count == 3 || pathComponents.count == 4 {
|
||||
if pathComponents[0] == "addstickers" {
|
||||
return .stickerPack(name: pathComponents[1], type: .stickers)
|
||||
} else if pathComponents[0] == "addemoji" {
|
||||
@ -429,6 +429,24 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? {
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
} else if pathComponents.count == 4 && pathComponents[0] == "c" {
|
||||
if let channelId = Int64(pathComponents[1]), let threadId = Int32(pathComponents[2]), let messageId = Int32(pathComponents[3]) {
|
||||
var timecode: Double?
|
||||
if let queryItems = components.queryItems {
|
||||
for queryItem in queryItems {
|
||||
if let value = queryItem.value {
|
||||
if queryItem.name == "t" {
|
||||
if let doubleValue = Double(value) {
|
||||
timecode = doubleValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return .privateMessage(messageId: MessageId(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)), namespace: Namespaces.Message.Cloud, id: messageId), threadId: threadId, timecode: timecode)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
} else if pathComponents.count == 2 && pathComponents[0] == "c" {
|
||||
if let channelId = Int64(pathComponents[1]) {
|
||||
var threadId: Int32?
|
||||
@ -475,7 +493,10 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? {
|
||||
}
|
||||
}
|
||||
}
|
||||
if let threadId = threadId {
|
||||
|
||||
if pathComponents.count >= 3, let subMessageId = Int32(pathComponents[2]) {
|
||||
return .peer(.name(peerName), .replyThread(value, subMessageId))
|
||||
} else if let threadId = threadId {
|
||||
return .peer(.name(peerName), .replyThread(threadId, value))
|
||||
} else if let commentId = commentId {
|
||||
return .peer(.name(peerName), .replyThread(value, commentId))
|
||||
@ -569,19 +590,42 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl)
|
||||
}
|
||||
}
|
||||
case let .channelMessage(id, timecode):
|
||||
return .single(.channelMessage(peer: peer, messageId: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: id), timecode: timecode))
|
||||
if let channel = peer as? TelegramChannel, channel.flags.contains(.isForum) {
|
||||
return context.engine.peers.fetchForumChannelTopic(id: channel.id, threadId: Int64(id))
|
||||
|> map { info -> ResolvedUrl? in
|
||||
if let _ = info {
|
||||
return .replyThread(messageId: MessageId(peerId: channel.id, namespace: Namespaces.Message.Cloud, id: id))
|
||||
} else {
|
||||
return .peer(peer, .chat(textInputState: nil, subject: nil, peekData: nil))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return .single(.channelMessage(peer: peer, messageId: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: id), timecode: timecode))
|
||||
}
|
||||
case let .replyThread(id, replyId):
|
||||
let replyThreadMessageId = MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: id)
|
||||
return context.engine.messages.fetchChannelReplyThreadMessage(messageId: replyThreadMessageId, atMessageId: nil)
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<ChatReplyThreadMessage?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> map { result -> ResolvedUrl? in
|
||||
guard let result = result else {
|
||||
return .channelMessage(peer: peer, messageId: replyThreadMessageId, timecode: nil)
|
||||
|
||||
if let channel = peer as? TelegramChannel, channel.flags.contains(.isForum) {
|
||||
return context.engine.peers.fetchForumChannelTopic(id: channel.id, threadId: Int64(replyThreadMessageId.id))
|
||||
|> map { info -> ResolvedUrl? in
|
||||
if let _ = info {
|
||||
return .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))
|
||||
} else {
|
||||
return .peer(peer, .chat(textInputState: nil, subject: nil, peekData: nil))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return context.engine.messages.fetchChannelReplyThreadMessage(messageId: replyThreadMessageId, atMessageId: nil)
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<ChatReplyThreadMessage?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> map { result -> ResolvedUrl? in
|
||||
guard let result = result else {
|
||||
return .channelMessage(peer: peer, messageId: replyThreadMessageId, timecode: nil)
|
||||
}
|
||||
return .replyThreadMessage(replyThreadMessage: result, messageId: MessageId(peerId: result.messageId.peerId, namespace: Namespaces.Message.Cloud, id: replyId))
|
||||
}
|
||||
return .replyThreadMessage(replyThreadMessage: result, messageId: MessageId(peerId: result.messageId.peerId, namespace: Namespaces.Message.Cloud, id: replyId))
|
||||
}
|
||||
case let .voiceChat(invite):
|
||||
return .single(.joinVoiceChat(peer.id, invite))
|
||||
@ -614,7 +658,27 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl)
|
||||
return foundPeer
|
||||
|> mapToSignal { foundPeer -> Signal<ResolvedUrl?, NoError> in
|
||||
if let foundPeer = foundPeer {
|
||||
if let threadId = threadId {
|
||||
if case let .channel(channel) = foundPeer, channel.flags.contains(.isForum) {
|
||||
if let threadId = threadId {
|
||||
return context.engine.peers.fetchForumChannelTopic(id: channel.id, threadId: Int64(threadId))
|
||||
|> map { info -> ResolvedUrl? in
|
||||
if let _ = info {
|
||||
return .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)
|
||||
} else {
|
||||
return .peer(peer?._asPeer(), .chat(textInputState: nil, subject: nil, peekData: nil))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return context.engine.peers.fetchForumChannelTopic(id: channel.id, threadId: Int64(messageId.id))
|
||||
|> map { info -> ResolvedUrl? in
|
||||
if let _ = info {
|
||||
return .replyThread(messageId: messageId)
|
||||
} else {
|
||||
return .peer(foundPeer._asPeer(), .chat(textInputState: nil, subject: nil, peekData: nil))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let threadId = threadId {
|
||||
let replyThreadMessageId = MessageId(peerId: foundPeer.id, namespace: Namespaces.Message.Cloud, id: threadId)
|
||||
return context.engine.messages.fetchChannelReplyThreadMessage(messageId: replyThreadMessageId, atMessageId: nil)
|
||||
|> map(Optional.init)
|
||||
|
Loading…
x
Reference in New Issue
Block a user