mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 09:20:08 +00:00
[WIP]
This commit is contained in:
parent
852478d851
commit
7ba86968c8
@ -471,6 +471,7 @@ public enum PeerInfoControllerMode {
|
|||||||
case nearbyPeer(distance: Int32)
|
case nearbyPeer(distance: Int32)
|
||||||
case group(PeerId)
|
case group(PeerId)
|
||||||
case reaction(MessageId)
|
case reaction(MessageId)
|
||||||
|
case forumTopic(thread: ChatReplyThreadMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ContactListActionItemInlineIconPosition {
|
public enum ContactListActionItemInlineIconPosition {
|
||||||
@ -749,7 +750,7 @@ public protocol SharedAccountContext: AnyObject {
|
|||||||
|
|
||||||
func makeRecentSessionsController(context: AccountContext, activeSessionsContext: ActiveSessionsContext) -> ViewController & RecentSessionsController
|
func makeRecentSessionsController(context: AccountContext, activeSessionsContext: ActiveSessionsContext) -> ViewController & RecentSessionsController
|
||||||
|
|
||||||
func makeChatQrCodeScreen(context: AccountContext, peer: Peer) -> ViewController
|
func makeChatQrCodeScreen(context: AccountContext, peer: Peer, threadId: Int64?) -> ViewController
|
||||||
|
|
||||||
func makePremiumIntroController(context: AccountContext, source: PremiumIntroSource) -> ViewController
|
func makePremiumIntroController(context: AccountContext, source: PremiumIntroSource) -> ViewController
|
||||||
|
|
||||||
|
|||||||
@ -1543,8 +1543,11 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
let context = strongSelf.context
|
let context = strongSelf.context
|
||||||
let controller = ForumCreateTopicScreen(context: context, peerId: peerId, mode: .create)
|
let controller = ForumCreateTopicScreen(context: context, peerId: peerId, mode: .create)
|
||||||
controller.navigationPresentation = .modal
|
controller.navigationPresentation = .modal
|
||||||
|
|
||||||
controller.completion = { title, fileId in
|
controller.completion = { title, fileId in
|
||||||
let _ = (context.engine.peers.createForumChannelTopic(id: peerId, title: title, iconFileId: fileId)
|
let availableColors: [Int32] = [0x6FB9F0, 0xFFD67E, 0xCB86DB, 0x8EEE98, 0xFF93B2, 0xFB6F5F]
|
||||||
|
|
||||||
|
let _ = (context.engine.peers.createForumChannelTopic(id: peerId, title: title, iconColor: availableColors.randomElement()!, iconFileId: fileId)
|
||||||
|> deliverOnMainQueue).start(next: { topicId in
|
|> deliverOnMainQueue).start(next: { topicId in
|
||||||
let _ = context.sharedContext.navigateToForumThread(context: context, peerId: peerId, threadId: topicId, navigationController: navigationController, activateInput: .text).start()
|
let _ = context.sharedContext.navigateToForumThread(context: context, peerId: peerId, threadId: topicId, navigationController: navigationController, activateInput: .text).start()
|
||||||
})
|
})
|
||||||
@ -2528,7 +2531,9 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
let controller = ForumCreateTopicScreen(context: context, peerId: peerId, mode: .create)
|
let controller = ForumCreateTopicScreen(context: context, peerId: peerId, mode: .create)
|
||||||
controller.navigationPresentation = .modal
|
controller.navigationPresentation = .modal
|
||||||
controller.completion = { title, fileId in
|
controller.completion = { title, fileId in
|
||||||
let _ = (context.engine.peers.createForumChannelTopic(id: peerId, title: title, iconFileId: fileId)
|
let availableColors: [Int32] = [0x6FB9F0, 0xFFD67E, 0xCB86DB, 0x8EEE98, 0xFF93B2, 0xFB6F5F]
|
||||||
|
|
||||||
|
let _ = (context.engine.peers.createForumChannelTopic(id: peerId, title: title, iconColor: availableColors.randomElement()!, iconFileId: fileId)
|
||||||
|> deliverOnMainQueue).start(next: { topicId in
|
|> deliverOnMainQueue).start(next: { topicId in
|
||||||
if let navigationController = (sourceController.navigationController as? NavigationController) {
|
if let navigationController = (sourceController.navigationController as? NavigationController) {
|
||||||
let _ = context.sharedContext.navigateToForumThread(context: context, peerId: peerId, threadId: topicId, navigationController: navigationController, activateInput: .text).start()
|
let _ = context.sharedContext.navigateToForumThread(context: context, peerId: peerId, threadId: topicId, navigationController: navigationController, activateInput: .text).start()
|
||||||
|
|||||||
@ -487,7 +487,7 @@ public class ContactsController: ViewController {
|
|||||||
let _ = (strongSelf.context.account.postbox.loadedPeerWithId(strongSelf.context.account.peerId)
|
let _ = (strongSelf.context.account.postbox.loadedPeerWithId(strongSelf.context.account.peerId)
|
||||||
|> deliverOnMainQueue).start(next: { [weak self, weak controller] peer in
|
|> deliverOnMainQueue).start(next: { [weak self, weak controller] peer in
|
||||||
if let strongSelf = self, let controller = controller {
|
if let strongSelf = self, let controller = controller {
|
||||||
controller.present(strongSelf.context.sharedContext.makeChatQrCodeScreen(context: strongSelf.context, peer: peer), in: .window(.root))
|
controller.present(strongSelf.context.sharedContext.makeChatQrCodeScreen(context: strongSelf.context, peer: peer, threadId: nil), in: .window(.root))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -89,13 +89,13 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
|
|||||||
return TelegramMediaAction(action: .giftPremium(currency: currency, amount: amount, months: months))
|
return TelegramMediaAction(action: .giftPremium(currency: currency, amount: amount, months: months))
|
||||||
case let .messageActionTopicCreate(_, title, iconColor, iconEmojiId):
|
case let .messageActionTopicCreate(_, title, iconColor, iconEmojiId):
|
||||||
return TelegramMediaAction(action: .topicCreated(title: title, iconColor: iconColor, iconFileId: iconEmojiId))
|
return TelegramMediaAction(action: .topicCreated(title: title, iconColor: iconColor, iconFileId: iconEmojiId))
|
||||||
case let .messageActionTopicEdit(_, title, iconEmojiId):
|
case let .messageActionTopicEdit(flags, title, iconEmojiId):
|
||||||
var componenents: [TelegramMediaActionType.ForumTopicEditComponent] = []
|
var componenents: [TelegramMediaActionType.ForumTopicEditComponent] = []
|
||||||
//messageActionTopicEdit#b117a9f5 flags:# title:flags.0?string icon_emoji_id:flags.1?long = MessageAction;
|
//messageActionTopicEdit#b117a9f5 flags:# title:flags.0?string icon_emoji_id:flags.1?long = MessageAction;
|
||||||
if let title {
|
if let title {
|
||||||
componenents.append(.title(title))
|
componenents.append(.title(title))
|
||||||
}
|
}
|
||||||
if let iconEmojiId {
|
if (flags & (1 << 1)) != 0 {
|
||||||
componenents.append(.iconFileId(iconEmojiId == 0 ? nil : iconEmojiId))
|
componenents.append(.iconFileId(iconEmojiId == 0 ? nil : iconEmojiId))
|
||||||
}
|
}
|
||||||
return TelegramMediaAction(action: .topicEdited(components: componenents))
|
return TelegramMediaAction(action: .topicEdited(components: componenents))
|
||||||
|
|||||||
@ -123,6 +123,55 @@ func _internal_createForumChannelTopic(account: Account, peerId: PeerId, title:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum EditForumChannelTopicError {
|
||||||
|
case generic
|
||||||
|
}
|
||||||
|
|
||||||
|
func _internal_editForumChannelTopic(account: Account, peerId: PeerId, threadId: Int64, title: String, iconFileId: Int64?) -> Signal<Never, EditForumChannelTopicError> {
|
||||||
|
return account.postbox.transaction { transaction -> Api.InputChannel? in
|
||||||
|
return transaction.getPeer(peerId).flatMap(apiInputChannel)
|
||||||
|
}
|
||||||
|
|> castError(EditForumChannelTopicError.self)
|
||||||
|
|> mapToSignal { inputChannel -> Signal<Never, EditForumChannelTopicError> in
|
||||||
|
guard let inputChannel = inputChannel else {
|
||||||
|
return .fail(.generic)
|
||||||
|
}
|
||||||
|
var flags: Int32 = 0
|
||||||
|
flags |= (1 << 0)
|
||||||
|
flags |= (1 << 1)
|
||||||
|
|
||||||
|
return account.network.request(Api.functions.channels.editForumTopic(
|
||||||
|
flags: flags,
|
||||||
|
channel: inputChannel,
|
||||||
|
topicId: Int32(clamping: threadId),
|
||||||
|
title: title,
|
||||||
|
iconEmojiId: iconFileId ?? 0
|
||||||
|
))
|
||||||
|
|> mapError { _ -> EditForumChannelTopicError in
|
||||||
|
return .generic
|
||||||
|
}
|
||||||
|
|> mapToSignal { result -> Signal<Never, EditForumChannelTopicError> in
|
||||||
|
account.stateManager.addUpdates(result)
|
||||||
|
|
||||||
|
return account.postbox.transaction { transaction -> Void in
|
||||||
|
if let initialData = transaction.getMessageHistoryThreadInfo(peerId: peerId, threadId: threadId)?.get(MessageHistoryThreadData.self) {
|
||||||
|
var data = initialData
|
||||||
|
|
||||||
|
data.info = EngineMessageHistoryThread.Info(title: title, icon: iconFileId, iconColor: data.info.iconColor)
|
||||||
|
|
||||||
|
if data != initialData {
|
||||||
|
if let entry = CodableEntry(data) {
|
||||||
|
transaction.setMessageHistoryThreadInfo(peerId: peerId, threadId: threadId, info: entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> castError(EditForumChannelTopicError.self)
|
||||||
|
|> ignoreValues
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func _internal_setChannelForumMode(account: Account, peerId: PeerId, isForum: Bool) -> Signal<Never, NoError> {
|
func _internal_setChannelForumMode(account: Account, peerId: PeerId, isForum: Bool) -> Signal<Never, NoError> {
|
||||||
return account.postbox.transaction { transaction -> Api.InputChannel? in
|
return account.postbox.transaction { transaction -> Api.InputChannel? in
|
||||||
return transaction.getPeer(peerId).flatMap(apiInputChannel)
|
return transaction.getPeer(peerId).flatMap(apiInputChannel)
|
||||||
|
|||||||
@ -7,6 +7,7 @@ public final class SparseMessageList {
|
|||||||
private let queue: Queue
|
private let queue: Queue
|
||||||
private let account: Account
|
private let account: Account
|
||||||
private let peerId: PeerId
|
private let peerId: PeerId
|
||||||
|
private let threadId: Int64?
|
||||||
private let messageTag: MessageTags
|
private let messageTag: MessageTags
|
||||||
|
|
||||||
private struct TopSection: Equatable {
|
private struct TopSection: Equatable {
|
||||||
@ -91,14 +92,16 @@ public final class SparseMessageList {
|
|||||||
|
|
||||||
let statePromise = Promise<SparseMessageList.State>()
|
let statePromise = Promise<SparseMessageList.State>()
|
||||||
|
|
||||||
init(queue: Queue, account: Account, peerId: PeerId, messageTag: MessageTags) {
|
init(queue: Queue, account: Account, peerId: PeerId, threadId: Int64?, messageTag: MessageTags) {
|
||||||
self.queue = queue
|
self.queue = queue
|
||||||
self.account = account
|
self.account = account
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
|
self.threadId = threadId
|
||||||
self.messageTag = messageTag
|
self.messageTag = messageTag
|
||||||
|
|
||||||
self.resetTopSection()
|
self.resetTopSection()
|
||||||
|
|
||||||
|
if self.threadId == nil {
|
||||||
self.sparseItemsDisposable = (self.account.postbox.transaction { transaction -> Api.InputPeer? in
|
self.sparseItemsDisposable = (self.account.postbox.transaction { transaction -> Api.InputPeer? in
|
||||||
return transaction.getPeer(peerId).flatMap(apiInputPeer)
|
return transaction.getPeer(peerId).flatMap(apiInputPeer)
|
||||||
}
|
}
|
||||||
@ -161,6 +164,7 @@ public final class SparseMessageList {
|
|||||||
strongSelf.updateState()
|
strongSelf.updateState()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
self.deletedMessagesDisposable = (account.postbox.combinedView(keys: [.deletedMessages(peerId: peerId)])
|
self.deletedMessagesDisposable = (account.postbox.combinedView(keys: [.deletedMessages(peerId: peerId)])
|
||||||
|> deliverOn(self.queue)).start(next: { [weak self] views in
|
|> deliverOn(self.queue)).start(next: { [weak self] views in
|
||||||
@ -183,12 +187,16 @@ public final class SparseMessageList {
|
|||||||
|
|
||||||
private func resetTopSection() {
|
private func resetTopSection() {
|
||||||
let count: Int
|
let count: Int
|
||||||
/*#if DEBUG
|
|
||||||
count = 20
|
|
||||||
#else*/
|
|
||||||
count = 200
|
count = 200
|
||||||
//#endif
|
|
||||||
self.topItemsDisposable.set((self.account.postbox.aroundMessageHistoryViewForLocation(.peer(peerId: peerId), anchor: .upperBound, ignoreMessagesInTimestampRange: nil, count: count, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: Set(), tagMask: self.messageTag, appendMessagesFromTheSameGroup: false, namespaces: .not(Set(Namespaces.Message.allScheduled)), orderStatistics: [])
|
let location: ChatLocationInput
|
||||||
|
if let threadId = self.threadId {
|
||||||
|
location = .thread(peerId: self.peerId, threadId: threadId, data: .single(MessageHistoryViewExternalInput(content: .thread(peerId: self.peerId, id: threadId, holes: [:]), maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil)))
|
||||||
|
} else {
|
||||||
|
location = .peer(peerId: self.peerId)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.topItemsDisposable.set((self.account.postbox.aroundMessageHistoryViewForLocation(location, anchor: .upperBound, ignoreMessagesInTimestampRange: nil, count: count, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: Set(), tagMask: self.messageTag, appendMessagesFromTheSameGroup: false, namespaces: .not(Set(Namespaces.Message.allScheduled)), orderStatistics: [])
|
||||||
|> deliverOn(self.queue)).start(next: { [weak self] view, updateType, _ in
|
|> deliverOn(self.queue)).start(next: { [weak self] view, updateType, _ in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
@ -688,11 +696,11 @@ public final class SparseMessageList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init(account: Account, peerId: PeerId, messageTag: MessageTags) {
|
init(account: Account, peerId: PeerId, threadId: Int64?, messageTag: MessageTags) {
|
||||||
self.queue = Queue()
|
self.queue = Queue()
|
||||||
let queue = self.queue
|
let queue = self.queue
|
||||||
self.impl = QueueLocalObject(queue: queue, generate: {
|
self.impl = QueueLocalObject(queue: queue, generate: {
|
||||||
return Impl(queue: queue, account: account, peerId: peerId, messageTag: messageTag)
|
return Impl(queue: queue, account: account, peerId: peerId, threadId: threadId, messageTag: messageTag)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -285,8 +285,8 @@ public extension TelegramEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func sparseMessageList(peerId: EnginePeer.Id, tag: EngineMessage.Tags) -> SparseMessageList {
|
public func sparseMessageList(peerId: EnginePeer.Id, threadId: Int64?, tag: EngineMessage.Tags) -> SparseMessageList {
|
||||||
return SparseMessageList(account: self.account, peerId: peerId, messageTag: tag)
|
return SparseMessageList(account: self.account, peerId: peerId, threadId: threadId, messageTag: tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func sparseMessageCalendar(peerId: EnginePeer.Id, tag: EngineMessage.Tags) -> SparseMessageCalendar {
|
public func sparseMessageCalendar(peerId: EnginePeer.Id, tag: EngineMessage.Tags) -> SparseMessageCalendar {
|
||||||
|
|||||||
@ -805,6 +805,10 @@ public extension TelegramEngine {
|
|||||||
public func createForumChannelTopic(id: EnginePeer.Id, title: String, iconColor: Int32, iconFileId: Int64?) -> Signal<Int64, CreateForumChannelTopicError> {
|
public func createForumChannelTopic(id: EnginePeer.Id, title: String, iconColor: Int32, iconFileId: Int64?) -> Signal<Int64, CreateForumChannelTopicError> {
|
||||||
return _internal_createForumChannelTopic(account: self.account, peerId: id, title: title, iconColor: iconColor, iconFileId: iconFileId)
|
return _internal_createForumChannelTopic(account: self.account, peerId: id, title: title, iconColor: iconColor, iconFileId: iconFileId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -225,8 +225,11 @@ public final class EmojiStatusComponent: Component {
|
|||||||
}
|
}
|
||||||
case let .topic(title, colorIndex):
|
case let .topic(title, colorIndex):
|
||||||
func generateTopicIcon(backgroundColors: [UIColor], strokeColors: [UIColor]) -> UIImage? {
|
func generateTopicIcon(backgroundColors: [UIColor], strokeColors: [UIColor]) -> UIImage? {
|
||||||
return generateImage(CGSize(width: 44.0, height: 44.0), rotatedContext: { size, context in
|
return generateImage(CGSize(width: availableSize.width, height: availableSize.height), rotatedContext: { realSize, context in
|
||||||
context.clear(CGRect(origin: .zero, size: size))
|
context.clear(CGRect(origin: .zero, size: realSize))
|
||||||
|
|
||||||
|
let size = CGSize(width: 44.0, height: 44.0)
|
||||||
|
context.scaleBy(x: realSize.width / size.width, y: realSize.height / size.height)
|
||||||
|
|
||||||
context.saveGState()
|
context.saveGState()
|
||||||
|
|
||||||
|
|||||||
@ -357,9 +357,9 @@ private final class ForumCreateTopicScreenComponent: CombinedComponent {
|
|||||||
case .create:
|
case .create:
|
||||||
self.title = ""
|
self.title = ""
|
||||||
self.fileId = 0
|
self.fileId = 0
|
||||||
case let .edit(topic):
|
case let .edit(info):
|
||||||
self.title = topic.info.title
|
self.title = info.title
|
||||||
self.fileId = topic.info.icon ?? 0
|
self.fileId = info.icon ?? 0
|
||||||
}
|
}
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
@ -670,7 +670,7 @@ private final class ForumCreateTopicScreenComponent: CombinedComponent {
|
|||||||
public class ForumCreateTopicScreen: ViewControllerComponentContainer {
|
public class ForumCreateTopicScreen: ViewControllerComponentContainer {
|
||||||
public enum Mode: Equatable {
|
public enum Mode: Equatable {
|
||||||
case create
|
case create
|
||||||
case edit(topic: ForumChannelTopics.Item)
|
case edit(topic: EngineMessageHistoryThread.Info)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var state: (String, Int64?) = ("", nil)
|
private var state: (String, Int64?) = ("", nil)
|
||||||
|
|||||||
@ -4809,14 +4809,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let threadInfo = messageAndTopic.threadInfo, let message = message {
|
if let threadInfo = messageAndTopic.threadInfo {
|
||||||
strongSelf.chatTitleView?.titleContent = .peer(peerView: peerView, customTitle: threadInfo.title, onlineMemberCount: onlineMemberCount, isScheduledMessages: false)
|
strongSelf.chatTitleView?.titleContent = .peer(peerView: peerView, customTitle: threadInfo.title, onlineMemberCount: onlineMemberCount, isScheduledMessages: false)
|
||||||
|
|
||||||
let avatarContent: EmojiStatusComponent.Content
|
let avatarContent: EmojiStatusComponent.Content
|
||||||
if let fileId = threadInfo.icon {
|
if let fileId = threadInfo.icon {
|
||||||
avatarContent = .animation(content: .customEmoji(fileId: fileId), size: CGSize(width: 32.0, height: 32.0), placeholderColor: strongSelf.presentationData.theme.list.mediaPlaceholderColor, themeColor: nil, loopMode: .count(2))
|
avatarContent = .animation(content: .customEmoji(fileId: fileId), size: CGSize(width: 32.0, height: 32.0), placeholderColor: strongSelf.presentationData.theme.list.mediaPlaceholderColor, themeColor: nil, loopMode: .count(2))
|
||||||
} else {
|
} else {
|
||||||
avatarContent = .topic(title: String(threadInfo.title.prefix(1)), colorIndex: Int(message.id.id))
|
avatarContent = .topic(title: String(threadInfo.title.prefix(1)), colorIndex: Int(threadInfo.iconColor))
|
||||||
}
|
}
|
||||||
(strongSelf.chatInfoNavigationButton?.buttonItem.customDisplayNode as? ChatAvatarNavigationNode)?.setStatus(context: strongSelf.context, content: avatarContent)
|
(strongSelf.chatInfoNavigationButton?.buttonItem.customDisplayNode as? ChatAvatarNavigationNode)?.setStatus(context: strongSelf.context, content: avatarContent)
|
||||||
} else {
|
} else {
|
||||||
@ -9979,7 +9979,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
|
|
||||||
if case let .peer(peerId) = self.chatLocation {
|
if case let .peer(peerId) = self.chatLocation {
|
||||||
let context = self.context
|
let context = self.context
|
||||||
self.keepPeerInfoScreenDataHotDisposable.set(keepPeerInfoScreenDataHot(context: context, peerId: peerId).start())
|
self.keepPeerInfoScreenDataHotDisposable.set(keepPeerInfoScreenDataHot(context: context, peerId: peerId, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder).start())
|
||||||
|
|
||||||
if peerId.namespace == Namespaces.Peer.CloudUser {
|
if peerId.namespace == Namespaces.Peer.CloudUser {
|
||||||
self.preloadAvatarDisposable.set((peerInfoProfilePhotosWithCache(context: context, peerId: peerId)
|
self.preloadAvatarDisposable.set((peerInfoProfilePhotosWithCache(context: context, peerId: peerId)
|
||||||
@ -11140,7 +11140,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
case .replyThread:
|
case .replyThread:
|
||||||
break
|
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) {
|
||||||
|
self.effectiveNavigationController?.pushViewController(infoController)
|
||||||
|
}
|
||||||
|
}
|
||||||
case .feed:
|
case .feed:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@ -564,19 +564,24 @@ final class ChatQrCodeScreen: ViewController {
|
|||||||
static let themeCrossfadeDelay: Double = 0.05
|
static let themeCrossfadeDelay: Double = 0.05
|
||||||
|
|
||||||
enum Subject {
|
enum Subject {
|
||||||
case peer(Peer)
|
case peer(peer: Peer, threadId: Int64?)
|
||||||
case messages([Message])
|
case messages([Message])
|
||||||
|
|
||||||
var fileName: String {
|
var fileName: String {
|
||||||
switch self {
|
switch self {
|
||||||
case let .peer(peer):
|
case let .peer(peer, threadId):
|
||||||
|
var result: String
|
||||||
if let addressName = peer.addressName, !addressName.isEmpty {
|
if let addressName = peer.addressName, !addressName.isEmpty {
|
||||||
return "t_me-\(peer.addressName ?? "")"
|
result = "t_me-\(peer.addressName ?? "")"
|
||||||
} else if let peer = peer as? TelegramUser {
|
} else if let peer = peer as? TelegramUser {
|
||||||
return "t_me-\(peer.phone ?? "")"
|
result = "t_me-\(peer.phone ?? "")"
|
||||||
} else {
|
} else {
|
||||||
return "t_me-\(Int32.random(in: 0 ..< Int32.max))"
|
result = "t_me-\(Int32.random(in: 0 ..< Int32.max))"
|
||||||
}
|
}
|
||||||
|
if let threadId = threadId {
|
||||||
|
result.append("-\(threadId)")
|
||||||
|
}
|
||||||
|
return result
|
||||||
case let .messages(messages):
|
case let .messages(messages):
|
||||||
if let message = messages.first, let chatPeer = message.peers[message.id.peerId] as? TelegramChannel, message.id.namespace == Namespaces.Message.Cloud, let addressName = chatPeer.addressName, !addressName.isEmpty {
|
if let message = messages.first, let chatPeer = message.peers[message.id.peerId] as? TelegramChannel, message.id.namespace == Namespaces.Message.Cloud, let addressName = chatPeer.addressName, !addressName.isEmpty {
|
||||||
return "t_me-\(addressName)-\(message.id.id)"
|
return "t_me-\(addressName)-\(message.id.id)"
|
||||||
@ -800,8 +805,8 @@ private class ChatQrCodeScreenNode: ViewControllerTracingNode, UIScrollViewDeleg
|
|||||||
self.wrappingScrollNode.view.canCancelContentTouches = true
|
self.wrappingScrollNode.view.canCancelContentTouches = true
|
||||||
|
|
||||||
switch controller.subject {
|
switch controller.subject {
|
||||||
case let .peer(peer):
|
case let .peer(peer, threadId):
|
||||||
self.contentNode = QrContentNode(context: context, peer: peer, isStatic: false)
|
self.contentNode = QrContentNode(context: context, peer: peer, threadId: threadId, isStatic: false)
|
||||||
case let .messages(messages):
|
case let .messages(messages):
|
||||||
self.contentNode = MessageContentNode(context: context, messages: messages)
|
self.contentNode = MessageContentNode(context: context, messages: messages)
|
||||||
}
|
}
|
||||||
@ -994,7 +999,7 @@ private class ChatQrCodeScreenNode: ViewControllerTracingNode, UIScrollViewDeleg
|
|||||||
let initiallySelectedEmoticon: Signal<String, NoError>
|
let initiallySelectedEmoticon: Signal<String, NoError>
|
||||||
let sharedData = self.context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationThemeSettings])
|
let sharedData = self.context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationThemeSettings])
|
||||||
|> take(1)
|
|> take(1)
|
||||||
if case let .peer(peer) = controller.subject, peer.id != self.context.account.peerId {
|
if case let .peer(peer, _) = controller.subject, peer.id != self.context.account.peerId {
|
||||||
let themeEmoticon = self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.ThemeEmoticon(id: peer.id))
|
let themeEmoticon = self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.ThemeEmoticon(id: peer.id))
|
||||||
initiallySelectedEmoticon = combineLatest(themeEmoticon, sharedData)
|
initiallySelectedEmoticon = combineLatest(themeEmoticon, sharedData)
|
||||||
|> map { themeEmoticon, sharedData -> String in
|
|> map { themeEmoticon, sharedData -> String in
|
||||||
@ -1434,6 +1439,7 @@ private protocol ContentNode: ASDisplayNode {
|
|||||||
private class QrContentNode: ASDisplayNode, ContentNode {
|
private class QrContentNode: ASDisplayNode, ContentNode {
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private let peer: Peer
|
private let peer: Peer
|
||||||
|
private let threadId: Int64?
|
||||||
private let isStatic: Bool
|
private let isStatic: Bool
|
||||||
|
|
||||||
fileprivate let containerNode: ASDisplayNode
|
fileprivate let containerNode: ASDisplayNode
|
||||||
@ -1463,9 +1469,10 @@ private class QrContentNode: ASDisplayNode, ContentNode {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
init(context: AccountContext, peer: Peer, isStatic: Bool = false) {
|
init(context: AccountContext, peer: Peer, threadId: Int64?, isStatic: Bool = false) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.peer = peer
|
self.peer = peer
|
||||||
|
self.threadId = threadId
|
||||||
self.isStatic = isStatic
|
self.isStatic = isStatic
|
||||||
|
|
||||||
self.containerNode = ASDisplayNode()
|
self.containerNode = ASDisplayNode()
|
||||||
@ -1506,12 +1513,15 @@ private class QrContentNode: ASDisplayNode, ContentNode {
|
|||||||
self.codeStaticIconNode = nil
|
self.codeStaticIconNode = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
let codeText: String
|
var codeText: String
|
||||||
if let addressName = peer.addressName, !addressName.isEmpty {
|
if let addressName = peer.addressName, !addressName.isEmpty {
|
||||||
codeText = "@\(peer.addressName ?? "")".uppercased()
|
codeText = "@\(peer.addressName ?? "")".uppercased()
|
||||||
} else {
|
} else {
|
||||||
codeText = peer.debugDisplayTitle.uppercased()
|
codeText = peer.debugDisplayTitle.uppercased()
|
||||||
}
|
}
|
||||||
|
if let threadId = self.threadId {
|
||||||
|
codeText += "/\(threadId)"
|
||||||
|
}
|
||||||
|
|
||||||
self.codeTextNode = ImmediateTextNode()
|
self.codeTextNode = ImmediateTextNode()
|
||||||
self.codeTextNode.displaysAsynchronously = false
|
self.codeTextNode.displaysAsynchronously = false
|
||||||
@ -1550,14 +1560,19 @@ private class QrContentNode: ASDisplayNode, ContentNode {
|
|||||||
self.addSubnode(codeAnimatedIconNode)
|
self.addSubnode(codeAnimatedIconNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
let codeLink: String
|
var codeLink: String
|
||||||
if let addressName = peer.addressName, !addressName.isEmpty {
|
if let addressName = peer.addressName, !addressName.isEmpty {
|
||||||
codeLink = "https://t.me/\(peer.addressName ?? "")"
|
codeLink = "https://t.me/\(peer.addressName ?? "")"
|
||||||
} else if let peer = peer as? TelegramUser {
|
} else if let peer = peer as? TelegramUser {
|
||||||
codeLink = "https://t.me/+\(peer.phone ?? "")"
|
codeLink = "https://t.me/+\(peer.phone ?? "")"
|
||||||
|
} else if let _ = peer as? TelegramChannel {
|
||||||
|
codeLink = "https://t.me/c/\(peer.id.id._internalGetInt64Value())"
|
||||||
} else {
|
} else {
|
||||||
codeLink = ""
|
codeLink = ""
|
||||||
}
|
}
|
||||||
|
if let threadId = threadId {
|
||||||
|
codeLink += "?topic=\(threadId)"
|
||||||
|
}
|
||||||
|
|
||||||
let codeReadyPromise = ValuePromise<Bool>()
|
let codeReadyPromise = ValuePromise<Bool>()
|
||||||
self.codeImageNode.setSignal(qrCode(string: codeLink, color: .black, backgroundColor: nil, icon: .cutout, ecl: "Q") |> beforeNext { [weak self] size, _ in
|
self.codeImageNode.setSignal(qrCode(string: codeLink, color: .black, backgroundColor: nil, icon: .cutout, ecl: "Q") |> beforeNext { [weak self] size, _ in
|
||||||
@ -1591,7 +1606,7 @@ private class QrContentNode: ASDisplayNode, ContentNode {
|
|||||||
let size = CGSize(width: 390.0, height: 844.0)
|
let size = CGSize(width: 390.0, height: 844.0)
|
||||||
let scale: CGFloat = 3.0
|
let scale: CGFloat = 3.0
|
||||||
|
|
||||||
let copyNode = QrContentNode(context: self.context, peer: self.peer, isStatic: true)
|
let copyNode = QrContentNode(context: self.context, peer: self.peer, threadId: self.threadId, isStatic: true)
|
||||||
|
|
||||||
func prepare(view: UIView, scale: CGFloat) {
|
func prepare(view: UIView, scale: CGFloat) {
|
||||||
view.contentScaleFactor = scale
|
view.contentScaleFactor = scale
|
||||||
|
|||||||
@ -1408,7 +1408,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
|||||||
}
|
}
|
||||||
} else if let channel = peer as? TelegramChannel, case .group = channel.info, channel.hasPermission(.canBeAnonymous) {
|
} else if let channel = peer as? TelegramChannel, case .group = channel.info, channel.hasPermission(.canBeAnonymous) {
|
||||||
placeholder = interfaceState.strings.Conversation_InputTextAnonymousPlaceholder
|
placeholder = interfaceState.strings.Conversation_InputTextAnonymousPlaceholder
|
||||||
} else if case let .replyThread(replyThreadMessage) = interfaceState.chatLocation {
|
} else if case let .replyThread(replyThreadMessage) = interfaceState.chatLocation, !replyThreadMessage.isForumPost {
|
||||||
if replyThreadMessage.isChannelPost {
|
if replyThreadMessage.isChannelPost {
|
||||||
placeholder = interfaceState.strings.Conversation_InputTextPlaceholderComment
|
placeholder = interfaceState.strings.Conversation_InputTextPlaceholderComment
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -19,6 +19,8 @@ import ChatPresentationInterfaceState
|
|||||||
final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode {
|
final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode {
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private let peerId: PeerId
|
private let peerId: PeerId
|
||||||
|
private let chatLocation: ChatLocation
|
||||||
|
private let chatLocationContextHolder: Atomic<ChatLocationContextHolder?>
|
||||||
private let chatControllerInteraction: ChatControllerInteraction
|
private let chatControllerInteraction: ChatControllerInteraction
|
||||||
|
|
||||||
weak var parentController: ViewController?
|
weak var parentController: ViewController?
|
||||||
@ -61,16 +63,18 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode {
|
|||||||
return 0.0
|
return 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, chatControllerInteraction: ChatControllerInteraction, peerId: PeerId, tagMask: MessageTags) {
|
init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, chatControllerInteraction: ChatControllerInteraction, peerId: PeerId, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, tagMask: MessageTags) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
|
self.chatLocation = chatLocation
|
||||||
|
self.chatLocationContextHolder = chatLocationContextHolder
|
||||||
|
|
||||||
self.chatControllerInteraction = chatControllerInteraction
|
self.chatControllerInteraction = chatControllerInteraction
|
||||||
|
|
||||||
self.selectedMessages = chatControllerInteraction.selectionState.flatMap { $0.selectedIds }
|
self.selectedMessages = chatControllerInteraction.selectionState.flatMap { $0.selectedIds }
|
||||||
self.selectedMessagesPromise.set(.single(self.selectedMessages))
|
self.selectedMessagesPromise.set(.single(self.selectedMessages))
|
||||||
|
|
||||||
let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
|
self.listNode = ChatHistoryListNode(context: context, updatedPresentationData: updatedPresentationData ?? (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData), chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, subject: nil, controllerInteraction: chatControllerInteraction, selectedMessages: self.selectedMessagesPromise.get(), mode: .list(search: false, reversed: false, displayHeaders: .allButLast, hintLinks: tagMask == .webPage, isGlobalSearch: false))
|
||||||
self.listNode = ChatHistoryListNode(context: context, updatedPresentationData: updatedPresentationData ?? (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData), chatLocation: .peer(id: peerId), chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, subject: nil, controllerInteraction: chatControllerInteraction, selectedMessages: self.selectedMessagesPromise.get(), mode: .list(search: false, reversed: false, displayHeaders: .allButLast, hintLinks: tagMask == .webPage, isGlobalSearch: false))
|
|
||||||
self.listNode.clipsToBounds = true
|
self.listNode.clipsToBounds = true
|
||||||
self.listNode.defaultToSynchronousTransactionWhileScrolling = true
|
self.listNode.defaultToSynchronousTransactionWhileScrolling = true
|
||||||
self.listNode.scroller.bounces = false
|
self.listNode.scroller.bounces = false
|
||||||
|
|||||||
@ -1594,6 +1594,8 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
|
|||||||
|
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private let peerId: PeerId
|
private let peerId: PeerId
|
||||||
|
private let chatLocation: ChatLocation
|
||||||
|
private let chatLocationContextHolder: Atomic<ChatLocationContextHolder?>
|
||||||
private let chatControllerInteraction: ChatControllerInteraction
|
private let chatControllerInteraction: ChatControllerInteraction
|
||||||
private(set) var contentType: ContentType
|
private(set) var contentType: ContentType
|
||||||
private var contentTypePromise: ValuePromise<ContentType>
|
private var contentTypePromise: ValuePromise<ContentType>
|
||||||
@ -1657,9 +1659,11 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
|
|||||||
private var presentationData: PresentationData
|
private var presentationData: PresentationData
|
||||||
private var presentationDataDisposable: Disposable?
|
private var presentationDataDisposable: Disposable?
|
||||||
|
|
||||||
init(context: AccountContext, chatControllerInteraction: ChatControllerInteraction, peerId: PeerId, contentType: ContentType, captureProtected: Bool) {
|
init(context: AccountContext, chatControllerInteraction: ChatControllerInteraction, peerId: PeerId, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, contentType: ContentType, captureProtected: Bool) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
|
self.chatLocation = chatLocation
|
||||||
|
self.chatLocationContextHolder = chatLocationContextHolder
|
||||||
self.chatControllerInteraction = chatControllerInteraction
|
self.chatControllerInteraction = chatControllerInteraction
|
||||||
self.contentType = contentType
|
self.contentType = contentType
|
||||||
self.contentTypePromise = ValuePromise<ContentType>(contentType)
|
self.contentTypePromise = ValuePromise<ContentType>(contentType)
|
||||||
@ -1720,13 +1724,22 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
|
|||||||
captureProtected: captureProtected
|
captureProtected: captureProtected
|
||||||
)
|
)
|
||||||
|
|
||||||
self.listSource = self.context.engine.messages.sparseMessageList(peerId: self.peerId, tag: tagMaskForType(self.contentType))
|
var threadId: Int64?
|
||||||
|
if case let .replyThread(message) = chatLocation {
|
||||||
|
threadId = Int64(message.messageId.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.listSource = self.context.engine.messages.sparseMessageList(peerId: self.peerId, threadId: threadId, tag: tagMaskForType(self.contentType))
|
||||||
|
if threadId == nil {
|
||||||
switch contentType {
|
switch contentType {
|
||||||
case .photoOrVideo, .photo, .video:
|
case .photoOrVideo, .photo, .video:
|
||||||
self.calendarSource = self.context.engine.messages.sparseMessageCalendar(peerId: self.peerId, tag: tagMaskForType(self.contentType))
|
self.calendarSource = self.context.engine.messages.sparseMessageCalendar(peerId: self.peerId, tag: tagMaskForType(self.contentType))
|
||||||
default:
|
default:
|
||||||
self.calendarSource = nil
|
self.calendarSource = nil
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
self.calendarSource = nil
|
||||||
|
}
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
@ -2173,7 +2186,12 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
|
|||||||
|
|
||||||
self.itemGrid.hideScrollingArea()
|
self.itemGrid.hideScrollingArea()
|
||||||
|
|
||||||
self.listSource = self.context.engine.messages.sparseMessageList(peerId: self.peerId, tag: tagMaskForType(self.contentType))
|
var threadId: Int64?
|
||||||
|
if case let .replyThread(message) = chatLocation {
|
||||||
|
threadId = Int64(message.messageId.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.listSource = self.context.engine.messages.sparseMessageList(peerId: self.peerId, threadId: threadId, tag: tagMaskForType(self.contentType))
|
||||||
self.isRequestingView = false
|
self.isRequestingView = false
|
||||||
self.requestHistoryAroundVisiblePosition(synchronous: true, reloadAtTop: true)
|
self.requestHistoryAroundVisiblePosition(synchronous: true, reloadAtTop: true)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -187,6 +187,7 @@ final class PeerInfoScreenData {
|
|||||||
let invitations: PeerExportedInvitationsState?
|
let invitations: PeerExportedInvitationsState?
|
||||||
let requests: PeerInvitationImportersState?
|
let requests: PeerInvitationImportersState?
|
||||||
let requestsContext: PeerInvitationImportersContext?
|
let requestsContext: PeerInvitationImportersContext?
|
||||||
|
let threadInfo: EngineMessageHistoryThread.Info?
|
||||||
|
|
||||||
init(
|
init(
|
||||||
peer: Peer?,
|
peer: Peer?,
|
||||||
@ -204,7 +205,8 @@ final class PeerInfoScreenData {
|
|||||||
globalSettings: TelegramGlobalSettings?,
|
globalSettings: TelegramGlobalSettings?,
|
||||||
invitations: PeerExportedInvitationsState?,
|
invitations: PeerExportedInvitationsState?,
|
||||||
requests: PeerInvitationImportersState?,
|
requests: PeerInvitationImportersState?,
|
||||||
requestsContext: PeerInvitationImportersContext?
|
requestsContext: PeerInvitationImportersContext?,
|
||||||
|
threadInfo: EngineMessageHistoryThread.Info?
|
||||||
) {
|
) {
|
||||||
self.peer = peer
|
self.peer = peer
|
||||||
self.chatPeer = chatPeer
|
self.chatPeer = chatPeer
|
||||||
@ -222,6 +224,7 @@ final class PeerInfoScreenData {
|
|||||||
self.invitations = invitations
|
self.invitations = invitations
|
||||||
self.requests = requests
|
self.requests = requests
|
||||||
self.requestsContext = requestsContext
|
self.requestsContext = requestsContext
|
||||||
|
self.threadInfo = threadInfo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,7 +243,7 @@ private enum PeerInfoScreenInputData: Equatable {
|
|||||||
case group(groupId: PeerId)
|
case group(groupId: PeerId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func peerInfoAvailableMediaPanes(context: AccountContext, peerId: PeerId) -> Signal<[PeerInfoPaneKey]?, NoError> {
|
private func peerInfoAvailableMediaPanes(context: AccountContext, peerId: PeerId, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>) -> Signal<[PeerInfoPaneKey]?, NoError> {
|
||||||
let tags: [(MessageTags, PeerInfoPaneKey)] = [
|
let tags: [(MessageTags, PeerInfoPaneKey)] = [
|
||||||
(.photoOrVideo, .media),
|
(.photoOrVideo, .media),
|
||||||
(.file, .files),
|
(.file, .files),
|
||||||
@ -257,7 +260,8 @@ private func peerInfoAvailableMediaPanes(context: AccountContext, peerId: PeerId
|
|||||||
let loadedOnce = Atomic<Bool>(value: false)
|
let loadedOnce = Atomic<Bool>(value: false)
|
||||||
return combineLatest(queue: .mainQueue(), tags.map { tagAndKey -> Signal<(PeerInfoPaneKey, PaneState), NoError> in
|
return combineLatest(queue: .mainQueue(), tags.map { tagAndKey -> Signal<(PeerInfoPaneKey, PaneState), NoError> in
|
||||||
let (tag, key) = tagAndKey
|
let (tag, key) = tagAndKey
|
||||||
return context.account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peerId), index: .upperBound, anchorIndex: .upperBound, count: 20, clipHoles: false, fixedCombinedReadStates: nil, tagMask: tag)
|
let location = context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder)
|
||||||
|
return context.account.viewTracker.aroundMessageHistoryViewForLocation(location, index: .upperBound, anchorIndex: .upperBound, count: 20, clipHoles: false, fixedCombinedReadStates: nil, tagMask: tag)
|
||||||
|> map { (view, _, _) -> (PeerInfoPaneKey, PaneState) in
|
|> map { (view, _, _) -> (PeerInfoPaneKey, PaneState) in
|
||||||
if view.entries.isEmpty {
|
if view.entries.isEmpty {
|
||||||
if view.isLoading {
|
if view.isLoading {
|
||||||
@ -353,7 +357,7 @@ private func peerInfoScreenInputData(context: AccountContext, peerId: EnginePeer
|
|||||||
|> distinctUntilChanged
|
|> distinctUntilChanged
|
||||||
}
|
}
|
||||||
|
|
||||||
func keepPeerInfoScreenDataHot(context: AccountContext, peerId: PeerId) -> Signal<Never, NoError> {
|
func keepPeerInfoScreenDataHot(context: AccountContext, peerId: PeerId, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>) -> Signal<Never, NoError> {
|
||||||
return peerInfoScreenInputData(context: context, peerId: peerId, isSettings: false)
|
return peerInfoScreenInputData(context: context, peerId: peerId, isSettings: false)
|
||||||
|> mapToSignal { inputData -> Signal<Never, NoError> in
|
|> mapToSignal { inputData -> Signal<Never, NoError> in
|
||||||
switch inputData {
|
switch inputData {
|
||||||
@ -361,7 +365,7 @@ func keepPeerInfoScreenDataHot(context: AccountContext, peerId: PeerId) -> Signa
|
|||||||
return .complete()
|
return .complete()
|
||||||
case .user, .channel, .group:
|
case .user, .channel, .group:
|
||||||
return combineLatest(
|
return combineLatest(
|
||||||
context.peerChannelMemberCategoriesContextsManager.profileData(postbox: context.account.postbox, network: context.account.network, peerId: peerId, customData: peerInfoAvailableMediaPanes(context: context, peerId: peerId) |> ignoreValues),
|
context.peerChannelMemberCategoriesContextsManager.profileData(postbox: context.account.postbox, network: context.account.network, peerId: peerId, customData: peerInfoAvailableMediaPanes(context: context, peerId: peerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder) |> ignoreValues),
|
||||||
context.peerChannelMemberCategoriesContextsManager.profilePhotos(postbox: context.account.postbox, network: context.account.network, peerId: peerId, fetch: peerInfoProfilePhotos(context: context, peerId: peerId)) |> ignoreValues
|
context.peerChannelMemberCategoriesContextsManager.profilePhotos(postbox: context.account.postbox, network: context.account.network, peerId: peerId, fetch: peerInfoProfilePhotos(context: context, peerId: peerId)) |> ignoreValues
|
||||||
)
|
)
|
||||||
|> ignoreValues
|
|> ignoreValues
|
||||||
@ -472,12 +476,13 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
|||||||
globalSettings: globalSettings,
|
globalSettings: globalSettings,
|
||||||
invitations: nil,
|
invitations: nil,
|
||||||
requests: nil,
|
requests: nil,
|
||||||
requestsContext: nil
|
requestsContext: nil,
|
||||||
|
threadInfo: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, isSettings: Bool, hintGroupInCommon: PeerId?, existingRequestsContext: PeerInvitationImportersContext?) -> Signal<PeerInfoScreenData, NoError> {
|
func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, isSettings: Bool, hintGroupInCommon: PeerId?, existingRequestsContext: PeerInvitationImportersContext?, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>) -> Signal<PeerInfoScreenData, NoError> {
|
||||||
return peerInfoScreenInputData(context: context, peerId: peerId, isSettings: isSettings)
|
return peerInfoScreenInputData(context: context, peerId: peerId, isSettings: isSettings)
|
||||||
|> mapToSignal { inputData -> Signal<PeerInfoScreenData, NoError> in
|
|> mapToSignal { inputData -> Signal<PeerInfoScreenData, NoError> in
|
||||||
switch inputData {
|
switch inputData {
|
||||||
@ -498,7 +503,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
globalSettings: nil,
|
globalSettings: nil,
|
||||||
invitations: nil,
|
invitations: nil,
|
||||||
requests: nil,
|
requests: nil,
|
||||||
requestsContext: nil
|
requestsContext: nil,
|
||||||
|
threadInfo: nil
|
||||||
))
|
))
|
||||||
case let .user(userPeerId, secretChatId, kind):
|
case let .user(userPeerId, secretChatId, kind):
|
||||||
let groupsInCommon: GroupsInCommonContext?
|
let groupsInCommon: GroupsInCommonContext?
|
||||||
@ -599,7 +605,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
|
|
||||||
return combineLatest(
|
return combineLatest(
|
||||||
context.account.viewTracker.peerView(peerId, updateData: true),
|
context.account.viewTracker.peerView(peerId, updateData: true),
|
||||||
peerInfoAvailableMediaPanes(context: context, peerId: peerId),
|
peerInfoAvailableMediaPanes(context: context, peerId: peerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder),
|
||||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.NotificationSettings.Global()),
|
context.engine.data.subscribe(TelegramEngine.EngineData.Item.NotificationSettings.Global()),
|
||||||
secretChatKeyFingerprint,
|
secretChatKeyFingerprint,
|
||||||
status
|
status
|
||||||
@ -628,7 +634,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
globalSettings: nil,
|
globalSettings: nil,
|
||||||
invitations: nil,
|
invitations: nil,
|
||||||
requests: nil,
|
requests: nil,
|
||||||
requestsContext: nil
|
requestsContext: nil,
|
||||||
|
threadInfo: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
case .channel:
|
case .channel:
|
||||||
@ -653,7 +660,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
|
|
||||||
return combineLatest(
|
return combineLatest(
|
||||||
context.account.viewTracker.peerView(peerId, updateData: true),
|
context.account.viewTracker.peerView(peerId, updateData: true),
|
||||||
peerInfoAvailableMediaPanes(context: context, peerId: peerId),
|
peerInfoAvailableMediaPanes(context: context, peerId: peerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder),
|
||||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.NotificationSettings.Global()),
|
context.engine.data.subscribe(TelegramEngine.EngineData.Item.NotificationSettings.Global()),
|
||||||
status,
|
status,
|
||||||
invitationsContextPromise.get(),
|
invitationsContextPromise.get(),
|
||||||
@ -703,7 +710,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
globalSettings: nil,
|
globalSettings: nil,
|
||||||
invitations: invitations,
|
invitations: invitations,
|
||||||
requests: requests,
|
requests: requests,
|
||||||
requestsContext: currentRequestsContext
|
requestsContext: currentRequestsContext,
|
||||||
|
threadInfo: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
case let .group(groupId):
|
case let .group(groupId):
|
||||||
@ -785,9 +793,10 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
}
|
}
|
||||||
|> distinctUntilChanged
|
|> distinctUntilChanged
|
||||||
|
|
||||||
|
let membersData: Signal<PeerInfoMembersData?, NoError>
|
||||||
|
if case .peer = chatLocation {
|
||||||
let membersContext = PeerInfoMembersContext(context: context, peerId: groupId)
|
let membersContext = PeerInfoMembersContext(context: context, peerId: groupId)
|
||||||
|
membersData = combineLatest(membersContext.state, context.account.viewTracker.peerView(groupId, updateData: false))
|
||||||
let membersData: Signal<PeerInfoMembersData?, NoError> = combineLatest(membersContext.state, context.account.viewTracker.peerView(groupId, updateData: false))
|
|
||||||
|> map { state, view -> PeerInfoMembersData? in
|
|> map { state, view -> PeerInfoMembersData? in
|
||||||
if state.members.count > 5 {
|
if state.members.count > 5 {
|
||||||
return .longList(membersContext)
|
return .longList(membersContext)
|
||||||
@ -796,6 +805,9 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> distinctUntilChanged
|
|> distinctUntilChanged
|
||||||
|
} else {
|
||||||
|
membersData = .single(nil)
|
||||||
|
}
|
||||||
|
|
||||||
let invitationsContextPromise = Promise<PeerExportedInvitationsContext?>(nil)
|
let invitationsContextPromise = Promise<PeerExportedInvitationsContext?>(nil)
|
||||||
let invitationsStatePromise = Promise<PeerExportedInvitationsState?>(nil)
|
let invitationsStatePromise = Promise<PeerExportedInvitationsState?>(nil)
|
||||||
@ -803,27 +815,40 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
let requestsContextPromise = Promise<PeerInvitationImportersContext?>(nil)
|
let requestsContextPromise = Promise<PeerInvitationImportersContext?>(nil)
|
||||||
let requestsStatePromise = Promise<PeerInvitationImportersState?>(nil)
|
let requestsStatePromise = Promise<PeerInvitationImportersState?>(nil)
|
||||||
|
|
||||||
|
let threadInfo: Signal<EngineMessageHistoryThread.Info?, NoError>
|
||||||
|
if case let .replyThread(message) = chatLocation {
|
||||||
|
let threadId = Int64(message.messageId.id)
|
||||||
|
let viewKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: peerId, threadId: threadId)
|
||||||
|
threadInfo = context.account.postbox.combinedView(keys: [viewKey])
|
||||||
|
|> map { views -> EngineMessageHistoryThread.Info? in
|
||||||
|
guard let view = views.views[viewKey] as? MessageHistoryThreadInfoView else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return view.info?.get(MessageHistoryThreadData.self)?.info
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
threadInfo = .single(nil)
|
||||||
|
}
|
||||||
|
|
||||||
return combineLatest(queue: .mainQueue(),
|
return combineLatest(queue: .mainQueue(),
|
||||||
context.account.viewTracker.peerView(groupId, updateData: true),
|
context.account.viewTracker.peerView(groupId, updateData: true),
|
||||||
peerInfoAvailableMediaPanes(context: context, peerId: groupId),
|
peerInfoAvailableMediaPanes(context: context, peerId: groupId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder),
|
||||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.NotificationSettings.Global()),
|
context.engine.data.subscribe(TelegramEngine.EngineData.Item.NotificationSettings.Global()),
|
||||||
status,
|
status,
|
||||||
membersData,
|
membersData,
|
||||||
invitationsContextPromise.get(),
|
invitationsContextPromise.get(),
|
||||||
invitationsStatePromise.get(),
|
invitationsStatePromise.get(),
|
||||||
requestsContextPromise.get(),
|
requestsContextPromise.get(),
|
||||||
requestsStatePromise.get()
|
requestsStatePromise.get(),
|
||||||
|
threadInfo
|
||||||
)
|
)
|
||||||
|> map { peerView, availablePanes, globalNotificationSettings, status, membersData, currentInvitationsContext, invitations, currentRequestsContext, requests -> PeerInfoScreenData in
|
|> map { peerView, availablePanes, globalNotificationSettings, status, membersData, currentInvitationsContext, invitations, currentRequestsContext, requests, threadInfo -> PeerInfoScreenData in
|
||||||
var discussionPeer: Peer?
|
var discussionPeer: Peer?
|
||||||
if case let .known(maybeLinkedDiscussionPeerId) = (peerView.cachedData as? CachedChannelData)?.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId, let peer = peerView.peers[linkedDiscussionPeerId] {
|
if case let .known(maybeLinkedDiscussionPeerId) = (peerView.cachedData as? CachedChannelData)?.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId, let peer = peerView.peers[linkedDiscussionPeerId] {
|
||||||
discussionPeer = peer
|
discussionPeer = peer
|
||||||
}
|
}
|
||||||
|
|
||||||
var availablePanes = availablePanes
|
var availablePanes = availablePanes
|
||||||
if let channel = peerView.peers[peerView.peerId] as? TelegramChannel, channel.flags.contains(.isForum) {
|
|
||||||
availablePanes?.removeAll()
|
|
||||||
}
|
|
||||||
if let membersData = membersData, case .longList = membersData {
|
if let membersData = membersData, case .longList = membersData {
|
||||||
if availablePanes != nil {
|
if availablePanes != nil {
|
||||||
availablePanes?.insert(.members, at: 0)
|
availablePanes?.insert(.members, at: 0)
|
||||||
@ -874,7 +899,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
|||||||
globalSettings: nil,
|
globalSettings: nil,
|
||||||
invitations: invitations,
|
invitations: invitations,
|
||||||
requests: requests,
|
requests: requests,
|
||||||
requestsContext: currentRequestsContext
|
requestsContext: currentRequestsContext,
|
||||||
|
threadInfo: threadInfo
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1013,7 +1039,7 @@ func peerInfoHeaderButtonIsHiddenWhileExpanded(buttonKey: PeerInfoHeaderButtonKe
|
|||||||
return hiddenWhileExpanded
|
return hiddenWhileExpanded
|
||||||
}
|
}
|
||||||
|
|
||||||
func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?, isOpenedFromChat: Bool, isExpanded: Bool, videoCallsEnabled: Bool, isSecretChat: Bool, isContact: Bool) -> [PeerInfoHeaderButtonKey] {
|
func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?, isOpenedFromChat: Bool, isExpanded: Bool, videoCallsEnabled: Bool, isSecretChat: Bool, isContact: Bool, threadInfo: EngineMessageHistoryThread.Info?) -> [PeerInfoHeaderButtonKey] {
|
||||||
var result: [PeerInfoHeaderButtonKey] = []
|
var result: [PeerInfoHeaderButtonKey] = []
|
||||||
if let user = peer as? TelegramUser {
|
if let user = peer as? TelegramUser {
|
||||||
if !isOpenedFromChat {
|
if !isOpenedFromChat {
|
||||||
@ -1050,6 +1076,10 @@ func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?, isOpenedFro
|
|||||||
result.append(.more)
|
result.append(.more)
|
||||||
}
|
}
|
||||||
} else if let channel = peer as? TelegramChannel {
|
} else if let channel = peer as? TelegramChannel {
|
||||||
|
if let _ = threadInfo {
|
||||||
|
result.append(.mute)
|
||||||
|
result.append(.search)
|
||||||
|
} else {
|
||||||
let hasVoiceChat = channel.flags.contains(.hasVoiceChat)
|
let hasVoiceChat = channel.flags.contains(.hasVoiceChat)
|
||||||
let canStartVoiceChat = !hasVoiceChat && (channel.flags.contains(.isCreator) || channel.hasPermission(.manageCalls))
|
let canStartVoiceChat = !hasVoiceChat && (channel.flags.contains(.isCreator) || channel.hasPermission(.manageCalls))
|
||||||
let canManage = channel.flags.contains(.isCreator) || channel.adminRights != nil
|
let canManage = channel.flags.contains(.isCreator) || channel.adminRights != nil
|
||||||
@ -1115,6 +1145,7 @@ func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?, isOpenedFro
|
|||||||
result.append(.more)
|
result.append(.more)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if let group = peer as? TelegramGroup {
|
} else if let group = peer as? TelegramGroup {
|
||||||
let hasVoiceChat = group.flags.contains(.hasVoiceChat)
|
let hasVoiceChat = group.flags.contains(.hasVoiceChat)
|
||||||
let canStartVoiceChat: Bool
|
let canStartVoiceChat: Bool
|
||||||
|
|||||||
@ -308,6 +308,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
|||||||
|
|
||||||
let avatarNode: AvatarNode
|
let avatarNode: AvatarNode
|
||||||
fileprivate var videoNode: UniversalVideoNode?
|
fileprivate var videoNode: UniversalVideoNode?
|
||||||
|
fileprivate var iconView: ComponentView<Empty>?
|
||||||
private var videoContent: NativeVideoContent?
|
private var videoContent: NativeVideoContent?
|
||||||
private var videoStartTimestamp: Double?
|
private var videoStartTimestamp: Double?
|
||||||
|
|
||||||
@ -380,7 +381,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var removedPhotoResourceIds = Set<String>()
|
var removedPhotoResourceIds = Set<String>()
|
||||||
func update(peer: Peer?, item: PeerInfoAvatarListItem?, theme: PresentationTheme, avatarSize: CGFloat, isExpanded: Bool, isSettings: Bool) {
|
func update(peer: Peer?, threadInfo: EngineMessageHistoryThread.Info?, item: PeerInfoAvatarListItem?, theme: PresentationTheme, avatarSize: CGFloat, isExpanded: Bool, isSettings: Bool) {
|
||||||
if let peer = peer {
|
if let peer = peer {
|
||||||
let previousItem = self.item
|
let previousItem = self.item
|
||||||
var item = item
|
var item = item
|
||||||
@ -410,6 +411,43 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
|||||||
|
|
||||||
self.avatarNode.setPeer(context: self.context, theme: theme, peer: EnginePeer(peer), overrideImage: overrideImage, clipStyle: .none, synchronousLoad: self.isFirstAvatarLoading, displayDimensions: CGSize(width: avatarSize, height: avatarSize), storeUnrounded: true)
|
self.avatarNode.setPeer(context: self.context, theme: theme, peer: EnginePeer(peer), overrideImage: overrideImage, clipStyle: .none, synchronousLoad: self.isFirstAvatarLoading, displayDimensions: CGSize(width: avatarSize, height: avatarSize), storeUnrounded: true)
|
||||||
|
|
||||||
|
if let threadInfo = threadInfo {
|
||||||
|
self.avatarNode.isHidden = true
|
||||||
|
|
||||||
|
let iconView: ComponentView<Empty>
|
||||||
|
if let current = self.iconView {
|
||||||
|
iconView = current
|
||||||
|
} else {
|
||||||
|
iconView = ComponentView()
|
||||||
|
self.iconView = iconView
|
||||||
|
}
|
||||||
|
let content: EmojiStatusComponent.Content
|
||||||
|
if let iconFileId = threadInfo.icon {
|
||||||
|
content = .animation(content: .customEmoji(fileId: iconFileId), size: CGSize(width: avatarSize, height: avatarSize), placeholderColor: theme.list.mediaPlaceholderColor, themeColor: nil, loopMode: .forever)
|
||||||
|
} else {
|
||||||
|
content = .topic(title: String(threadInfo.title.prefix(1)), colorIndex: Int(threadInfo.iconColor))
|
||||||
|
}
|
||||||
|
let _ = iconView.update(
|
||||||
|
transition: .immediate,
|
||||||
|
component: AnyComponent(EmojiStatusComponent(
|
||||||
|
context: self.context,
|
||||||
|
animationCache: self.context.animationCache,
|
||||||
|
animationRenderer: self.context.animationRenderer,
|
||||||
|
content: content,
|
||||||
|
isVisibleForAnimations: true,
|
||||||
|
action: nil
|
||||||
|
)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: CGSize(width: avatarSize, height: avatarSize)
|
||||||
|
)
|
||||||
|
if let iconComponentView = iconView.view {
|
||||||
|
if iconComponentView.superview == nil {
|
||||||
|
self.avatarNode.view.superview?.addSubview(iconComponentView)
|
||||||
|
}
|
||||||
|
iconComponentView.frame = CGRect(origin: CGPoint(), size: CGSize(width: avatarSize, height: avatarSize))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let avatarCornerRadius: CGFloat
|
let avatarCornerRadius: CGFloat
|
||||||
if let channel = peer as? TelegramChannel, channel.flags.contains(.isForum) {
|
if let channel = peer as? TelegramChannel, channel.flags.contains(.isForum) {
|
||||||
avatarCornerRadius = floor(avatarSize * 0.25)
|
avatarCornerRadius = floor(avatarSize * 0.25)
|
||||||
@ -825,7 +863,7 @@ final class PeerInfoAvatarListNode: ASDisplayNode {
|
|||||||
|
|
||||||
let isReady = Promise<Bool>()
|
let isReady = Promise<Bool>()
|
||||||
|
|
||||||
var arguments: (Peer?, PresentationTheme, CGFloat, Bool)?
|
var arguments: (Peer?, EngineMessageHistoryThread.Info?, PresentationTheme, CGFloat, Bool)?
|
||||||
var item: PeerInfoAvatarListItem?
|
var item: PeerInfoAvatarListItem?
|
||||||
|
|
||||||
var itemsUpdated: (([PeerInfoAvatarListItem]) -> Void)?
|
var itemsUpdated: (([PeerInfoAvatarListItem]) -> Void)?
|
||||||
@ -884,14 +922,14 @@ final class PeerInfoAvatarListNode: ASDisplayNode {
|
|||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.item = items.first
|
strongSelf.item = items.first
|
||||||
strongSelf.itemsUpdated?(items)
|
strongSelf.itemsUpdated?(items)
|
||||||
if let (peer, theme, avatarSize, isExpanded) = strongSelf.arguments {
|
if let (peer, threadInfo, theme, avatarSize, isExpanded) = strongSelf.arguments {
|
||||||
strongSelf.avatarContainerNode.update(peer: peer, item: strongSelf.item, theme: theme, avatarSize: avatarSize, isExpanded: isExpanded, isSettings: strongSelf.isSettings)
|
strongSelf.avatarContainerNode.update(peer: peer, threadInfo: threadInfo, item: strongSelf.item, theme: theme, avatarSize: avatarSize, isExpanded: isExpanded, isSettings: strongSelf.isSettings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.pinchSourceNode.activate = { [weak self] sourceNode in
|
self.pinchSourceNode.activate = { [weak self] sourceNode in
|
||||||
guard let strongSelf = self, let (_, _, _, isExpanded) = strongSelf.arguments, isExpanded else {
|
guard let strongSelf = self, let (_, _, _, _, isExpanded) = strongSelf.arguments, isExpanded else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let pinchController = PinchController(sourceNode: sourceNode, getContentAreaInScreenSpace: {
|
let pinchController = PinchController(sourceNode: sourceNode, getContentAreaInScreenSpace: {
|
||||||
@ -910,11 +948,11 @@ final class PeerInfoAvatarListNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(size: CGSize, avatarSize: CGFloat, isExpanded: Bool, peer: Peer?, theme: PresentationTheme, transition: ContainedViewLayoutTransition) {
|
func update(size: CGSize, avatarSize: CGFloat, isExpanded: Bool, peer: Peer?, threadInfo: EngineMessageHistoryThread.Info?, theme: PresentationTheme, transition: ContainedViewLayoutTransition) {
|
||||||
self.arguments = (peer, theme, avatarSize, isExpanded)
|
self.arguments = (peer, threadInfo, theme, avatarSize, isExpanded)
|
||||||
self.pinchSourceNode.update(size: size, transition: transition)
|
self.pinchSourceNode.update(size: size, transition: transition)
|
||||||
self.pinchSourceNode.frame = CGRect(origin: CGPoint(), size: size)
|
self.pinchSourceNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||||
self.avatarContainerNode.update(peer: peer, item: self.item, theme: theme, avatarSize: avatarSize, isExpanded: isExpanded, isSettings: self.isSettings)
|
self.avatarContainerNode.update(peer: peer, threadInfo: threadInfo, item: self.item, theme: theme, avatarSize: avatarSize, isExpanded: isExpanded, isSettings: self.isSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
@ -1996,6 +2034,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
private let isOpenedFromChat: Bool
|
private let isOpenedFromChat: Bool
|
||||||
private let isSettings: Bool
|
private let isSettings: Bool
|
||||||
private let videoCallsEnabled: Bool
|
private let videoCallsEnabled: Bool
|
||||||
|
private let forumTopicThreadId: Int64?
|
||||||
|
|
||||||
private(set) var isAvatarExpanded: Bool
|
private(set) var isAvatarExpanded: Bool
|
||||||
var skipCollapseCompletion = false
|
var skipCollapseCompletion = false
|
||||||
@ -2056,12 +2095,13 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
var emojiStatusPackDisposable = MetaDisposable()
|
var emojiStatusPackDisposable = MetaDisposable()
|
||||||
var emojiStatusFileAndPackTitle = Promise<(TelegramMediaFile, LoadedStickerPack)?>()
|
var emojiStatusFileAndPackTitle = Promise<(TelegramMediaFile, LoadedStickerPack)?>()
|
||||||
|
|
||||||
init(context: AccountContext, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, isMediaOnly: Bool, isSettings: Bool) {
|
init(context: AccountContext, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, isMediaOnly: Bool, isSettings: Bool, forumTopicThreadId: Int64?) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.isAvatarExpanded = avatarInitiallyExpanded
|
self.isAvatarExpanded = avatarInitiallyExpanded
|
||||||
self.isOpenedFromChat = isOpenedFromChat
|
self.isOpenedFromChat = isOpenedFromChat
|
||||||
self.isSettings = isSettings
|
self.isSettings = isSettings
|
||||||
self.videoCallsEnabled = true
|
self.videoCallsEnabled = true
|
||||||
|
self.forumTopicThreadId = forumTopicThreadId
|
||||||
|
|
||||||
self.avatarListNode = PeerInfoAvatarListNode(context: context, readyWhenGalleryLoads: avatarInitiallyExpanded, isSettings: isSettings)
|
self.avatarListNode = PeerInfoAvatarListNode(context: context, readyWhenGalleryLoads: avatarInitiallyExpanded, isSettings: isSettings)
|
||||||
|
|
||||||
@ -2304,7 +2344,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
private var currentCredibilityIcon: CredibilityIcon?
|
private var currentCredibilityIcon: CredibilityIcon?
|
||||||
|
|
||||||
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?, notificationSettings: TelegramPeerNotificationSettings?, statusData: PeerInfoStatusData?, panelStatusData: (PeerInfoStatusData?, PeerInfoStatusData?, CGFloat?), isSecretChat: Bool, isContact: Bool, isSettings: Bool, state: PeerInfoState, metrics: LayoutMetrics, transition: ContainedViewLayoutTransition, additive: 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?, threadInfo: EngineMessageHistoryThread.Info?, notificationSettings: TelegramPeerNotificationSettings?, statusData: PeerInfoStatusData?, panelStatusData: (PeerInfoStatusData?, PeerInfoStatusData?, CGFloat?), isSecretChat: Bool, isContact: Bool, isSettings: Bool, state: PeerInfoState, metrics: LayoutMetrics, transition: ContainedViewLayoutTransition, additive: Bool) -> CGFloat {
|
||||||
self.state = state
|
self.state = state
|
||||||
self.peer = peer
|
self.peer = peer
|
||||||
self.avatarListNode.listContainerNode.peer = peer
|
self.avatarListNode.listContainerNode.peer = peer
|
||||||
@ -2527,7 +2567,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
let expandedAvatarListHeight = min(width, containerHeight - expandedAvatarControlsHeight)
|
let expandedAvatarListHeight = min(width, containerHeight - expandedAvatarControlsHeight)
|
||||||
let expandedAvatarListSize = CGSize(width: width, height: expandedAvatarListHeight)
|
let expandedAvatarListSize = CGSize(width: width, height: expandedAvatarListHeight)
|
||||||
|
|
||||||
let buttonKeys: [PeerInfoHeaderButtonKey] = self.isSettings ? [] : peerInfoHeaderButtons(peer: peer, cachedData: cachedData, isOpenedFromChat: self.isOpenedFromChat, isExpanded: true, videoCallsEnabled: width > 320.0 && self.videoCallsEnabled, isSecretChat: isSecretChat, isContact: isContact)
|
let buttonKeys: [PeerInfoHeaderButtonKey] = self.isSettings ? [] : peerInfoHeaderButtons(peer: peer, cachedData: cachedData, isOpenedFromChat: self.isOpenedFromChat, isExpanded: true, videoCallsEnabled: width > 320.0 && self.videoCallsEnabled, isSecretChat: isSecretChat, isContact: isContact, threadInfo: threadInfo)
|
||||||
|
|
||||||
var isPremium = false
|
var isPremium = false
|
||||||
var isVerified = false
|
var isVerified = false
|
||||||
@ -2551,6 +2591,8 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
title = presentationData.strings.Conversation_SavedMessages
|
title = presentationData.strings.Conversation_SavedMessages
|
||||||
} else if peer.id == self.context.account.peerId && !self.isSettings {
|
} else if peer.id == self.context.account.peerId && !self.isSettings {
|
||||||
title = presentationData.strings.DialogList_Replies
|
title = presentationData.strings.DialogList_Replies
|
||||||
|
} else if let threadInfo = threadInfo {
|
||||||
|
title = threadInfo.title
|
||||||
} else {
|
} else {
|
||||||
title = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
title = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
||||||
}
|
}
|
||||||
@ -2577,6 +2619,34 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
smallSubtitleString = NSAttributedString(string: subtitle, font: Font.regular(15.0), textColor: UIColor(rgb: 0xffffff, alpha: 0.7))
|
smallSubtitleString = NSAttributedString(string: subtitle, font: Font.regular(15.0), textColor: UIColor(rgb: 0xffffff, alpha: 0.7))
|
||||||
subtitleString = NSAttributedString(string: subtitle, font: Font.regular(17.0), textColor: presentationData.theme.list.itemSecondaryTextColor)
|
subtitleString = NSAttributedString(string: subtitle, font: Font.regular(17.0), textColor: presentationData.theme.list.itemSecondaryTextColor)
|
||||||
usernameString = NSAttributedString(string: "", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor)
|
usernameString = NSAttributedString(string: "", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor)
|
||||||
|
} else if let _ = threadInfo {
|
||||||
|
let subtitleColor: UIColor = presentationData.theme.list.itemSecondaryTextColor
|
||||||
|
|
||||||
|
//TODO:localize
|
||||||
|
var statusText = "in "
|
||||||
|
if let addressName = peer.addressName {
|
||||||
|
statusText += "@\(addressName)"
|
||||||
|
} else {
|
||||||
|
statusText += peer.debugDisplayTitle
|
||||||
|
}
|
||||||
|
|
||||||
|
smallSubtitleString = NSAttributedString(string: statusText, font: Font.regular(15.0), textColor: UIColor(rgb: 0xffffff, alpha: 0.7))
|
||||||
|
subtitleString = NSAttributedString(string: statusText, font: Font.regular(17.0), textColor: subtitleColor)
|
||||||
|
usernameString = NSAttributedString(string: "", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor)
|
||||||
|
|
||||||
|
let (maybePanelStatusData, maybeNextPanelStatusData, _) = panelStatusData
|
||||||
|
if let panelStatusData = maybePanelStatusData {
|
||||||
|
let subtitleColor: UIColor
|
||||||
|
if panelStatusData.isActivity {
|
||||||
|
subtitleColor = presentationData.theme.list.itemAccentColor
|
||||||
|
} else {
|
||||||
|
subtitleColor = presentationData.theme.list.itemSecondaryTextColor
|
||||||
|
}
|
||||||
|
panelSubtitleString = NSAttributedString(string: panelStatusData.text, font: Font.regular(17.0), textColor: subtitleColor)
|
||||||
|
}
|
||||||
|
if let nextPanelStatusData = maybeNextPanelStatusData {
|
||||||
|
nextPanelSubtitleString = NSAttributedString(string: nextPanelStatusData.text, font: Font.regular(17.0), textColor: presentationData.theme.list.itemSecondaryTextColor)
|
||||||
|
}
|
||||||
} else if let statusData = statusData {
|
} else if let statusData = statusData {
|
||||||
let subtitleColor: UIColor
|
let subtitleColor: UIColor
|
||||||
if statusData.isActivity {
|
if statusData.isActivity {
|
||||||
@ -2839,7 +2909,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
self.avatarListNode.update(size: CGSize(), avatarSize: avatarSize, isExpanded: self.isAvatarExpanded, peer: peer, theme: presentationData.theme, transition: transition)
|
self.avatarListNode.update(size: CGSize(), avatarSize: avatarSize, isExpanded: self.isAvatarExpanded, peer: peer, threadInfo: threadInfo, theme: presentationData.theme, transition: transition)
|
||||||
self.editingContentNode.avatarNode.update(peer: peer, item: self.avatarListNode.item, updatingAvatar: state.updatingAvatar, uploadProgress: state.avatarUploadProgress, theme: presentationData.theme, avatarSize: avatarSize, isEditing: state.isEditing)
|
self.editingContentNode.avatarNode.update(peer: peer, item: self.avatarListNode.item, updatingAvatar: state.updatingAvatar, uploadProgress: state.avatarUploadProgress, theme: presentationData.theme, avatarSize: avatarSize, isEditing: state.isEditing)
|
||||||
self.avatarOverlayNode.update(peer: peer, item: self.avatarListNode.item, updatingAvatar: state.updatingAvatar, uploadProgress: state.avatarUploadProgress, theme: presentationData.theme, avatarSize: avatarSize, isEditing: state.isEditing)
|
self.avatarOverlayNode.update(peer: peer, item: self.avatarListNode.item, updatingAvatar: state.updatingAvatar, uploadProgress: state.avatarUploadProgress, theme: presentationData.theme, avatarSize: avatarSize, isEditing: state.isEditing)
|
||||||
if additive {
|
if additive {
|
||||||
|
|||||||
@ -386,6 +386,8 @@ private final class PeerInfoPendingPane {
|
|||||||
openAddMemberAction: @escaping () -> Void,
|
openAddMemberAction: @escaping () -> Void,
|
||||||
requestPerformPeerMemberAction: @escaping (PeerInfoMember, PeerMembersListAction) -> Void,
|
requestPerformPeerMemberAction: @escaping (PeerInfoMember, PeerMembersListAction) -> Void,
|
||||||
peerId: PeerId,
|
peerId: PeerId,
|
||||||
|
chatLocation: ChatLocation,
|
||||||
|
chatLocationContextHolder: Atomic<ChatLocationContextHolder?>,
|
||||||
key: PeerInfoPaneKey,
|
key: PeerInfoPaneKey,
|
||||||
hasBecomeReady: @escaping (PeerInfoPaneKey) -> Void,
|
hasBecomeReady: @escaping (PeerInfoPaneKey) -> Void,
|
||||||
parentController: ViewController?,
|
parentController: ViewController?,
|
||||||
@ -396,7 +398,7 @@ private final class PeerInfoPendingPane {
|
|||||||
let paneNode: PeerInfoPaneNode
|
let paneNode: PeerInfoPaneNode
|
||||||
switch key {
|
switch key {
|
||||||
case .media:
|
case .media:
|
||||||
let visualPaneNode = PeerInfoVisualMediaPaneNode(context: context, chatControllerInteraction: chatControllerInteraction, peerId: peerId, contentType: .photoOrVideo, captureProtected: captureProtected)
|
let visualPaneNode = PeerInfoVisualMediaPaneNode(context: context, chatControllerInteraction: chatControllerInteraction, peerId: peerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, contentType: .photoOrVideo, captureProtected: captureProtected)
|
||||||
paneNode = visualPaneNode
|
paneNode = visualPaneNode
|
||||||
visualPaneNode.openCurrentDate = {
|
visualPaneNode.openCurrentDate = {
|
||||||
openMediaCalendar()
|
openMediaCalendar()
|
||||||
@ -405,21 +407,19 @@ private final class PeerInfoPendingPane {
|
|||||||
paneDidScroll()
|
paneDidScroll()
|
||||||
}
|
}
|
||||||
case .files:
|
case .files:
|
||||||
let visualPaneNode = PeerInfoVisualMediaPaneNode(context: context, chatControllerInteraction: chatControllerInteraction, peerId: peerId, contentType: .files, captureProtected: captureProtected)
|
let visualPaneNode = PeerInfoVisualMediaPaneNode(context: context, chatControllerInteraction: chatControllerInteraction, peerId: peerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, contentType: .files, captureProtected: captureProtected)
|
||||||
paneNode = visualPaneNode
|
paneNode = visualPaneNode
|
||||||
//paneNode = PeerInfoListPaneNode(context: context, updatedPresentationData: updatedPresentationData, chatControllerInteraction: chatControllerInteraction, peerId: peerId, tagMask: .file)
|
//paneNode = PeerInfoListPaneNode(context: context, updatedPresentationData: updatedPresentationData, chatControllerInteraction: chatControllerInteraction, peerId: peerId, tagMask: .file)
|
||||||
case .links:
|
case .links:
|
||||||
paneNode = PeerInfoListPaneNode(context: context, updatedPresentationData: updatedPresentationData, chatControllerInteraction: chatControllerInteraction, peerId: peerId, tagMask: .webPage)
|
paneNode = PeerInfoListPaneNode(context: context, updatedPresentationData: updatedPresentationData, chatControllerInteraction: chatControllerInteraction, peerId: peerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, tagMask: .webPage)
|
||||||
case .voice:
|
case .voice:
|
||||||
let visualPaneNode = PeerInfoVisualMediaPaneNode(context: context, chatControllerInteraction: chatControllerInteraction, peerId: peerId, contentType: .voiceAndVideoMessages, captureProtected: captureProtected)
|
let visualPaneNode = PeerInfoVisualMediaPaneNode(context: context, chatControllerInteraction: chatControllerInteraction, peerId: peerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, contentType: .voiceAndVideoMessages, captureProtected: captureProtected)
|
||||||
paneNode = visualPaneNode
|
paneNode = visualPaneNode
|
||||||
//paneNode = PeerInfoListPaneNode(context: context, updatedPresentationData: updatedPresentationData, chatControllerInteraction: chatControllerInteraction, peerId: peerId, tagMask: .voiceOrInstantVideo)
|
|
||||||
case .music:
|
case .music:
|
||||||
let visualPaneNode = PeerInfoVisualMediaPaneNode(context: context, chatControllerInteraction: chatControllerInteraction, peerId: peerId, contentType: .music, captureProtected: captureProtected)
|
let visualPaneNode = PeerInfoVisualMediaPaneNode(context: context, chatControllerInteraction: chatControllerInteraction, peerId: peerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, contentType: .music, captureProtected: captureProtected)
|
||||||
paneNode = visualPaneNode
|
paneNode = visualPaneNode
|
||||||
//paneNode = PeerInfoListPaneNode(context: context, updatedPresentationData: updatedPresentationData, chatControllerInteraction: chatControllerInteraction, peerId: peerId, tagMask: .music)
|
|
||||||
case .gifs:
|
case .gifs:
|
||||||
let visualPaneNode = PeerInfoGifPaneNode(context: context, chatControllerInteraction: chatControllerInteraction, peerId: peerId, contentType: .gifs)
|
let visualPaneNode = PeerInfoGifPaneNode(context: context, chatControllerInteraction: chatControllerInteraction, peerId: peerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, contentType: .gifs)
|
||||||
paneNode = visualPaneNode
|
paneNode = visualPaneNode
|
||||||
case .groupsInCommon:
|
case .groupsInCommon:
|
||||||
paneNode = PeerInfoGroupsInCommonPaneNode(context: context, peerId: peerId, chatControllerInteraction: chatControllerInteraction, openPeerContextAction: openPeerContextAction, groupsInCommonContext: data.groupsInCommon!)
|
paneNode = PeerInfoGroupsInCommonPaneNode(context: context, peerId: peerId, chatControllerInteraction: chatControllerInteraction, openPeerContextAction: openPeerContextAction, groupsInCommonContext: data.groupsInCommon!)
|
||||||
@ -452,6 +452,8 @@ private final class PeerInfoPendingPane {
|
|||||||
final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private let peerId: PeerId
|
private let peerId: PeerId
|
||||||
|
private let chatLocation: ChatLocation
|
||||||
|
private let chatLocationContextHolder: Atomic<ChatLocationContextHolder?>
|
||||||
private let isMediaOnly: Bool
|
private let isMediaOnly: Bool
|
||||||
|
|
||||||
weak var parentController: ViewController?
|
weak var parentController: ViewController?
|
||||||
@ -509,10 +511,12 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat
|
|||||||
private var currentAvailablePanes: [PeerInfoPaneKey]?
|
private var currentAvailablePanes: [PeerInfoPaneKey]?
|
||||||
private let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?
|
private let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?
|
||||||
|
|
||||||
init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peerId: PeerId, isMediaOnly: Bool) {
|
init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peerId: PeerId, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, isMediaOnly: Bool) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.updatedPresentationData = updatedPresentationData
|
self.updatedPresentationData = updatedPresentationData
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
|
self.chatLocation = chatLocation
|
||||||
|
self.chatLocationContextHolder = chatLocationContextHolder
|
||||||
self.isMediaOnly = isMediaOnly
|
self.isMediaOnly = isMediaOnly
|
||||||
|
|
||||||
self.additionalBackgroundNode = ASDisplayNode()
|
self.additionalBackgroundNode = ASDisplayNode()
|
||||||
@ -807,6 +811,8 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat
|
|||||||
self?.requestPerformPeerMemberAction?(member, action)
|
self?.requestPerformPeerMemberAction?(member, action)
|
||||||
},
|
},
|
||||||
peerId: self.peerId,
|
peerId: self.peerId,
|
||||||
|
chatLocation: self.chatLocation,
|
||||||
|
chatLocationContextHolder: self.chatLocationContextHolder,
|
||||||
key: key,
|
key: key,
|
||||||
hasBecomeReady: { [weak self] key in
|
hasBecomeReady: { [weak self] key in
|
||||||
let apply: () -> Void = {
|
let apply: () -> Void = {
|
||||||
|
|||||||
@ -77,6 +77,7 @@ import AvatarNode
|
|||||||
import ComponentFlow
|
import ComponentFlow
|
||||||
import EmojiStatusComponent
|
import EmojiStatusComponent
|
||||||
import ChatTitleView
|
import ChatTitleView
|
||||||
|
import ForumCreateTopicScreen
|
||||||
|
|
||||||
protocol PeerInfoScreenItem: AnyObject {
|
protocol PeerInfoScreenItem: AnyObject {
|
||||||
var id: AnyHashable { get }
|
var id: AnyHashable { get }
|
||||||
@ -423,7 +424,7 @@ private enum PeerInfoMemberAction {
|
|||||||
private enum PeerInfoContextSubject {
|
private enum PeerInfoContextSubject {
|
||||||
case bio
|
case bio
|
||||||
case phone(String)
|
case phone(String)
|
||||||
case link
|
case link(customLink: String?)
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum PeerInfoSettingsSection {
|
private enum PeerInfoSettingsSection {
|
||||||
@ -915,7 +916,7 @@ private func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoStat
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private func infoItems(data: PeerInfoScreenData?, context: AccountContext, presentationData: PresentationData, interaction: PeerInfoInteraction, nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, callMessages: [Message]) -> [(AnyHashable, [PeerInfoScreenItem])] {
|
private func infoItems(data: PeerInfoScreenData?, context: AccountContext, presentationData: PresentationData, interaction: PeerInfoInteraction, nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, callMessages: [Message], chatLocation: ChatLocation) -> [(AnyHashable, [PeerInfoScreenItem])] {
|
||||||
guard let data = data else {
|
guard let data = data else {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
@ -973,7 +974,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
|||||||
action: { _ in
|
action: { _ in
|
||||||
interaction.openUsername(username)
|
interaction.openUsername(username)
|
||||||
}, longTapAction: { sourceNode in
|
}, longTapAction: { sourceNode in
|
||||||
interaction.openPeerInfoContextMenu(.link, sourceNode)
|
interaction.openPeerInfoContextMenu(.link(customLink: nil), sourceNode)
|
||||||
}, linkItemAction: { type, item in
|
}, linkItemAction: { type, item in
|
||||||
if case .tap = type {
|
if case .tap = type {
|
||||||
if case let .mention(username) = item {
|
if case let .mention(username) = item {
|
||||||
@ -1077,6 +1078,46 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
|||||||
let ItemMembers = 6
|
let ItemMembers = 6
|
||||||
let ItemMemberRequests = 7
|
let ItemMemberRequests = 7
|
||||||
|
|
||||||
|
if let _ = data.threadInfo {
|
||||||
|
let mainUsername: String
|
||||||
|
if let addressName = channel.addressName {
|
||||||
|
mainUsername = addressName
|
||||||
|
} else {
|
||||||
|
mainUsername = "c/\(channel.id.id._internalGetInt64Value())"
|
||||||
|
}
|
||||||
|
|
||||||
|
var threadId: Int64 = 0
|
||||||
|
if case let .replyThread(message) = chatLocation {
|
||||||
|
threadId = Int64(message.messageId.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
let linkText = "https://t.me/\(mainUsername)?topic=\(threadId)"
|
||||||
|
|
||||||
|
items[.peerInfo]!.append(
|
||||||
|
PeerInfoScreenLabeledValueItem(
|
||||||
|
id: ItemUsername,
|
||||||
|
label: presentationData.strings.Channel_LinkItem,
|
||||||
|
text: linkText,
|
||||||
|
textColor: .accent,
|
||||||
|
icon: .qrCode,
|
||||||
|
action: { _ in
|
||||||
|
interaction.openUsername(linkText)
|
||||||
|
}, longTapAction: { sourceNode in
|
||||||
|
interaction.openPeerInfoContextMenu(.link(customLink: linkText), sourceNode)
|
||||||
|
}, linkItemAction: { type, item in
|
||||||
|
if case .tap = type {
|
||||||
|
if case let .mention(username) = item {
|
||||||
|
interaction.openUsername(String(username.suffix(from: username.index(username.startIndex, offsetBy: 1))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, iconAction: {
|
||||||
|
interaction.openQrCode()
|
||||||
|
}, requestLayout: {
|
||||||
|
interaction.requestLayout(false)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
if let location = (data.cachedData as? CachedChannelData)?.peerGeoLocation {
|
if let location = (data.cachedData as? CachedChannelData)?.peerGeoLocation {
|
||||||
items[.groupLocation]!.append(PeerInfoScreenHeaderItem(id: ItemLocationHeader, text: presentationData.strings.GroupInfo_Location.uppercased()))
|
items[.groupLocation]!.append(PeerInfoScreenHeaderItem(id: ItemLocationHeader, text: presentationData.strings.GroupInfo_Location.uppercased()))
|
||||||
|
|
||||||
@ -1112,7 +1153,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
|||||||
action: { _ in
|
action: { _ in
|
||||||
interaction.openUsername(username)
|
interaction.openUsername(username)
|
||||||
}, longTapAction: { sourceNode in
|
}, longTapAction: { sourceNode in
|
||||||
interaction.openPeerInfoContextMenu(.link, sourceNode)
|
interaction.openPeerInfoContextMenu(.link(customLink: nil), sourceNode)
|
||||||
}, linkItemAction: { type, item in
|
}, linkItemAction: { type, item in
|
||||||
if case .tap = type {
|
if case .tap = type {
|
||||||
if case let .mention(username) = item {
|
if case let .mention(username) = item {
|
||||||
@ -1183,6 +1224,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if let group = data.peer as? TelegramGroup {
|
} else if let group = data.peer as? TelegramGroup {
|
||||||
if let cachedData = data.cachedData as? CachedGroupData {
|
if let cachedData = data.cachedData as? CachedGroupData {
|
||||||
let aboutText: String?
|
let aboutText: String?
|
||||||
@ -1740,6 +1782,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
private let isOpenedFromChat: Bool
|
private let isOpenedFromChat: Bool
|
||||||
private let videoCallsEnabled: Bool
|
private let videoCallsEnabled: Bool
|
||||||
private let callMessages: [Message]
|
private let callMessages: [Message]
|
||||||
|
private let chatLocation: ChatLocation
|
||||||
|
private let chatLocationContextHolder: Atomic<ChatLocationContextHolder?>
|
||||||
|
|
||||||
let isSettings: Bool
|
let isSettings: Bool
|
||||||
private let isMediaOnly: Bool
|
private let isMediaOnly: Bool
|
||||||
@ -1834,7 +1878,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
}
|
}
|
||||||
private var didSetReady = false
|
private var didSetReady = false
|
||||||
|
|
||||||
init(controller: PeerInfoScreenImpl, context: AccountContext, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, callMessages: [Message], isSettings: Bool, hintGroupInCommon: PeerId?, requestsContext: PeerInvitationImportersContext?) {
|
init(controller: PeerInfoScreenImpl, context: AccountContext, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, callMessages: [Message], isSettings: Bool, hintGroupInCommon: PeerId?, requestsContext: PeerInvitationImportersContext?, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>) {
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
self.context = context
|
self.context = context
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
@ -1845,14 +1889,20 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
self.reactionSourceMessageId = reactionSourceMessageId
|
self.reactionSourceMessageId = reactionSourceMessageId
|
||||||
self.callMessages = callMessages
|
self.callMessages = callMessages
|
||||||
self.isSettings = isSettings
|
self.isSettings = isSettings
|
||||||
|
self.chatLocation = chatLocation
|
||||||
|
self.chatLocationContextHolder = chatLocationContextHolder
|
||||||
self.isMediaOnly = context.account.peerId == peerId && !isSettings
|
self.isMediaOnly = context.account.peerId == peerId && !isSettings
|
||||||
|
|
||||||
self.scrollNode = ASScrollNode()
|
self.scrollNode = ASScrollNode()
|
||||||
self.scrollNode.view.delaysContentTouches = false
|
self.scrollNode.view.delaysContentTouches = false
|
||||||
self.scrollNode.canCancelAllTouchesInViews = true
|
self.scrollNode.canCancelAllTouchesInViews = true
|
||||||
|
|
||||||
self.headerNode = PeerInfoHeaderNode(context: context, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, isMediaOnly: self.isMediaOnly, isSettings: isSettings)
|
var forumTopicThreadId: Int64?
|
||||||
self.paneContainerNode = PeerInfoPaneContainerNode(context: context, updatedPresentationData: controller.updatedPresentationData, peerId: peerId, isMediaOnly: self.isMediaOnly)
|
if case let .replyThread(message) = chatLocation {
|
||||||
|
forumTopicThreadId = Int64(message.messageId.id)
|
||||||
|
}
|
||||||
|
self.headerNode = PeerInfoHeaderNode(context: context, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, isMediaOnly: self.isMediaOnly, isSettings: isSettings, forumTopicThreadId: forumTopicThreadId)
|
||||||
|
self.paneContainerNode = PeerInfoPaneContainerNode(context: context, updatedPresentationData: controller.updatedPresentationData, peerId: peerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, isMediaOnly: self.isMediaOnly)
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
@ -2765,6 +2815,21 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
}
|
}
|
||||||
switch key {
|
switch key {
|
||||||
case .edit:
|
case .edit:
|
||||||
|
if case let .replyThread(message) = strongSelf.chatLocation {
|
||||||
|
let threadId = Int64(message.messageId.id)
|
||||||
|
if let threadInfo = strongSelf.data?.threadInfo {
|
||||||
|
let controller = ForumCreateTopicScreen(context: strongSelf.context, peerId: strongSelf.peerId, mode: .edit(topic: threadInfo))
|
||||||
|
controller.navigationPresentation = .modal
|
||||||
|
let context = strongSelf.context
|
||||||
|
controller.completion = { [weak controller] title, fileId in
|
||||||
|
let _ = (context.engine.peers.editForumChannelTopic(id: peerId, threadId: threadId, title: title, iconFileId: fileId)
|
||||||
|
|> deliverOnMainQueue).start(completed: {
|
||||||
|
controller?.dismiss()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
strongSelf.controller?.push(controller)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
(strongSelf.controller?.parent as? TabBarController)?.updateIsTabBarHidden(true, transition: .animated(duration: 0.3, curve: .linear))
|
(strongSelf.controller?.parent as? TabBarController)?.updateIsTabBarHidden(true, transition: .animated(duration: 0.3, curve: .linear))
|
||||||
strongSelf.state = strongSelf.state.withIsEditing(true)
|
strongSelf.state = strongSelf.state.withIsEditing(true)
|
||||||
var updateOnCompletion = false
|
var updateOnCompletion = false
|
||||||
@ -2795,6 +2860,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
strongSelf.controller?.navigationItem.setLeftBarButton(UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, style: .plain, target: strongSelf, action: #selector(strongSelf.editingCancelPressed)), animated: true)
|
strongSelf.controller?.navigationItem.setLeftBarButton(UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, style: .plain, target: strongSelf, action: #selector(strongSelf.editingCancelPressed)), animated: true)
|
||||||
|
}
|
||||||
case .done, .cancel:
|
case .done, .cancel:
|
||||||
strongSelf.view.endEditing(true)
|
strongSelf.view.endEditing(true)
|
||||||
if case .done = key {
|
if case .done = key {
|
||||||
@ -3207,7 +3273,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
strongSelf.controller?.present(emojiStatusSelectionController, in: .window(.root))
|
strongSelf.controller?.present(emojiStatusSelectionController, in: .window(.root))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
screenData = peerInfoScreenData(context: context, peerId: peerId, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, isSettings: self.isSettings, hintGroupInCommon: hintGroupInCommon, existingRequestsContext: requestsContext)
|
screenData = peerInfoScreenData(context: context, peerId: peerId, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, isSettings: self.isSettings, hintGroupInCommon: hintGroupInCommon, existingRequestsContext: requestsContext, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder)
|
||||||
|
|
||||||
self.headerNode.displayPremiumIntro = { [weak self] sourceView, peerStatus, emojiStatusFileAndPack, white in
|
self.headerNode.displayPremiumIntro = { [weak self] sourceView, peerStatus, emojiStatusFileAndPack, white in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
@ -4085,8 +4151,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
return .single(items)
|
return .single(items)
|
||||||
}
|
}
|
||||||
|
|
||||||
let allHeaderButtons = Set(peerInfoHeaderButtons(peer: peer, cachedData: data.cachedData, isOpenedFromChat: strongSelf.isOpenedFromChat, isExpanded: false, videoCallsEnabled: strongSelf.videoCallsEnabled, isSecretChat: strongSelf.peerId.namespace == Namespaces.Peer.SecretChat, isContact: strongSelf.data?.isContact ?? false))
|
let allHeaderButtons = Set(peerInfoHeaderButtons(peer: peer, cachedData: data.cachedData, isOpenedFromChat: strongSelf.isOpenedFromChat, isExpanded: false, videoCallsEnabled: strongSelf.videoCallsEnabled, isSecretChat: strongSelf.peerId.namespace == Namespaces.Peer.SecretChat, isContact: strongSelf.data?.isContact ?? false, threadInfo: data.threadInfo))
|
||||||
let headerButtons = Set(peerInfoHeaderButtons(peer: peer, cachedData: data.cachedData, isOpenedFromChat: strongSelf.isOpenedFromChat, isExpanded: true, videoCallsEnabled: strongSelf.videoCallsEnabled, isSecretChat: strongSelf.peerId.namespace == Namespaces.Peer.SecretChat, isContact: strongSelf.data?.isContact ?? false))
|
let headerButtons = Set(peerInfoHeaderButtons(peer: peer, cachedData: data.cachedData, isOpenedFromChat: strongSelf.isOpenedFromChat, isExpanded: true, videoCallsEnabled: strongSelf.videoCallsEnabled, isSecretChat: strongSelf.peerId.namespace == Namespaces.Peer.SecretChat, isContact: strongSelf.data?.isContact ?? false, threadInfo: strongSelf.data?.threadInfo))
|
||||||
|
|
||||||
let filteredButtons = allHeaderButtons.subtracting(headerButtons)
|
let filteredButtons = allHeaderButtons.subtracting(headerButtons)
|
||||||
|
|
||||||
@ -4538,6 +4604,19 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
|
|
||||||
private func openChatWithMessageSearch() {
|
private func openChatWithMessageSearch() {
|
||||||
if let navigationController = (self.controller?.navigationController as? NavigationController) {
|
if let navigationController = (self.controller?.navigationController as? NavigationController) {
|
||||||
|
if case let .replyThread(currentMessage) = self.chatLocation, let current = navigationController.viewControllers.first(where: { controller in
|
||||||
|
if let controller = controller as? ChatControllerImpl, case let .replyThread(message) = controller.chatLocation, message.messageId == currentMessage.messageId {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}) as? ChatControllerImpl {
|
||||||
|
var viewControllers = navigationController.viewControllers
|
||||||
|
if let index = viewControllers.firstIndex(of: current) {
|
||||||
|
viewControllers.removeSubrange(index + 1 ..< viewControllers.count)
|
||||||
|
}
|
||||||
|
navigationController.setViewControllers(viewControllers, animated: true)
|
||||||
|
current.activateSearch()
|
||||||
|
} else {
|
||||||
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(id: self.peerId), keepStack: self.nearbyPeerDistance != nil ? .always : .default, activateMessageSearch: (.everything, ""), peerNearbyData: self.nearbyPeerDistance.flatMap({ ChatPeerNearbyData(distance: $0) }), completion: { [weak self] _ in
|
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(id: self.peerId), keepStack: self.nearbyPeerDistance != nil ? .always : .default, activateMessageSearch: (.everything, ""), peerNearbyData: self.nearbyPeerDistance.flatMap({ ChatPeerNearbyData(distance: $0) }), completion: { [weak self] _ in
|
||||||
if let strongSelf = self, strongSelf.nearbyPeerDistance != nil {
|
if let strongSelf = self, strongSelf.nearbyPeerDistance != nil {
|
||||||
var viewControllers = navigationController.viewControllers
|
var viewControllers = navigationController.viewControllers
|
||||||
@ -4552,6 +4631,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func openChatForReporting(_ reason: ReportReason) {
|
private func openChatForReporting(_ reason: ReportReason) {
|
||||||
if let navigationController = (self.controller?.navigationController as? NavigationController) {
|
if let navigationController = (self.controller?.navigationController as? NavigationController) {
|
||||||
@ -4779,7 +4859,14 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func openUsername(value: String) {
|
private func openUsername(value: String) {
|
||||||
let shareController = ShareController(context: self.context, subject: .url("https://t.me/\(value)"), updatedPresentationData: self.controller?.updatedPresentationData)
|
let url: String
|
||||||
|
if value.hasPrefix("https://") {
|
||||||
|
url = value
|
||||||
|
} else {
|
||||||
|
url = "https://t.me/\(value)"
|
||||||
|
}
|
||||||
|
|
||||||
|
let shareController = ShareController(context: self.context, subject: .url(url), updatedPresentationData: self.controller?.updatedPresentationData)
|
||||||
shareController.completed = { [weak self] peerIds in
|
shareController.completed = { [weak self] peerIds in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
@ -5940,10 +6027,13 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
case .link:
|
case let .link(customLink):
|
||||||
if let addressName = peer.addressName {
|
|
||||||
let text: String
|
let text: String
|
||||||
let content: UndoOverlayContent
|
let content: UndoOverlayContent
|
||||||
|
if let customLink = customLink {
|
||||||
|
text = customLink
|
||||||
|
content = .linkCopied(text: self.presentationData.strings.Conversation_LinkCopied)
|
||||||
|
} else if let addressName = peer.addressName {
|
||||||
if peer is TelegramChannel {
|
if peer is TelegramChannel {
|
||||||
text = "https://t.me/\(addressName)"
|
text = "https://t.me/\(addressName)"
|
||||||
content = .linkCopied(text: self.presentationData.strings.Conversation_LinkCopied)
|
content = .linkCopied(text: self.presentationData.strings.Conversation_LinkCopied)
|
||||||
@ -5951,6 +6041,11 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
text = "@" + addressName
|
text = "@" + addressName
|
||||||
content = .copy(text: self.presentationData.strings.Conversation_UsernameCopied)
|
content = .copy(text: self.presentationData.strings.Conversation_UsernameCopied)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
text = "https://t.me/@id\(peer.id.id._internalGetInt64Value())"
|
||||||
|
content = .linkCopied(text: self.presentationData.strings.Conversation_LinkCopied)
|
||||||
|
}
|
||||||
|
|
||||||
let contextMenuController = ContextMenuController(actions: [ContextMenuAction(content: .text(title: self.presentationData.strings.Conversation_ContextMenuCopy, accessibilityLabel: self.presentationData.strings.Conversation_ContextMenuCopy), action: { [weak self] in
|
let contextMenuController = ContextMenuController(actions: [ContextMenuAction(content: .text(title: self.presentationData.strings.Conversation_ContextMenuCopy, accessibilityLabel: self.presentationData.strings.Conversation_ContextMenuCopy), action: { [weak self] in
|
||||||
UIPasteboard.general.string = text
|
UIPasteboard.general.string = text
|
||||||
|
|
||||||
@ -5966,7 +6061,6 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private func performBioLinkAction(action: TextLinkItemActionType, item: TextLinkItem) {
|
private func performBioLinkAction(action: TextLinkItemActionType, item: TextLinkItem) {
|
||||||
guard let data = self.data, let peer = data.peer, let controller = self.controller else {
|
guard let data = self.data, let peer = data.peer, let controller = self.controller else {
|
||||||
@ -6460,7 +6554,12 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
controller.present(ChatQrCodeScreen(context: self.context, subject: .peer(peer)), in: .window(.root))
|
var threadId: Int64 = 0
|
||||||
|
if case let .replyThread(message) = self.chatLocation {
|
||||||
|
threadId = Int64(message.messageId.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
controller.present(ChatQrCodeScreen(context: self.context, subject: .peer(peer: peer, threadId: threadId)), in: .window(.root))
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func openSettings(section: PeerInfoSettingsSection) {
|
fileprivate func openSettings(section: PeerInfoSettingsSection) {
|
||||||
@ -7428,7 +7527,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
}
|
}
|
||||||
let headerInset = sectionInset
|
let headerInset = sectionInset
|
||||||
|
|
||||||
var 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, notificationSettings: self.data?.notificationSettings, 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, transition: transition, additive: additive)
|
var 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, threadInfo: self.data?.threadInfo, notificationSettings: self.data?.notificationSettings, 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, transition: transition, additive: additive)
|
||||||
if !self.isSettings && !self.state.isEditing {
|
if !self.isSettings && !self.state.isEditing {
|
||||||
headerHeight += 71.0
|
headerHeight += 71.0
|
||||||
}
|
}
|
||||||
@ -7448,7 +7547,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
insets.left += sectionInset
|
insets.left += sectionInset
|
||||||
insets.right += sectionInset
|
insets.right += sectionInset
|
||||||
|
|
||||||
let items = self.isSettings ? settingsItems(data: self.data, context: self.context, presentationData: self.presentationData, interaction: self.interaction, isExpanded: self.headerNode.isAvatarExpanded) : infoItems(data: self.data, context: self.context, presentationData: self.presentationData, interaction: self.interaction, nearbyPeerDistance: self.nearbyPeerDistance, reactionSourceMessageId: self.reactionSourceMessageId, callMessages: self.callMessages)
|
let items = self.isSettings ? settingsItems(data: self.data, context: self.context, presentationData: self.presentationData, interaction: self.interaction, isExpanded: self.headerNode.isAvatarExpanded) : infoItems(data: self.data, context: self.context, presentationData: self.presentationData, interaction: self.interaction, nearbyPeerDistance: self.nearbyPeerDistance, reactionSourceMessageId: self.reactionSourceMessageId, callMessages: self.callMessages, chatLocation: self.chatLocation)
|
||||||
|
|
||||||
contentHeight += headerHeight
|
contentHeight += headerHeight
|
||||||
if !(self.isSettings && self.state.isEditing) {
|
if !(self.isSettings && self.state.isEditing) {
|
||||||
@ -7788,7 +7887,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
}
|
}
|
||||||
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, notificationSettings: self.data?.notificationSettings, 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, transition: transition, additive: additive)
|
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, threadInfo: self.data?.threadInfo, notificationSettings: self.data?.notificationSettings, 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, transition: transition, additive: additive)
|
||||||
}
|
}
|
||||||
|
|
||||||
let paneAreaExpansionDistance: CGFloat = 32.0
|
let paneAreaExpansionDistance: CGFloat = 32.0
|
||||||
@ -8068,6 +8167,8 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
|||||||
private let isSettings: Bool
|
private let isSettings: Bool
|
||||||
private let hintGroupInCommon: PeerId?
|
private let hintGroupInCommon: PeerId?
|
||||||
private weak var requestsContext: PeerInvitationImportersContext?
|
private weak var requestsContext: PeerInvitationImportersContext?
|
||||||
|
private let chatLocation: ChatLocation
|
||||||
|
private let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
|
||||||
|
|
||||||
fileprivate var presentationData: PresentationData
|
fileprivate var presentationData: PresentationData
|
||||||
private var presentationDataDisposable: Disposable?
|
private var presentationDataDisposable: Disposable?
|
||||||
@ -8102,7 +8203,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
|||||||
|
|
||||||
private var validLayout: (layout: ContainerViewLayout, navigationHeight: CGFloat)?
|
private var validLayout: (layout: ContainerViewLayout, navigationHeight: CGFloat)?
|
||||||
|
|
||||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, callMessages: [Message], isSettings: Bool = false, hintGroupInCommon: PeerId? = nil, requestsContext: PeerInvitationImportersContext? = nil) {
|
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, callMessages: [Message], isSettings: Bool = false, hintGroupInCommon: PeerId? = nil, requestsContext: PeerInvitationImportersContext? = nil, forumTopicThread: ChatReplyThreadMessage? = nil) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.updatedPresentationData = updatedPresentationData
|
self.updatedPresentationData = updatedPresentationData
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
@ -8115,6 +8216,12 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
|||||||
self.hintGroupInCommon = hintGroupInCommon
|
self.hintGroupInCommon = hintGroupInCommon
|
||||||
self.requestsContext = requestsContext
|
self.requestsContext = requestsContext
|
||||||
|
|
||||||
|
if let forumTopicThread = forumTopicThread {
|
||||||
|
self.chatLocation = .replyThread(message: forumTopicThread)
|
||||||
|
} else {
|
||||||
|
self.chatLocation = .peer(id: peerId)
|
||||||
|
}
|
||||||
|
|
||||||
self.presentationData = updatedPresentationData?.0 ?? context.sharedContext.currentPresentationData.with { $0 }
|
self.presentationData = updatedPresentationData?.0 ?? context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
let baseNavigationBarPresentationData = NavigationBarPresentationData(presentationData: self.presentationData)
|
let baseNavigationBarPresentationData = NavigationBarPresentationData(presentationData: self.presentationData)
|
||||||
@ -8299,6 +8406,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
|||||||
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if case .peer = self.chatLocation {
|
||||||
self.navigationBar?.makeCustomTransitionNode = { [weak self] other, isInteractive in
|
self.navigationBar?.makeCustomTransitionNode = { [weak self] other, isInteractive in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return nil
|
return nil
|
||||||
@ -8326,6 +8434,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.setStatusBarStyle(avatarInitiallyExpanded ? .White : self.presentationData.theme.rootController.statusBarStyle.style, animated: false)
|
self.setStatusBarStyle(avatarInitiallyExpanded ? .White : self.presentationData.theme.rootController.statusBarStyle.style, animated: false)
|
||||||
|
|
||||||
@ -8396,7 +8505,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
|||||||
}
|
}
|
||||||
|
|
||||||
override public func loadDisplayNode() {
|
override public func loadDisplayNode() {
|
||||||
self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded, isOpenedFromChat: self.isOpenedFromChat, nearbyPeerDistance: self.nearbyPeerDistance, reactionSourceMessageId: self.reactionSourceMessageId, callMessages: self.callMessages, isSettings: self.isSettings, hintGroupInCommon: self.hintGroupInCommon, requestsContext: requestsContext)
|
self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded, isOpenedFromChat: self.isOpenedFromChat, nearbyPeerDistance: self.nearbyPeerDistance, reactionSourceMessageId: self.reactionSourceMessageId, callMessages: self.callMessages, isSettings: self.isSettings, hintGroupInCommon: self.hintGroupInCommon, requestsContext: self.requestsContext, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder)
|
||||||
self.controllerNode.accountsAndPeers.set(self.accountsAndPeers.get() |> map { $0.1 })
|
self.controllerNode.accountsAndPeers.set(self.accountsAndPeers.get() |> map { $0.1 })
|
||||||
self.controllerNode.activeSessionsContextAndCount.set(self.activeSessionsContextAndCount.get())
|
self.controllerNode.activeSessionsContextAndCount.set(self.activeSessionsContextAndCount.get())
|
||||||
self.cachedDataPromise.set(self.controllerNode.cachedDataPromise.get())
|
self.cachedDataPromise.set(self.controllerNode.cachedDataPromise.get())
|
||||||
@ -8795,7 +8904,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, notificationSettings: self.screenNode.data?.notificationSettings, 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, transition: transition, additive: false)
|
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, threadInfo: self.screenNode.data?.threadInfo, notificationSettings: self.screenNode.data?.notificationSettings, 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, transition: transition, additive: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
@ -761,6 +761,8 @@ final class PeerInfoGifPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScrollViewDe
|
|||||||
|
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private let peerId: PeerId
|
private let peerId: PeerId
|
||||||
|
private let chatLocation: ChatLocation
|
||||||
|
private let chatLocationContextHolder: Atomic<ChatLocationContextHolder?>
|
||||||
private let chatControllerInteraction: ChatControllerInteraction
|
private let chatControllerInteraction: ChatControllerInteraction
|
||||||
private let contentType: ContentType
|
private let contentType: ContentType
|
||||||
|
|
||||||
@ -809,9 +811,11 @@ final class PeerInfoGifPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScrollViewDe
|
|||||||
return 0.0
|
return 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
init(context: AccountContext, chatControllerInteraction: ChatControllerInteraction, peerId: PeerId, contentType: ContentType) {
|
init(context: AccountContext, chatControllerInteraction: ChatControllerInteraction, peerId: PeerId, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, contentType: ContentType) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
|
self.chatLocation = chatLocation
|
||||||
|
self.chatLocationContextHolder = chatLocationContextHolder
|
||||||
self.chatControllerInteraction = chatControllerInteraction
|
self.chatControllerInteraction = chatControllerInteraction
|
||||||
self.contentType = contentType
|
self.contentType = contentType
|
||||||
|
|
||||||
|
|||||||
@ -1468,8 +1468,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
return recentSessionsController(context: context, activeSessionsContext: activeSessionsContext, webSessionsContext: context.engine.privacy.webSessions(), websitesOnly: false)
|
return recentSessionsController(context: context, activeSessionsContext: activeSessionsContext, webSessionsContext: context.engine.privacy.webSessions(), websitesOnly: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func makeChatQrCodeScreen(context: AccountContext, peer: Peer) -> ViewController {
|
public func makeChatQrCodeScreen(context: AccountContext, peer: Peer, threadId: Int64?) -> ViewController {
|
||||||
return ChatQrCodeScreen(context: context, subject: .peer(peer))
|
return ChatQrCodeScreen(context: context, subject: .peer(peer: peer, threadId: threadId))
|
||||||
}
|
}
|
||||||
|
|
||||||
public func makePrivacyAndSecurityController(context: AccountContext) -> ViewController {
|
public func makePrivacyAndSecurityController(context: AccountContext) -> ViewController {
|
||||||
@ -1532,7 +1532,14 @@ private func peerInfoControllerImpl(context: AccountContext, updatedPresentation
|
|||||||
if let _ = peer as? TelegramGroup {
|
if let _ = peer as? TelegramGroup {
|
||||||
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: [])
|
||||||
} else if let _ = peer as? TelegramChannel {
|
} else if let _ = peer as? TelegramChannel {
|
||||||
return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nil, reactionSourceMessageId: nil, callMessages: [])
|
var forumTopicThread: ChatReplyThreadMessage?
|
||||||
|
switch mode {
|
||||||
|
case let .forumTopic(thread):
|
||||||
|
forumTopicThread = thread
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nil, reactionSourceMessageId: nil, callMessages: [], forumTopicThread: forumTopicThread)
|
||||||
} else if peer is TelegramUser {
|
} else if peer is TelegramUser {
|
||||||
var nearbyPeerDistance: Int32?
|
var nearbyPeerDistance: Int32?
|
||||||
var reactionSourceMessageId: MessageId?
|
var reactionSourceMessageId: MessageId?
|
||||||
@ -1549,6 +1556,8 @@ private func peerInfoControllerImpl(context: AccountContext, updatedPresentation
|
|||||||
hintGroupInCommon = id
|
hintGroupInCommon = id
|
||||||
case let .reaction(messageId):
|
case let .reaction(messageId):
|
||||||
reactionSourceMessageId = messageId
|
reactionSourceMessageId = messageId
|
||||||
|
case .forumTopic:
|
||||||
|
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)
|
||||||
} else if peer is TelegramSecretChat {
|
} else if peer is TelegramSecretChat {
|
||||||
|
|||||||
@ -73,7 +73,12 @@ public enum ParsedInternalPeerUrlParameter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public enum ParsedInternalUrl {
|
public enum ParsedInternalUrl {
|
||||||
case peerName(String, ParsedInternalPeerUrlParameter?)
|
public enum UrlPeerReference {
|
||||||
|
case name(String)
|
||||||
|
case id(PeerId)
|
||||||
|
}
|
||||||
|
|
||||||
|
case peer(UrlPeerReference, ParsedInternalPeerUrlParameter?)
|
||||||
case peerId(PeerId)
|
case peerId(PeerId)
|
||||||
case privateMessage(messageId: MessageId, threadId: Int32?, timecode: Double?)
|
case privateMessage(messageId: MessageId, threadId: Int32?, timecode: Double?)
|
||||||
case stickerPack(name: String, type: StickerPackUrlType)
|
case stickerPack(name: String, type: StickerPackUrlType)
|
||||||
@ -193,9 +198,9 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return .peerName(peerName, .attachBotStart(value, startAttach))
|
return .peer(.name(peerName), .attachBotStart(value, startAttach))
|
||||||
} else if queryItem.name == "start" {
|
} else if queryItem.name == "start" {
|
||||||
return .peerName(peerName, .botStart(value))
|
return .peer(.name(peerName), .botStart(value))
|
||||||
} else if queryItem.name == "startgroup" {
|
} else if queryItem.name == "startgroup" {
|
||||||
var botAdminRights: ResolvedBotAdminRights?
|
var botAdminRights: ResolvedBotAdminRights?
|
||||||
for queryItem in queryItems {
|
for queryItem in queryItems {
|
||||||
@ -204,11 +209,11 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return .peerName(peerName, .groupBotStart(value, botAdminRights))
|
return .peer(.name(peerName), .groupBotStart(value, botAdminRights))
|
||||||
} else if queryItem.name == "game" {
|
} else if queryItem.name == "game" {
|
||||||
return nil
|
return nil
|
||||||
} else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) {
|
} else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) {
|
||||||
return .peerName(peerName, .voiceChat(value))
|
return .peer(.name(peerName), .voiceChat(value))
|
||||||
} else if queryItem.name == "startattach" {
|
} else if queryItem.name == "startattach" {
|
||||||
var choose: String?
|
var choose: String?
|
||||||
for queryItem in queryItems {
|
for queryItem in queryItems {
|
||||||
@ -220,7 +225,7 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? {
|
|||||||
return .startAttach(peerName, value, choose)
|
return .startAttach(peerName, value, choose)
|
||||||
}
|
}
|
||||||
} else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) {
|
} else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) {
|
||||||
return .peerName(peerName, .voiceChat(nil))
|
return .peer(.name(peerName), .voiceChat(nil))
|
||||||
} else if queryItem.name == "startattach" {
|
} else if queryItem.name == "startattach" {
|
||||||
var choose: String?
|
var choose: String?
|
||||||
for queryItem in queryItems {
|
for queryItem in queryItems {
|
||||||
@ -238,7 +243,7 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return .peerName(peerName, .groupBotStart("", botAdminRights))
|
return .peer(.name(peerName), .groupBotStart("", botAdminRights))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -269,7 +274,7 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? {
|
|||||||
let component = pathComponents[0].replacingOccurrences(of: "%24", with: "$")
|
let component = pathComponents[0].replacingOccurrences(of: "%24", with: "$")
|
||||||
return .invoice(component)
|
return .invoice(component)
|
||||||
}
|
}
|
||||||
return .peerName(peerName, nil)
|
return .peer(.name(peerName), nil)
|
||||||
} else if pathComponents.count == 2 || pathComponents.count == 3 {
|
} else if pathComponents.count == 2 || pathComponents.count == 3 {
|
||||||
if pathComponents[0] == "addstickers" {
|
if pathComponents[0] == "addstickers" {
|
||||||
return .stickerPack(name: pathComponents[1], type: .stickers)
|
return .stickerPack(name: pathComponents[1], type: .stickers)
|
||||||
@ -408,7 +413,7 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? {
|
|||||||
if let queryItems = components.queryItems {
|
if let queryItems = components.queryItems {
|
||||||
for queryItem in queryItems {
|
for queryItem in queryItems {
|
||||||
if let value = queryItem.value {
|
if let value = queryItem.value {
|
||||||
if queryItem.name == "thread" {
|
if queryItem.name == "thread" || queryItem.name == "topic" {
|
||||||
if let intValue = Int32(value) {
|
if let intValue = Int32(value) {
|
||||||
threadId = intValue
|
threadId = intValue
|
||||||
}
|
}
|
||||||
@ -424,6 +429,29 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? {
|
|||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
} else if pathComponents.count == 2 && pathComponents[0] == "c" {
|
||||||
|
if let channelId = Int64(pathComponents[1]) {
|
||||||
|
var threadId: Int32?
|
||||||
|
if let queryItems = components.queryItems {
|
||||||
|
for queryItem in queryItems {
|
||||||
|
if let value = queryItem.value {
|
||||||
|
if queryItem.name == "thread" || queryItem.name == "topic" {
|
||||||
|
if let intValue = Int32(value) {
|
||||||
|
threadId = intValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let threadId = threadId {
|
||||||
|
return .peer(.id(PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId))), .replyThread(threadId, threadId))
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
} else if let value = Int32(pathComponents[1]) {
|
} else if let value = Int32(pathComponents[1]) {
|
||||||
var threadId: Int32?
|
var threadId: Int32?
|
||||||
var commentId: Int32?
|
var commentId: Int32?
|
||||||
@ -431,7 +459,7 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? {
|
|||||||
if let queryItems = components.queryItems {
|
if let queryItems = components.queryItems {
|
||||||
for queryItem in queryItems {
|
for queryItem in queryItems {
|
||||||
if let value = queryItem.value {
|
if let value = queryItem.value {
|
||||||
if queryItem.name == "thread" {
|
if queryItem.name == "thread" || queryItem.name == "topic" {
|
||||||
if let intValue = Int32(value) {
|
if let intValue = Int32(value) {
|
||||||
threadId = intValue
|
threadId = intValue
|
||||||
}
|
}
|
||||||
@ -448,11 +476,11 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let threadId = threadId {
|
if let threadId = threadId {
|
||||||
return .peerName(peerName, .replyThread(threadId, value))
|
return .peer(.name(peerName), .replyThread(threadId, value))
|
||||||
} else if let commentId = commentId {
|
} else if let commentId = commentId {
|
||||||
return .peerName(peerName, .replyThread(value, commentId))
|
return .peer(.name(peerName), .replyThread(value, commentId))
|
||||||
} else {
|
} else {
|
||||||
return .peerName(peerName, .channelMessage(value, timecode))
|
return .peer(.name(peerName), .channelMessage(value, timecode))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
@ -489,12 +517,36 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl)
|
|||||||
return .single(.peer(nil, .info))
|
return .single(.peer(nil, .info))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case let .peerName(name, parameter):
|
case let .peer(reference, parameter):
|
||||||
return context.engine.peers.resolvePeerByName(name: name)
|
let resolvedPeer: Signal<Peer?, NoError>
|
||||||
|
switch reference {
|
||||||
|
case let .name(name):
|
||||||
|
resolvedPeer = context.engine.peers.resolvePeerByName(name: name)
|
||||||
|> take(1)
|
|> take(1)
|
||||||
|> mapToSignal { peer -> Signal<Peer?, NoError> in
|
|> mapToSignal { peer -> Signal<Peer?, NoError> in
|
||||||
return .single(peer?._asPeer())
|
return .single(peer?._asPeer())
|
||||||
}
|
}
|
||||||
|
case let .id(id):
|
||||||
|
if id.namespace == Namespaces.Peer.CloudChannel {
|
||||||
|
resolvedPeer = context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: id))
|
||||||
|
|> mapToSignal { peer -> Signal<Peer?, NoError> in
|
||||||
|
let foundPeer: Signal<Peer?, NoError>
|
||||||
|
if let peer = peer {
|
||||||
|
foundPeer = .single(peer._asPeer())
|
||||||
|
} else {
|
||||||
|
foundPeer = TelegramEngine(account: context.account).peers.findChannelById(channelId: id.id._internalGetInt64Value())
|
||||||
|
|> map { peer -> Peer? in
|
||||||
|
return peer?._asPeer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return foundPeer
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resolvedPeer = .single(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolvedPeer
|
||||||
|> mapToSignal { peer -> Signal<ResolvedUrl?, NoError> in
|
|> mapToSignal { peer -> Signal<ResolvedUrl?, NoError> in
|
||||||
if let peer = peer {
|
if let peer = peer {
|
||||||
if let parameter = parameter {
|
if let parameter = parameter {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user