diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 20084fa97d..31c6d17ad9 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -8241,3 +8241,6 @@ Sorry for the inconvenience."; "Attachment.DiscardPasteboardAlertText" = "Discard pasted items?"; "Undo.DeletedTopic" = "Topic Deleted"; + +"ChatList.MaxThreadPinsFinalText_1" = "Sorry, you can't pin more than **%@** thread to the top. Unpin some that are currently pinned."; +"ChatList.MaxThreadPinsFinalText_any" = "Sorry, you can't pin more than **%@** threads to the top. Unpin some that are currently pinned."; diff --git a/submodules/ChatListUI/Sources/ChatContextMenus.swift b/submodules/ChatListUI/Sources/ChatContextMenus.swift index 079a76380b..8d0fbc5c01 100644 --- a/submodules/ChatListUI/Sources/ChatContextMenus.swift +++ b/submodules/ChatListUI/Sources/ChatContextMenus.swift @@ -519,7 +519,19 @@ func chatForumTopicMenuItems(context: AccountContext, peerId: PeerId, threadId: items.append(.action(ContextMenuActionItem(text: isPinned ? presentationData.strings.ChatList_Context_Unpin : presentationData.strings.ChatList_Context_Pin, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isPinned ? "Chat/Context Menu/Unpin": "Chat/Context Menu/Pin"), color: theme.contextMenu.primaryColor) }, action: { _, f in f(.default) - let _ = context.engine.peers.toggleForumChannelTopicPinned(id: peerId, threadId: threadId).start() + let _ = (context.engine.peers.toggleForumChannelTopicPinned(id: peerId, threadId: threadId) + |> deliverOnMainQueue).start(error: { error in + switch error { + case let .limitReached(count): + if let chatListController = chatListController { + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + let text = presentationData.strings.ChatList_MaxThreadPinsFinalText(Int32(count)) + chatListController.present(textAlertController(context: context, title: presentationData.strings.Premium_LimitReached, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})], parseMarkdown: true), in: .window(.root)) + } + default: + break + } + }) }))) } diff --git a/submodules/ChatListUI/Sources/Node/ChatListNode.swift b/submodules/ChatListUI/Sources/Node/ChatListNode.swift index 1438dcf409..0ab3d0eb17 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNode.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNode.swift @@ -1697,85 +1697,160 @@ public final class ChatListNode: ListView { }) self.reorderItem = { [weak self] fromIndex, toIndex, transactionOpaqueState -> Signal in - if let strongSelf = self, let filteredEntries = (transactionOpaqueState as? ChatListOpaqueTransactionState)?.chatListView.filteredEntries { - guard case let .chatList(groupId) = strongSelf.location else { - return .single(false) + guard let strongSelf = self, let filteredEntries = (transactionOpaqueState as? ChatListOpaqueTransactionState)?.chatListView.filteredEntries else { + return .single(false) + } + guard fromIndex >= 0 && fromIndex < filteredEntries.count && toIndex >= 0 && toIndex < filteredEntries.count else { + return .single(false) + } + + switch strongSelf.location { + case let .chatList(groupId): + let fromEntry = filteredEntries[filteredEntries.count - 1 - fromIndex] + let toEntry = filteredEntries[filteredEntries.count - 1 - toIndex] + + var referenceId: EngineChatList.PinnedItem.Id? + var beforeAll = false + switch toEntry { + case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, promoInfo, _, _, _): + if promoInfo != nil { + beforeAll = true + } else { + if case let .chatList(chatListIndex) = index { + referenceId = .peer(chatListIndex.messageIndex.id.peerId) + } + } + default: + break } - if fromIndex >= 0 && fromIndex < filteredEntries.count && toIndex >= 0 && toIndex < filteredEntries.count { - let fromEntry = filteredEntries[filteredEntries.count - 1 - fromIndex] - let toEntry = filteredEntries[filteredEntries.count - 1 - toIndex] + if case let .index(index) = fromEntry.sortIndex, case let .chatList(chatListIndex) = index, let _ = chatListIndex.pinningIndex { + let location: TogglePeerChatPinnedLocation + if let chatListFilter = chatListFilter { + location = .filter(chatListFilter.id) + } else { + location = .group(groupId._asGroup()) + } - var referenceId: EngineChatList.PinnedItem.Id? - var beforeAll = false - switch toEntry { - case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, promoInfo, _, _, _): - if promoInfo != nil { - beforeAll = true - } else { - if case let .chatList(chatListIndex) = index { - referenceId = .peer(chatListIndex.messageIndex.id.peerId) + let engine = strongSelf.context.engine + return engine.peers.getPinnedItemIds(location: location) + |> mapToSignal { itemIds -> Signal in + var itemIds = itemIds + + var itemId: EngineChatList.PinnedItem.Id? + switch fromEntry { + case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): + if case let .chatList(index) = index { + itemId = .peer(index.messageIndex.id.peerId) } - } default: break - } - - if case let .index(index) = fromEntry.sortIndex, case let .chatList(chatListIndex) = index, let _ = chatListIndex.pinningIndex { - let location: TogglePeerChatPinnedLocation - if let chatListFilter = chatListFilter { - location = .filter(chatListFilter.id) - } else { - location = .group(groupId._asGroup()) } - - let engine = strongSelf.context.engine - return engine.peers.getPinnedItemIds(location: location) - |> mapToSignal { itemIds -> Signal in - var itemIds = itemIds - - var itemId: EngineChatList.PinnedItem.Id? - switch fromEntry { - case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): - if case let .chatList(index) = index { - itemId = .peer(index.messageIndex.id.peerId) - } - default: - break - } - - if let itemId = itemId { - itemIds = itemIds.filter({ $0 != itemId }) - if let referenceId = referenceId { - var inserted = false - for i in 0 ..< itemIds.count { - if itemIds[i] == referenceId { - if fromIndex < toIndex { - itemIds.insert(itemId, at: i + 1) - } else { - itemIds.insert(itemId, at: i) - } - inserted = true - break + + if let itemId = itemId { + itemIds = itemIds.filter({ $0 != itemId }) + if let referenceId = referenceId { + var inserted = false + for i in 0 ..< itemIds.count { + if itemIds[i] == referenceId { + if fromIndex < toIndex { + itemIds.insert(itemId, at: i + 1) + } else { + itemIds.insert(itemId, at: i) } + inserted = true + break } - if !inserted { - itemIds.append(itemId) - } - } else if beforeAll { - itemIds.insert(itemId, at: 0) - } else { + } + if !inserted { itemIds.append(itemId) } - return engine.peers.reorderPinnedItemIds(location: location, itemIds: itemIds) + } else if beforeAll { + itemIds.insert(itemId, at: 0) } else { - return .single(false) + itemIds.append(itemId) } + return engine.peers.reorderPinnedItemIds(location: location, itemIds: itemIds) + } else { + return .single(false) } } + } else { + return .single(false) + } + case let .forum(peerId): + let fromEntry = filteredEntries[filteredEntries.count - 1 - fromIndex] + let toEntry = filteredEntries[filteredEntries.count - 1 - toIndex] + + var referenceId: Int64? + var beforeAll = false + switch toEntry { + case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, promoInfo, _, _, _): + if promoInfo != nil { + beforeAll = true + } else { + if case let .forum(_, _, threadId, _, _) = index { + referenceId = threadId + } + } + default: + break + } + + if case let .index(index) = fromEntry.sortIndex, case let .forum(pinningIndex, _, _, _, _) = index, case .index = pinningIndex { + let engine = strongSelf.context.engine + return engine.peers.getForumChannelPinnedTopics(id: peerId) + |> mapToSignal { itemIds -> Signal in + var itemIds = itemIds + + var itemId: Int64? + switch fromEntry { + case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): + if case let .forum(_, _, threadId, _, _) = index { + itemId = threadId + } + default: + break + } + + if let itemId = itemId { + itemIds = itemIds.filter({ $0 != itemId }) + if let referenceId = referenceId { + var inserted = false + for i in 0 ..< itemIds.count { + if itemIds[i] == referenceId { + if fromIndex < toIndex { + itemIds.insert(itemId, at: i + 1) + } else { + itemIds.insert(itemId, at: i) + } + inserted = true + break + } + } + if !inserted { + itemIds.append(itemId) + } + } else if beforeAll { + itemIds.insert(itemId, at: 0) + } else { + itemIds.append(itemId) + } + return engine.peers.setForumChannelPinnedTopics(id: peerId, threadIds: itemIds) + |> map { _ -> Bool in + } + |> `catch` { _ -> Signal in + return .single(false) + } + |> then(Signal.single(true)) + } else { + return .single(false) + } + } + } else { + return .single(false) } } - return .single(false) } var startedScrollingAtUpperBound = false diff --git a/submodules/TelegramCore/Sources/ForumChannels.swift b/submodules/TelegramCore/Sources/ForumChannels.swift index a4042fbe92..84a1bf30dc 100644 --- a/submodules/TelegramCore/Sources/ForumChannels.swift +++ b/submodules/TelegramCore/Sources/ForumChannels.swift @@ -386,6 +386,12 @@ func _internal_setForumChannelPinnedTopics(account: Account, id: EnginePeer.Id, return .fail(.generic) } + #if DEBUG + if "".isEmpty { + return .complete() + } + #endif + return account.network.request(Api.functions.channels.reorderPinnedForumTopics( channel: inputChannel, order: threadIds.map(Int32.init(clamping:)) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift index 7b2a20a312..bc38a263fc 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift @@ -878,6 +878,12 @@ public extension TelegramEngine { } } + public func getForumChannelPinnedTopics(id: EnginePeer.Id) -> Signal<[Int64], NoError> { + return self.account.postbox.transaction { transcation -> [Int64] in + return transcation.getPeerPinnedThreads(peerId: id) + } + } + public func setForumChannelPinnedTopics(id: EnginePeer.Id, threadIds: [Int64]) -> Signal { return _internal_setForumChannelPinnedTopics(account: self.account, id: id, threadIds: threadIds) }