Support multiple pinned threads

This commit is contained in:
Ali 2022-11-04 19:15:25 +04:00
parent f1864a43b9
commit fa95906962
5 changed files with 165 additions and 63 deletions

View File

@ -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.";

View File

@ -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
}
})
})))
}

View File

@ -1697,85 +1697,160 @@ public final class ChatListNode: ListView {
})
self.reorderItem = { [weak self] fromIndex, toIndex, transactionOpaqueState -> Signal<Bool, NoError> 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<Bool, NoError> 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<Bool, NoError> 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<Bool, NoError> 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<Bool, NoError> in
return .single(false)
}
|> then(Signal<Bool, NoError>.single(true))
} else {
return .single(false)
}
}
} else {
return .single(false)
}
}
return .single(false)
}
var startedScrollingAtUpperBound = false

View File

@ -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:))

View File

@ -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<Never, SetForumChannelTopicPinnedError> {
return _internal_setForumChannelPinnedTopics(account: self.account, id: id, threadIds: threadIds)
}