mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Folders
This commit is contained in:
parent
60db6559ea
commit
a78924ccd9
@ -88,6 +88,7 @@ swift_library(
|
|||||||
"//submodules/TelegramUI/Components/ChatListTitleView",
|
"//submodules/TelegramUI/Components/ChatListTitleView",
|
||||||
"//submodules/AvatarNode:AvatarNode",
|
"//submodules/AvatarNode:AvatarNode",
|
||||||
"//submodules/AvatarVideoNode:AvatarVideoNode",
|
"//submodules/AvatarVideoNode:AvatarVideoNode",
|
||||||
|
"//submodules/InviteLinksUI",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -14,6 +14,7 @@ import ItemListPeerActionItem
|
|||||||
import AvatarNode
|
import AvatarNode
|
||||||
import ChatListFilterSettingsHeaderItem
|
import ChatListFilterSettingsHeaderItem
|
||||||
import PremiumUI
|
import PremiumUI
|
||||||
|
import InviteLinksUI
|
||||||
|
|
||||||
private enum FilterSection: Int32, Hashable {
|
private enum FilterSection: Int32, Hashable {
|
||||||
case include
|
case include
|
||||||
@ -32,6 +33,8 @@ private final class ChatListFilterPresetControllerArguments {
|
|||||||
let deleteExcludeCategory: (ChatListFilterExcludeCategory) -> Void
|
let deleteExcludeCategory: (ChatListFilterExcludeCategory) -> Void
|
||||||
let focusOnName: () -> Void
|
let focusOnName: () -> Void
|
||||||
let expandSection: (FilterSection) -> Void
|
let expandSection: (FilterSection) -> Void
|
||||||
|
let createLink: () -> Void
|
||||||
|
let openLink: (ExportedChatFolderLink) -> Void
|
||||||
|
|
||||||
init(
|
init(
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
@ -44,7 +47,9 @@ private final class ChatListFilterPresetControllerArguments {
|
|||||||
deleteIncludeCategory: @escaping (ChatListFilterIncludeCategory) -> Void,
|
deleteIncludeCategory: @escaping (ChatListFilterIncludeCategory) -> Void,
|
||||||
deleteExcludeCategory: @escaping (ChatListFilterExcludeCategory) -> Void,
|
deleteExcludeCategory: @escaping (ChatListFilterExcludeCategory) -> Void,
|
||||||
focusOnName: @escaping () -> Void,
|
focusOnName: @escaping () -> Void,
|
||||||
expandSection: @escaping (FilterSection) -> Void
|
expandSection: @escaping (FilterSection) -> Void,
|
||||||
|
createLink: @escaping () -> Void,
|
||||||
|
openLink: @escaping (ExportedChatFolderLink) -> Void
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.updateState = updateState
|
self.updateState = updateState
|
||||||
@ -57,6 +62,8 @@ private final class ChatListFilterPresetControllerArguments {
|
|||||||
self.deleteExcludeCategory = deleteExcludeCategory
|
self.deleteExcludeCategory = deleteExcludeCategory
|
||||||
self.focusOnName = focusOnName
|
self.focusOnName = focusOnName
|
||||||
self.expandSection = expandSection
|
self.expandSection = expandSection
|
||||||
|
self.createLink = createLink
|
||||||
|
self.openLink = openLink
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,6 +72,7 @@ private enum ChatListFilterPresetControllerSection: Int32 {
|
|||||||
case name
|
case name
|
||||||
case includePeers
|
case includePeers
|
||||||
case excludePeers
|
case excludePeers
|
||||||
|
case inviteLinks
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum ChatListFilterPresetEntryStableId: Hashable {
|
private enum ChatListFilterPresetEntryStableId: Hashable {
|
||||||
@ -76,6 +84,7 @@ private enum ChatListFilterPresetEntryStableId: Hashable {
|
|||||||
case excludeCategory(ChatListFilterExcludeCategory)
|
case excludeCategory(ChatListFilterExcludeCategory)
|
||||||
case includeExpand
|
case includeExpand
|
||||||
case excludeExpand
|
case excludeExpand
|
||||||
|
case inviteLink(String)
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum ChatListFilterPresetEntrySortId: Comparable {
|
private enum ChatListFilterPresetEntrySortId: Comparable {
|
||||||
@ -83,6 +92,9 @@ private enum ChatListFilterPresetEntrySortId: Comparable {
|
|||||||
case topIndex(Int)
|
case topIndex(Int)
|
||||||
case includeIndex(Int)
|
case includeIndex(Int)
|
||||||
case excludeIndex(Int)
|
case excludeIndex(Int)
|
||||||
|
case bottomIndex(Int)
|
||||||
|
case inviteLink(Int)
|
||||||
|
case inviteLinkFooter
|
||||||
|
|
||||||
static func <(lhs: ChatListFilterPresetEntrySortId, rhs: ChatListFilterPresetEntrySortId) -> Bool {
|
static func <(lhs: ChatListFilterPresetEntrySortId, rhs: ChatListFilterPresetEntrySortId) -> Bool {
|
||||||
switch lhs {
|
switch lhs {
|
||||||
@ -103,6 +115,12 @@ private enum ChatListFilterPresetEntrySortId: Comparable {
|
|||||||
return true
|
return true
|
||||||
case .excludeIndex:
|
case .excludeIndex:
|
||||||
return true
|
return true
|
||||||
|
case .bottomIndex:
|
||||||
|
return true
|
||||||
|
case .inviteLink:
|
||||||
|
return true
|
||||||
|
case .inviteLinkFooter:
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
case let .includeIndex(lhsIndex):
|
case let .includeIndex(lhsIndex):
|
||||||
switch rhs {
|
switch rhs {
|
||||||
@ -114,6 +132,12 @@ private enum ChatListFilterPresetEntrySortId: Comparable {
|
|||||||
return lhsIndex < rhsIndex
|
return lhsIndex < rhsIndex
|
||||||
case .excludeIndex:
|
case .excludeIndex:
|
||||||
return true
|
return true
|
||||||
|
case .bottomIndex:
|
||||||
|
return true
|
||||||
|
case .inviteLink:
|
||||||
|
return true
|
||||||
|
case .inviteLinkFooter:
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
case let .excludeIndex(lhsIndex):
|
case let .excludeIndex(lhsIndex):
|
||||||
switch rhs {
|
switch rhs {
|
||||||
@ -125,6 +149,63 @@ private enum ChatListFilterPresetEntrySortId: Comparable {
|
|||||||
return false
|
return false
|
||||||
case let .excludeIndex(rhsIndex):
|
case let .excludeIndex(rhsIndex):
|
||||||
return lhsIndex < rhsIndex
|
return lhsIndex < rhsIndex
|
||||||
|
case .bottomIndex:
|
||||||
|
return true
|
||||||
|
case .inviteLink:
|
||||||
|
return true
|
||||||
|
case .inviteLinkFooter:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case let .bottomIndex(lhsIndex):
|
||||||
|
switch rhs {
|
||||||
|
case .screenHeader:
|
||||||
|
return false
|
||||||
|
case .topIndex:
|
||||||
|
return false
|
||||||
|
case .includeIndex:
|
||||||
|
return false
|
||||||
|
case .excludeIndex:
|
||||||
|
return false
|
||||||
|
case let .bottomIndex(rhsIndex):
|
||||||
|
return lhsIndex < rhsIndex
|
||||||
|
case .inviteLink:
|
||||||
|
return true
|
||||||
|
case .inviteLinkFooter:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case let .inviteLink(lhsIndex):
|
||||||
|
switch rhs {
|
||||||
|
case .screenHeader:
|
||||||
|
return false
|
||||||
|
case .topIndex:
|
||||||
|
return false
|
||||||
|
case .includeIndex:
|
||||||
|
return false
|
||||||
|
case .excludeIndex:
|
||||||
|
return false
|
||||||
|
case .bottomIndex:
|
||||||
|
return false
|
||||||
|
case let .inviteLink(rhsIndex):
|
||||||
|
return lhsIndex < rhsIndex
|
||||||
|
case .inviteLinkFooter:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case .inviteLinkFooter:
|
||||||
|
switch rhs {
|
||||||
|
case .screenHeader:
|
||||||
|
return false
|
||||||
|
case .topIndex:
|
||||||
|
return false
|
||||||
|
case .includeIndex:
|
||||||
|
return false
|
||||||
|
case .excludeIndex:
|
||||||
|
return false
|
||||||
|
case .bottomIndex:
|
||||||
|
return false
|
||||||
|
case .inviteLink:
|
||||||
|
return false
|
||||||
|
case .inviteLinkFooter:
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -235,6 +316,10 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
|
|||||||
case excludePeerInfo(String)
|
case excludePeerInfo(String)
|
||||||
case includeExpand(String)
|
case includeExpand(String)
|
||||||
case excludeExpand(String)
|
case excludeExpand(String)
|
||||||
|
case inviteLinkHeader
|
||||||
|
case inviteLinkCreate
|
||||||
|
case inviteLink(Int, ExportedChatFolderLink)
|
||||||
|
case inviteLinkInfo
|
||||||
|
|
||||||
var section: ItemListSectionId {
|
var section: ItemListSectionId {
|
||||||
switch self {
|
switch self {
|
||||||
@ -246,6 +331,8 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
|
|||||||
return ChatListFilterPresetControllerSection.includePeers.rawValue
|
return ChatListFilterPresetControllerSection.includePeers.rawValue
|
||||||
case .excludePeersHeader, .addExcludePeer, .excludeCategory, .excludePeer, .excludePeerInfo, .excludeExpand:
|
case .excludePeersHeader, .addExcludePeer, .excludeCategory, .excludePeer, .excludePeerInfo, .excludeExpand:
|
||||||
return ChatListFilterPresetControllerSection.excludePeers.rawValue
|
return ChatListFilterPresetControllerSection.excludePeers.rawValue
|
||||||
|
case .inviteLinkHeader, .inviteLinkCreate, .inviteLink, .inviteLinkInfo:
|
||||||
|
return ChatListFilterPresetControllerSection.inviteLinks.rawValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,6 +368,14 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
|
|||||||
return .peer(peer.peerId)
|
return .peer(peer.peerId)
|
||||||
case let .excludePeer(_, peer, _):
|
case let .excludePeer(_, peer, _):
|
||||||
return .peer(peer.peerId)
|
return .peer(peer.peerId)
|
||||||
|
case .inviteLinkHeader:
|
||||||
|
return .index(11)
|
||||||
|
case .inviteLinkCreate:
|
||||||
|
return .index(12)
|
||||||
|
case let .inviteLink(_, link):
|
||||||
|
return .inviteLink(link.link)
|
||||||
|
case .inviteLinkInfo:
|
||||||
|
return .index(13)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,6 +411,14 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
|
|||||||
return .excludeIndex(999)
|
return .excludeIndex(999)
|
||||||
case .excludePeerInfo:
|
case .excludePeerInfo:
|
||||||
return .excludeIndex(1000)
|
return .excludeIndex(1000)
|
||||||
|
case .inviteLinkHeader:
|
||||||
|
return .bottomIndex(0)
|
||||||
|
case .inviteLinkCreate:
|
||||||
|
return .bottomIndex(1)
|
||||||
|
case let .inviteLink(index, _):
|
||||||
|
return .inviteLink(index)
|
||||||
|
case .inviteLinkInfo:
|
||||||
|
return .inviteLinkFooter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -413,6 +516,23 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
|
|||||||
return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.downArrowImage(presentationData.theme), title: text, sectionId: self.section, editing: false, action: {
|
return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.downArrowImage(presentationData.theme), title: text, sectionId: self.section, editing: false, action: {
|
||||||
arguments.expandSection(.exclude)
|
arguments.expandSection(.exclude)
|
||||||
})
|
})
|
||||||
|
case .inviteLinkHeader:
|
||||||
|
//TODO:localize
|
||||||
|
return ItemListSectionHeaderItem(presentationData: presentationData, text: "INVITE LINK", sectionId: self.section)
|
||||||
|
case .inviteLinkCreate:
|
||||||
|
//TODO:localize
|
||||||
|
return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.linkIcon(presentationData.theme), title: "Share Folder with Others", sectionId: self.section, editing: false, action: {
|
||||||
|
arguments.createLink()
|
||||||
|
})
|
||||||
|
case let .inviteLink(_, link):
|
||||||
|
return ItemListFolderInviteLinkListItem(presentationData: presentationData, invite: link, share: false, sectionId: self.section, style: .blocks) { invite in
|
||||||
|
arguments.openLink(invite)
|
||||||
|
} contextAction: { invite, node, gesture in
|
||||||
|
//arguments.linkContextAction(invite, canEdit, node, gesture)
|
||||||
|
}
|
||||||
|
case .inviteLinkInfo:
|
||||||
|
//TODO:localize
|
||||||
|
return ItemListTextItem(presentationData: presentationData, text: .markdown("Give vour friends and colleagues access to the entire folder including all of its groups and channels where you have the necessary rights."), sectionId: self.section)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -455,7 +575,7 @@ private struct ChatListFilterPresetControllerState: Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func chatListFilterPresetControllerEntries(presentationData: PresentationData, isNewFilter: Bool, state: ChatListFilterPresetControllerState, includePeers: [EngineRenderedPeer], excludePeers: [EngineRenderedPeer], isPremium: Bool, limit: Int32) -> [ChatListFilterPresetEntry] {
|
private func chatListFilterPresetControllerEntries(presentationData: PresentationData, isNewFilter: Bool, state: ChatListFilterPresetControllerState, includePeers: [EngineRenderedPeer], excludePeers: [EngineRenderedPeer], isPremium: Bool, limit: Int32, inviteLinks: [ExportedChatFolderLink]?) -> [ChatListFilterPresetEntry] {
|
||||||
var entries: [ChatListFilterPresetEntry] = []
|
var entries: [ChatListFilterPresetEntry] = []
|
||||||
|
|
||||||
if isNewFilter {
|
if isNewFilter {
|
||||||
@ -531,6 +651,19 @@ private func chatListFilterPresetControllerEntries(presentationData: Presentatio
|
|||||||
|
|
||||||
entries.append(.excludePeerInfo(presentationData.strings.ChatListFolder_ExcludeSectionInfo))
|
entries.append(.excludePeerInfo(presentationData.strings.ChatListFolder_ExcludeSectionInfo))
|
||||||
|
|
||||||
|
if !isNewFilter, let inviteLinks {
|
||||||
|
entries.append(.inviteLinkHeader)
|
||||||
|
entries.append(.inviteLinkCreate)
|
||||||
|
|
||||||
|
var index = 0
|
||||||
|
for link in inviteLinks {
|
||||||
|
entries.append(.inviteLink(index, link))
|
||||||
|
index += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
entries.append(.inviteLinkInfo)
|
||||||
|
}
|
||||||
|
|
||||||
return entries
|
return entries
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -887,7 +1020,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
|||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
var includePeers = ChatListFilterIncludePeers()
|
var includePeers = ChatListFilterIncludePeers()
|
||||||
includePeers.setPeers(state.additionallyIncludePeers)
|
includePeers.setPeers(state.additionallyIncludePeers)
|
||||||
let filter: ChatListFilter = .filter(id: currentPreset?.id ?? -1, title: state.name, emoticon: currentPreset?.emoticon, data: ChatListFilterData(categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: includePeers, excludePeers: state.additionallyExcludePeers))
|
let filter: ChatListFilter = .filter(id: currentPreset?.id ?? -1, title: state.name, emoticon: currentPreset?.emoticon, data: ChatListFilterData(isShared: currentPreset?.data?.isShared ?? false, categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: includePeers, excludePeers: state.additionallyExcludePeers))
|
||||||
if let data = filter.data {
|
if let data = filter.data {
|
||||||
switch chatListFilterType(data) {
|
switch chatListFilterType(data) {
|
||||||
case .generic:
|
case .generic:
|
||||||
@ -924,6 +1057,12 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
|||||||
var dismissImpl: (() -> Void)?
|
var dismissImpl: (() -> Void)?
|
||||||
var focusOnNameImpl: (() -> Void)?
|
var focusOnNameImpl: (() -> Void)?
|
||||||
|
|
||||||
|
let sharedLinks = Promise<[ExportedChatFolderLink]?>(nil)
|
||||||
|
if let currentPreset {
|
||||||
|
sharedLinks.set(context.engine.peers.getExportedChatLinks(id: currentPreset.id)
|
||||||
|
|> map(Optional.init))
|
||||||
|
}
|
||||||
|
|
||||||
let currentPeers = Atomic<[PeerId: EngineRenderedPeer]>(value: [:])
|
let currentPeers = Atomic<[PeerId: EngineRenderedPeer]>(value: [:])
|
||||||
let stateWithPeers = statePromise.get()
|
let stateWithPeers = statePromise.get()
|
||||||
|> mapToSignal { state -> Signal<(ChatListFilterPresetControllerState, [EngineRenderedPeer], [EngineRenderedPeer]), NoError> in
|
|> mapToSignal { state -> Signal<(ChatListFilterPresetControllerState, [EngineRenderedPeer], [EngineRenderedPeer]), NoError> in
|
||||||
@ -1025,7 +1164,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
|||||||
let state = stateValue.with { $0 }
|
let state = stateValue.with { $0 }
|
||||||
var includePeers = ChatListFilterIncludePeers()
|
var includePeers = ChatListFilterIncludePeers()
|
||||||
includePeers.setPeers(state.additionallyIncludePeers)
|
includePeers.setPeers(state.additionallyIncludePeers)
|
||||||
let filter: ChatListFilter = .filter(id: currentPreset?.id ?? -1, title: state.name, emoticon: currentPreset?.emoticon, data: ChatListFilterData(categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: includePeers, excludePeers: state.additionallyExcludePeers))
|
let filter: ChatListFilter = .filter(id: currentPreset?.id ?? -1, title: state.name, emoticon: currentPreset?.emoticon, data: ChatListFilterData(isShared: currentPreset?.data?.isShared ?? false, categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: includePeers, excludePeers: state.additionallyExcludePeers))
|
||||||
|
|
||||||
let _ = (context.engine.peers.currentChatListFilters()
|
let _ = (context.engine.peers.currentChatListFilters()
|
||||||
|> deliverOnMainQueue).start(next: { filters in
|
|> deliverOnMainQueue).start(next: { filters in
|
||||||
@ -1047,7 +1186,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
|||||||
let state = stateValue.with { $0 }
|
let state = stateValue.with { $0 }
|
||||||
var includePeers = ChatListFilterIncludePeers()
|
var includePeers = ChatListFilterIncludePeers()
|
||||||
includePeers.setPeers(state.additionallyIncludePeers)
|
includePeers.setPeers(state.additionallyIncludePeers)
|
||||||
let filter: ChatListFilter = .filter(id: currentPreset?.id ?? -1, title: state.name, emoticon: currentPreset?.emoticon, data: ChatListFilterData(categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: includePeers, excludePeers: state.additionallyExcludePeers))
|
let filter: ChatListFilter = .filter(id: currentPreset?.id ?? -1, title: state.name, emoticon: currentPreset?.emoticon, data: ChatListFilterData(isShared: currentPreset?.data?.isShared ?? false, categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: includePeers, excludePeers: state.additionallyExcludePeers))
|
||||||
|
|
||||||
let _ = (context.engine.peers.currentChatListFilters()
|
let _ = (context.engine.peers.currentChatListFilters()
|
||||||
|> deliverOnMainQueue).start(next: { filters in
|
|> deliverOnMainQueue).start(next: { filters in
|
||||||
@ -1124,6 +1263,24 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
|||||||
state.expandedSections.insert(section)
|
state.expandedSections.insert(section)
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
createLink: {
|
||||||
|
if let currentPreset, let data = currentPreset.data, !data.includePeers.peers.isEmpty {
|
||||||
|
pushControllerImpl?(folderInviteLinkListController(context: context, filterId: currentPreset.id, allPeerIds: data.includePeers.peers, currentInvitation: nil))
|
||||||
|
|
||||||
|
/*if data.isShared {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
let _ = (context.engine.peers.exportChatFolder(filterId: currentPreset.id, title: "Link", peerIds: data.includePeers.peers)
|
||||||
|
|> deliverOnMainQueue).start(completed: {
|
||||||
|
dismissImpl?()
|
||||||
|
})
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}, openLink: { link in
|
||||||
|
if let currentPreset, let data = currentPreset.data {
|
||||||
|
pushControllerImpl?(folderInviteLinkListController(context: context, filterId: currentPreset.id, allPeerIds: data.includePeers.peers, currentInvitation: link))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1138,7 +1295,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
|||||||
if currentPreset == nil {
|
if currentPreset == nil {
|
||||||
filterId = context.engine.peers.generateNewChatListFilterId(filters: filters)
|
filterId = context.engine.peers.generateNewChatListFilterId(filters: filters)
|
||||||
}
|
}
|
||||||
var updatedFilter: ChatListFilter = .filter(id: filterId, title: state.name, emoticon: currentPreset?.emoticon, data: ChatListFilterData(categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: includePeers, excludePeers: state.additionallyExcludePeers))
|
var updatedFilter: ChatListFilter = .filter(id: filterId, title: state.name, emoticon: currentPreset?.emoticon, data: ChatListFilterData(isShared: currentPreset?.data?.isShared ?? false, categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: includePeers, excludePeers: state.additionallyExcludePeers))
|
||||||
|
|
||||||
var filters = filters
|
var filters = filters
|
||||||
if let _ = currentPreset {
|
if let _ = currentPreset {
|
||||||
@ -1182,10 +1339,11 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
|||||||
context.account.postbox.peerView(id: context.account.peerId),
|
context.account.postbox.peerView(id: context.account.peerId),
|
||||||
context.engine.data.get(
|
context.engine.data.get(
|
||||||
TelegramEngine.EngineData.Item.Configuration.UserLimits(isPremium: true)
|
TelegramEngine.EngineData.Item.Configuration.UserLimits(isPremium: true)
|
||||||
)
|
),
|
||||||
|
sharedLinks.get()
|
||||||
)
|
)
|
||||||
|> deliverOnMainQueue
|
|> deliverOnMainQueue
|
||||||
|> map { presentationData, stateWithPeers, peerView, premiumLimits -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
|> map { presentationData, stateWithPeers, peerView, premiumLimits, sharedLinks -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||||
let (state, includePeers, excludePeers) = stateWithPeers
|
let (state, includePeers, excludePeers) = stateWithPeers
|
||||||
|
|
||||||
let isPremium = peerView.peers[peerView.peerId]?.isPremium ?? false
|
let isPremium = peerView.peers[peerView.peerId]?.isPremium ?? false
|
||||||
@ -1206,7 +1364,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
|||||||
}
|
}
|
||||||
|
|
||||||
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(currentPreset != nil ? presentationData.strings.ChatListFolder_TitleEdit : presentationData.strings.ChatListFolder_TitleCreate), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
|
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(currentPreset != nil ? presentationData.strings.ChatListFolder_TitleEdit : presentationData.strings.ChatListFolder_TitleCreate), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
|
||||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: chatListFilterPresetControllerEntries(presentationData: presentationData, isNewFilter: currentPreset == nil, state: state, includePeers: includePeers, excludePeers: excludePeers, isPremium: isPremium, limit: premiumLimits.maxFolderChatsCount), style: .blocks, emptyStateItem: nil, animateChanges: !skipStateAnimation)
|
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: chatListFilterPresetControllerEntries(presentationData: presentationData, isNewFilter: currentPreset == nil, state: state, includePeers: includePeers, excludePeers: excludePeers, isPremium: isPremium, limit: premiumLimits.maxFolderChatsCount, inviteLinks: sharedLinks), style: .blocks, emptyStateItem: nil, animateChanges: !skipStateAnimation)
|
||||||
skipStateAnimation = false
|
skipStateAnimation = false
|
||||||
|
|
||||||
return (controllerState, (listState, arguments))
|
return (controllerState, (listState, arguments))
|
||||||
@ -1261,7 +1419,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
|||||||
|
|
||||||
var includePeers = ChatListFilterIncludePeers()
|
var includePeers = ChatListFilterIncludePeers()
|
||||||
includePeers.setPeers(state.additionallyIncludePeers)
|
includePeers.setPeers(state.additionallyIncludePeers)
|
||||||
let filter: ChatListFilter = .filter(id: currentPreset.id, title: state.name, emoticon: currentPreset.emoticon, data: ChatListFilterData(categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: includePeers, excludePeers: state.additionallyExcludePeers))
|
let filter: ChatListFilter = .filter(id: currentPreset.id, title: state.name, emoticon: currentPreset.emoticon, data: ChatListFilterData(isShared: currentPreset.data?.isShared ?? false, categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: includePeers, excludePeers: state.additionallyExcludePeers))
|
||||||
if currentPresetWithoutPinnedPeers != filter {
|
if currentPresetWithoutPinnedPeers != filter {
|
||||||
displaySaveAlert()
|
displaySaveAlert()
|
||||||
return false
|
return false
|
||||||
|
@ -56,8 +56,8 @@ private enum ChatListFilterPresetListEntryStableId: Hashable {
|
|||||||
case suggestedPreset(ChatListFilterData)
|
case suggestedPreset(ChatListFilterData)
|
||||||
case suggestedAddCustom
|
case suggestedAddCustom
|
||||||
case listHeader
|
case listHeader
|
||||||
case preset(Int32)
|
|
||||||
case addItem
|
case addItem
|
||||||
|
case preset(Int32)
|
||||||
case listFooter
|
case listFooter
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +75,6 @@ private enum ChatListFilterPresetListEntry: ItemListNodeEntry {
|
|||||||
case suggestedPreset(index: PresetIndex, title: String, label: String, preset: ChatListFilterData)
|
case suggestedPreset(index: PresetIndex, title: String, label: String, preset: ChatListFilterData)
|
||||||
case suggestedAddCustom(String)
|
case suggestedAddCustom(String)
|
||||||
case listHeader(String)
|
case listHeader(String)
|
||||||
case addFolder
|
|
||||||
case preset(index: PresetIndex, title: String, label: String, preset: ChatListFilter, canBeReordered: Bool, canBeDeleted: Bool, isEditing: Bool, isAllChats: Bool, isDisabled: Bool)
|
case preset(index: PresetIndex, title: String, label: String, preset: ChatListFilter, canBeReordered: Bool, canBeDeleted: Bool, isEditing: Bool, isAllChats: Bool, isDisabled: Bool)
|
||||||
case addItem(text: String, isEditing: Bool)
|
case addItem(text: String, isEditing: Bool)
|
||||||
case listFooter(String)
|
case listFooter(String)
|
||||||
@ -86,7 +85,7 @@ private enum ChatListFilterPresetListEntry: ItemListNodeEntry {
|
|||||||
return ChatListFilterPresetListSection.screenHeader.rawValue
|
return ChatListFilterPresetListSection.screenHeader.rawValue
|
||||||
case .suggestedListHeader, .suggestedPreset, .suggestedAddCustom:
|
case .suggestedListHeader, .suggestedPreset, .suggestedAddCustom:
|
||||||
return ChatListFilterPresetListSection.suggested.rawValue
|
return ChatListFilterPresetListSection.suggested.rawValue
|
||||||
case .listHeader, .addFolder, .preset, .addItem, .listFooter:
|
case .listHeader, .preset, .addItem, .listFooter:
|
||||||
return ChatListFilterPresetListSection.list.rawValue
|
return ChatListFilterPresetListSection.list.rawValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,471 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import Display
|
||||||
|
import SwiftSignalKit
|
||||||
|
import Postbox
|
||||||
|
import TelegramCore
|
||||||
|
import TelegramPresentationData
|
||||||
|
import TelegramUIPreferences
|
||||||
|
import ItemListUI
|
||||||
|
import PresentationDataUtils
|
||||||
|
import OverlayStatusController
|
||||||
|
import AccountContext
|
||||||
|
import AlertUI
|
||||||
|
import PresentationDataUtils
|
||||||
|
import AppBundle
|
||||||
|
import ContextUI
|
||||||
|
import TelegramStringFormatting
|
||||||
|
import ItemListPeerActionItem
|
||||||
|
import ItemListPeerItem
|
||||||
|
import ShareController
|
||||||
|
import UndoUI
|
||||||
|
import QrCodeUI
|
||||||
|
|
||||||
|
private final class FolderInviteLinkListControllerArguments {
|
||||||
|
let context: AccountContext
|
||||||
|
let shareMainLink: (String) -> Void
|
||||||
|
let openMainLink: (String) -> Void
|
||||||
|
let copyLink: (String) -> Void
|
||||||
|
let mainLinkContextAction: (String?, ASDisplayNode, ContextGesture?) -> Void
|
||||||
|
let peerAction: (EnginePeer) -> Void
|
||||||
|
let generateLink: () -> Void
|
||||||
|
|
||||||
|
init(
|
||||||
|
context: AccountContext,
|
||||||
|
shareMainLink: @escaping (String) -> Void,
|
||||||
|
openMainLink: @escaping (String) -> Void,
|
||||||
|
copyLink: @escaping (String) -> Void,
|
||||||
|
mainLinkContextAction: @escaping (String?, ASDisplayNode, ContextGesture?) -> Void,
|
||||||
|
peerAction: @escaping (EnginePeer) -> Void,
|
||||||
|
generateLink: @escaping () -> Void
|
||||||
|
) {
|
||||||
|
self.context = context
|
||||||
|
self.shareMainLink = shareMainLink
|
||||||
|
self.openMainLink = openMainLink
|
||||||
|
self.copyLink = copyLink
|
||||||
|
self.mainLinkContextAction = mainLinkContextAction
|
||||||
|
self.peerAction = peerAction
|
||||||
|
self.generateLink = generateLink
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum InviteLinksListSection: Int32 {
|
||||||
|
case header
|
||||||
|
case mainLink
|
||||||
|
case peers
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum InviteLinksListEntry: ItemListNodeEntry {
|
||||||
|
enum StableId: Hashable {
|
||||||
|
case index(Int)
|
||||||
|
case peer(EnginePeer.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
case header(String)
|
||||||
|
|
||||||
|
case mainLinkHeader(String)
|
||||||
|
case mainLink(link: ExportedChatFolderLink?, isGenerating: Bool)
|
||||||
|
|
||||||
|
case peersHeader(String)
|
||||||
|
case peer(index: Int, peer: EnginePeer, isSelected: Bool)
|
||||||
|
case peersInfo(String)
|
||||||
|
|
||||||
|
var section: ItemListSectionId {
|
||||||
|
switch self {
|
||||||
|
case .header:
|
||||||
|
return InviteLinksListSection.header.rawValue
|
||||||
|
case .mainLinkHeader, .mainLink:
|
||||||
|
return InviteLinksListSection.mainLink.rawValue
|
||||||
|
case .peersHeader, .peer, .peersInfo:
|
||||||
|
return InviteLinksListSection.peers.rawValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var stableId: StableId {
|
||||||
|
switch self {
|
||||||
|
case .header:
|
||||||
|
return .index(0)
|
||||||
|
case .mainLinkHeader:
|
||||||
|
return .index(1)
|
||||||
|
case .mainLink:
|
||||||
|
return .index(2)
|
||||||
|
case .peersHeader:
|
||||||
|
return .index(4)
|
||||||
|
case .peersInfo:
|
||||||
|
return .index(5)
|
||||||
|
case let .peer(_, peer, _):
|
||||||
|
return .peer(peer.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var sortIndex: Int {
|
||||||
|
switch self {
|
||||||
|
case .header:
|
||||||
|
return 0
|
||||||
|
case .mainLinkHeader:
|
||||||
|
return 1
|
||||||
|
case .mainLink:
|
||||||
|
return 2
|
||||||
|
case .peersHeader:
|
||||||
|
return 4
|
||||||
|
case let .peer(index, _, _):
|
||||||
|
return 10 + index
|
||||||
|
case .peersInfo:
|
||||||
|
return 1000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func ==(lhs: InviteLinksListEntry, rhs: InviteLinksListEntry) -> Bool {
|
||||||
|
switch lhs {
|
||||||
|
case let .header(text):
|
||||||
|
if case .header(text) = rhs {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case let .mainLinkHeader(text):
|
||||||
|
if case .mainLinkHeader(text) = rhs {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case let .mainLink(lhsLink, lhsIsGenerating):
|
||||||
|
if case let .mainLink(rhsLink, rhsIsGenerating) = rhs, lhsLink == rhsLink, lhsIsGenerating == rhsIsGenerating {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case let .peersHeader(text):
|
||||||
|
if case .peersHeader(text) = rhs {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case let .peersInfo(text):
|
||||||
|
if case .peersInfo(text) = rhs {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case let .peer(index, peer, isSelected):
|
||||||
|
if case .peer(index, peer, isSelected) = rhs {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func <(lhs: InviteLinksListEntry, rhs: InviteLinksListEntry) -> Bool {
|
||||||
|
return lhs.sortIndex < rhs.sortIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
|
||||||
|
let arguments = arguments as! FolderInviteLinkListControllerArguments
|
||||||
|
switch self {
|
||||||
|
case let .header(text):
|
||||||
|
return InviteLinkHeaderItem(context: arguments.context, theme: presentationData.theme, text: text, animationName: "ChatListNewFolder", sectionId: self.section)
|
||||||
|
case let .mainLinkHeader(text):
|
||||||
|
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||||
|
case let .mainLink(link, isGenerating):
|
||||||
|
return ItemListFolderInviteLinkItem(context: arguments.context, presentationData: presentationData, invite: link, count: 0, peers: [], displayButton: true, enableButton: !isGenerating, buttonTitle: link != nil ? "Share Invite Link" : "Generate Invite Link", displayImporters: false, buttonColor: nil, sectionId: self.section, style: .blocks, copyAction: {
|
||||||
|
if let link {
|
||||||
|
arguments.copyLink(link.link)
|
||||||
|
}
|
||||||
|
}, shareAction: {
|
||||||
|
if let link {
|
||||||
|
arguments.shareMainLink(link.link)
|
||||||
|
} else {
|
||||||
|
arguments.generateLink()
|
||||||
|
}
|
||||||
|
}, contextAction: { node, gesture in
|
||||||
|
arguments.mainLinkContextAction(link?.link, node, gesture)
|
||||||
|
}, viewAction: {
|
||||||
|
if let link {
|
||||||
|
arguments.openMainLink(link.link)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
case let .peersHeader(text):
|
||||||
|
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||||
|
case let .peersInfo(text):
|
||||||
|
return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section)
|
||||||
|
case let .peer(_, peer, isSelected):
|
||||||
|
return ItemListPeerItem(
|
||||||
|
presentationData: presentationData,
|
||||||
|
dateTimeFormat: PresentationDateTimeFormat(),
|
||||||
|
nameDisplayOrder: presentationData.nameDisplayOrder,
|
||||||
|
context: arguments.context,
|
||||||
|
peer: peer,
|
||||||
|
presence: nil,
|
||||||
|
text: .none,
|
||||||
|
label: .none,
|
||||||
|
editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false),
|
||||||
|
switchValue: ItemListPeerItemSwitch(value: isSelected, style: .leftCheck),
|
||||||
|
enabled: true,
|
||||||
|
selectable: true,
|
||||||
|
sectionId: self.section,
|
||||||
|
action: {
|
||||||
|
arguments.peerAction(peer)
|
||||||
|
},
|
||||||
|
setPeerIdWithRevealedOptions: { _, _ in
|
||||||
|
},
|
||||||
|
removePeer: { _ in
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func folderInviteLinkListControllerEntries(
|
||||||
|
presentationData: PresentationData,
|
||||||
|
state: FolderInviteLinkListControllerState,
|
||||||
|
allPeers: [EnginePeer]
|
||||||
|
) -> [InviteLinksListEntry] {
|
||||||
|
var entries: [InviteLinksListEntry] = []
|
||||||
|
|
||||||
|
entries.append(.header("Anyone with this link can add Gaming Club folder and the 2 chats selected below."))
|
||||||
|
|
||||||
|
//TODO:localize
|
||||||
|
|
||||||
|
entries.append(.mainLinkHeader("INVITE LINK"))
|
||||||
|
entries.append(.mainLink(link: state.currentLink, isGenerating: state.generatingLink))
|
||||||
|
|
||||||
|
entries.append(.peersHeader("\(allPeers.count) CHATS SELECTED"))
|
||||||
|
for peer in allPeers {
|
||||||
|
entries.append(.peer(index: entries.count, peer: peer, isSelected: state.selectedPeerIds.contains(peer.id)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct FolderInviteLinkListControllerState: Equatable {
|
||||||
|
var currentLink: ExportedChatFolderLink?
|
||||||
|
var selectedPeerIds = Set<EnginePeer.Id>()
|
||||||
|
var generatingLink: Bool = false
|
||||||
|
}
|
||||||
|
|
||||||
|
public func folderInviteLinkListController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, filterId: Int32, allPeerIds: [PeerId], currentInvitation: ExportedChatFolderLink?) -> ViewController {
|
||||||
|
var pushControllerImpl: ((ViewController) -> Void)?
|
||||||
|
let _ = pushControllerImpl
|
||||||
|
var presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)?
|
||||||
|
var presentInGlobalOverlayImpl: ((ViewController) -> Void)?
|
||||||
|
|
||||||
|
var dismissTooltipsImpl: (() -> Void)?
|
||||||
|
|
||||||
|
let actionsDisposable = DisposableSet()
|
||||||
|
|
||||||
|
var initialState = FolderInviteLinkListControllerState()
|
||||||
|
initialState.currentLink = currentInvitation
|
||||||
|
for peerId in allPeerIds {
|
||||||
|
initialState.selectedPeerIds.insert(peerId)
|
||||||
|
}
|
||||||
|
let statePromise = ValuePromise(initialState, ignoreRepeated: true)
|
||||||
|
let stateValue = Atomic(value: initialState)
|
||||||
|
let updateState: ((FolderInviteLinkListControllerState) -> FolderInviteLinkListControllerState) -> Void = { f in
|
||||||
|
statePromise.set(stateValue.modify { f($0) })
|
||||||
|
}
|
||||||
|
let _ = updateState
|
||||||
|
|
||||||
|
let revokeLinkDisposable = MetaDisposable()
|
||||||
|
actionsDisposable.add(revokeLinkDisposable)
|
||||||
|
|
||||||
|
let deleteAllRevokedLinksDisposable = MetaDisposable()
|
||||||
|
actionsDisposable.add(deleteAllRevokedLinksDisposable)
|
||||||
|
|
||||||
|
var getControllerImpl: (() -> ViewController?)?
|
||||||
|
|
||||||
|
let arguments = FolderInviteLinkListControllerArguments(context: context, shareMainLink: { inviteLink in
|
||||||
|
let shareController = ShareController(context: context, subject: .url(inviteLink), updatedPresentationData: updatedPresentationData)
|
||||||
|
shareController.completed = { peerIds in
|
||||||
|
let _ = (context.engine.data.get(
|
||||||
|
EngineDataList(
|
||||||
|
peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|> deliverOnMainQueue).start(next: { peerList in
|
||||||
|
let peers = peerList.compactMap { $0 }
|
||||||
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
|
let text: String
|
||||||
|
var savedMessages = false
|
||||||
|
if peerIds.count == 1, let peerId = peerIds.first, peerId == context.account.peerId {
|
||||||
|
text = presentationData.strings.InviteLink_InviteLinkForwardTooltip_SavedMessages_One
|
||||||
|
savedMessages = true
|
||||||
|
} else {
|
||||||
|
if peers.count == 1, let peer = peers.first {
|
||||||
|
let peerName = peer.id == context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
||||||
|
text = presentationData.strings.InviteLink_InviteLinkForwardTooltip_Chat_One(peerName).string
|
||||||
|
} else if peers.count == 2, let firstPeer = peers.first, let secondPeer = peers.last {
|
||||||
|
let firstPeerName = firstPeer.id == context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
||||||
|
let secondPeerName = secondPeer.id == context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
||||||
|
text = presentationData.strings.InviteLink_InviteLinkForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).string
|
||||||
|
} else if let peer = peers.first {
|
||||||
|
let peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
||||||
|
text = presentationData.strings.InviteLink_InviteLinkForwardTooltip_ManyChats_One(peerName, "\(peers.count - 1)").string
|
||||||
|
} else {
|
||||||
|
text = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), nil)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
shareController.actionCompleted = {
|
||||||
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.InviteLink_InviteLinkCopiedText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||||
|
}
|
||||||
|
presentControllerImpl?(shareController, nil)
|
||||||
|
}, openMainLink: { _ in
|
||||||
|
}, copyLink: { link in
|
||||||
|
UIPasteboard.general.string = link
|
||||||
|
|
||||||
|
dismissTooltipsImpl?()
|
||||||
|
|
||||||
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.InviteLink_InviteLinkCopiedText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||||
|
}, mainLinkContextAction: { invite, node, gesture in
|
||||||
|
guard let node = node as? ContextReferenceContentNode, let controller = getControllerImpl?(), let invite = invite else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
var items: [ContextMenuItem] = []
|
||||||
|
|
||||||
|
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextCopy, icon: { theme in
|
||||||
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor)
|
||||||
|
}, action: { _, f in
|
||||||
|
f(.dismissWithoutContent)
|
||||||
|
|
||||||
|
dismissTooltipsImpl?()
|
||||||
|
|
||||||
|
UIPasteboard.general.string = invite
|
||||||
|
|
||||||
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.InviteLink_InviteLinkCopiedText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||||
|
})))
|
||||||
|
|
||||||
|
items.append(.action(ContextMenuActionItem(text: presentationData.strings.InviteLink_ContextGetQRCode, icon: { theme in
|
||||||
|
return generateTintedImage(image: UIImage(bundleImageName: "Settings/QrIcon"), color: theme.contextMenu.primaryColor)
|
||||||
|
}, action: { _, f in
|
||||||
|
f(.dismissWithoutContent)
|
||||||
|
|
||||||
|
//presentControllerImpl?(QrCodeScreen(context: context, updatedPresentationData: updatedPresentationData, subject: .invite(invite: invite, isGroup: isGroup)), nil)
|
||||||
|
})))
|
||||||
|
|
||||||
|
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .reference(InviteLinkContextReferenceContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
|
||||||
|
presentInGlobalOverlayImpl?(contextController)
|
||||||
|
}, peerAction: { peer in
|
||||||
|
updateState { state in
|
||||||
|
var state = state
|
||||||
|
|
||||||
|
if state.selectedPeerIds.contains(peer.id) {
|
||||||
|
state.selectedPeerIds.remove(peer.id)
|
||||||
|
} else {
|
||||||
|
state.selectedPeerIds.insert(peer.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
}, generateLink: {
|
||||||
|
let currentState = stateValue.with({ $0 })
|
||||||
|
if !currentState.generatingLink {
|
||||||
|
updateState { state in
|
||||||
|
var state = state
|
||||||
|
|
||||||
|
state.generatingLink = true
|
||||||
|
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
actionsDisposable.add((context.engine.peers.exportChatFolder(filterId: filterId, title: "Link", peerIds: Array(currentState.selectedPeerIds))
|
||||||
|
|> deliverOnMainQueue).start(next: { result in
|
||||||
|
updateState { state in
|
||||||
|
var state = state
|
||||||
|
|
||||||
|
state.generatingLink = false
|
||||||
|
state.currentLink = result
|
||||||
|
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
}, error: { _ in
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
let allPeers = context.engine.data.subscribe(
|
||||||
|
EngineDataList(allPeerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:)))
|
||||||
|
)
|
||||||
|
|
||||||
|
let presentationData = updatedPresentationData?.signal ?? context.sharedContext.presentationData
|
||||||
|
let signal = combineLatest(queue: .mainQueue(),
|
||||||
|
presentationData,
|
||||||
|
statePromise.get(),
|
||||||
|
allPeers
|
||||||
|
)
|
||||||
|
|> map { presentationData, state, allPeers -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||||
|
let crossfade = false
|
||||||
|
let animateChanges = false
|
||||||
|
|
||||||
|
//TODO:localize
|
||||||
|
let title: ItemListControllerTitle
|
||||||
|
title = .text("Share Folder")
|
||||||
|
|
||||||
|
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: title, leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
|
||||||
|
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: folderInviteLinkListControllerEntries(
|
||||||
|
presentationData: presentationData,
|
||||||
|
state: state,
|
||||||
|
allPeers: allPeers.compactMap { $0 }
|
||||||
|
), style: .blocks, emptyStateItem: nil, crossfadeState: crossfade, animateChanges: animateChanges)
|
||||||
|
|
||||||
|
return (controllerState, (listState, arguments))
|
||||||
|
}
|
||||||
|
|> afterDisposed {
|
||||||
|
actionsDisposable.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
let controller = ItemListController(context: context, state: signal)
|
||||||
|
controller.navigationPresentation = .modal
|
||||||
|
controller.willDisappear = { _ in
|
||||||
|
dismissTooltipsImpl?()
|
||||||
|
}
|
||||||
|
controller.didDisappear = { [weak controller] _ in
|
||||||
|
controller?.clearItemNodesHighlight(animated: true)
|
||||||
|
}
|
||||||
|
controller.visibleBottomContentOffsetChanged = { offset in
|
||||||
|
if case let .known(value) = offset, value < 40.0 {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pushControllerImpl = { [weak controller] c in
|
||||||
|
if let controller = controller {
|
||||||
|
(controller.navigationController as? NavigationController)?.pushViewController(c, animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
presentControllerImpl = { [weak controller] c, p in
|
||||||
|
if let controller = controller {
|
||||||
|
controller.present(c, in: .window(.root), with: p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
presentInGlobalOverlayImpl = { [weak controller] c in
|
||||||
|
if let controller = controller {
|
||||||
|
controller.presentInGlobalOverlay(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getControllerImpl = { [weak controller] in
|
||||||
|
return controller
|
||||||
|
}
|
||||||
|
dismissTooltipsImpl = { [weak controller] in
|
||||||
|
controller?.window?.forEachController({ controller in
|
||||||
|
if let controller = controller as? UndoOverlayController {
|
||||||
|
controller.dismissWithCommitAction()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
controller?.forEachController({ controller in
|
||||||
|
if let controller = controller as? UndoOverlayController {
|
||||||
|
controller.dismissWithCommitAction()
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return controller
|
||||||
|
}
|
@ -0,0 +1,586 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import Display
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import SwiftSignalKit
|
||||||
|
import AccountContext
|
||||||
|
import TelegramPresentationData
|
||||||
|
import ItemListUI
|
||||||
|
import SolidRoundedButtonNode
|
||||||
|
import AnimatedAvatarSetNode
|
||||||
|
import ShimmerEffect
|
||||||
|
import TelegramCore
|
||||||
|
|
||||||
|
private func actionButtonImage(color: UIColor) -> UIImage? {
|
||||||
|
return generateImage(CGSize(width: 24.0, height: 24.0), contextGenerator: { size, context in
|
||||||
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
|
|
||||||
|
context.setFillColor(color.cgColor)
|
||||||
|
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
|
||||||
|
|
||||||
|
context.setBlendMode(.clear)
|
||||||
|
context.fillEllipse(in: CGRect(origin: CGPoint(x: 4.0, y: 10.0), size: CGSize(width: 4.0, height: 4.0)))
|
||||||
|
context.fillEllipse(in: CGRect(origin: CGPoint(x: 10.0, y: 10.0), size: CGSize(width: 4.0, height: 4.0)))
|
||||||
|
context.fillEllipse(in: CGRect(origin: CGPoint(x: 16.0, y: 10.0), size: CGSize(width: 4.0, height: 4.0)))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ItemListFolderInviteLinkItem: ListViewItem, ItemListItem {
|
||||||
|
let context: AccountContext
|
||||||
|
let presentationData: ItemListPresentationData
|
||||||
|
let invite: ExportedChatFolderLink?
|
||||||
|
let count: Int32
|
||||||
|
let peers: [EnginePeer]
|
||||||
|
let displayButton: Bool
|
||||||
|
let enableButton: Bool
|
||||||
|
let buttonTitle: String
|
||||||
|
let displayImporters: Bool
|
||||||
|
let buttonColor: UIColor?
|
||||||
|
public let sectionId: ItemListSectionId
|
||||||
|
let style: ItemListStyle
|
||||||
|
let copyAction: (() -> Void)?
|
||||||
|
let shareAction: (() -> Void)?
|
||||||
|
let contextAction: ((ASDisplayNode, ContextGesture?) -> Void)?
|
||||||
|
let viewAction: (() -> Void)?
|
||||||
|
public let tag: ItemListItemTag?
|
||||||
|
|
||||||
|
public init(
|
||||||
|
context: AccountContext,
|
||||||
|
presentationData: ItemListPresentationData,
|
||||||
|
invite: ExportedChatFolderLink?,
|
||||||
|
count: Int32,
|
||||||
|
peers: [EnginePeer],
|
||||||
|
displayButton: Bool,
|
||||||
|
enableButton: Bool,
|
||||||
|
buttonTitle: String,
|
||||||
|
displayImporters: Bool,
|
||||||
|
buttonColor: UIColor?,
|
||||||
|
sectionId: ItemListSectionId,
|
||||||
|
style: ItemListStyle,
|
||||||
|
copyAction: (() -> Void)?,
|
||||||
|
shareAction: (() -> Void)?,
|
||||||
|
contextAction: ((ASDisplayNode, ContextGesture?) -> Void)?,
|
||||||
|
viewAction: (() -> Void)?,
|
||||||
|
tag: ItemListItemTag? = nil
|
||||||
|
) {
|
||||||
|
self.context = context
|
||||||
|
self.presentationData = presentationData
|
||||||
|
self.invite = invite
|
||||||
|
self.count = count
|
||||||
|
self.peers = peers
|
||||||
|
self.displayButton = displayButton
|
||||||
|
self.enableButton = enableButton
|
||||||
|
self.buttonTitle = buttonTitle
|
||||||
|
self.displayImporters = displayImporters
|
||||||
|
self.buttonColor = buttonColor
|
||||||
|
self.sectionId = sectionId
|
||||||
|
self.style = style
|
||||||
|
self.copyAction = copyAction
|
||||||
|
self.shareAction = shareAction
|
||||||
|
self.contextAction = contextAction
|
||||||
|
self.viewAction = viewAction
|
||||||
|
self.tag = tag
|
||||||
|
}
|
||||||
|
|
||||||
|
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||||
|
async {
|
||||||
|
let node = ItemListFolderInviteLinkItemNode()
|
||||||
|
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
||||||
|
|
||||||
|
node.contentSize = layout.contentSize
|
||||||
|
node.insets = layout.insets
|
||||||
|
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
completion(node, {
|
||||||
|
return (nil, { _ in apply() })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
if let nodeValue = node() as? ItemListFolderInviteLinkItemNode {
|
||||||
|
let makeLayout = nodeValue.asyncLayout()
|
||||||
|
|
||||||
|
async {
|
||||||
|
let (layout, apply) = makeLayout(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
completion(layout, { _ in
|
||||||
|
apply()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var selectable: Bool = false
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ItemListFolderInviteLinkItemNode: ListViewItemNode, ItemListItemNode {
|
||||||
|
private let backgroundNode: ASDisplayNode
|
||||||
|
private let topStripeNode: ASDisplayNode
|
||||||
|
private let bottomStripeNode: ASDisplayNode
|
||||||
|
private let maskNode: ASImageNode
|
||||||
|
|
||||||
|
private let fieldNode: ASImageNode
|
||||||
|
private let addressNode: TextNode
|
||||||
|
private let fieldButtonNode: HighlightTrackingButtonNode
|
||||||
|
private let referenceContainerNode: ContextReferenceContentNode
|
||||||
|
private let containerNode: ContextControllerSourceNode
|
||||||
|
private let addressButtonNode: HighlightTrackingButtonNode
|
||||||
|
private let addressButtonIconNode: ASImageNode
|
||||||
|
private var addressShimmerNode: ShimmerEffectNode?
|
||||||
|
private var shareButtonNode: SolidRoundedButtonNode?
|
||||||
|
|
||||||
|
private let avatarsButtonNode: HighlightTrackingButtonNode
|
||||||
|
private let avatarsContext: AnimatedAvatarSetContext
|
||||||
|
private var avatarsContent: AnimatedAvatarSetContext.Content?
|
||||||
|
private let avatarsNode: AnimatedAvatarSetNode
|
||||||
|
private let invitedPeersNode: TextNode
|
||||||
|
private var shimmerNode: ShimmerEffectNode?
|
||||||
|
private var absoluteLocation: (CGRect, CGSize)?
|
||||||
|
|
||||||
|
private let activateArea: AccessibilityAreaNode
|
||||||
|
|
||||||
|
private var item: ItemListFolderInviteLinkItem?
|
||||||
|
|
||||||
|
override public var canBeSelected: Bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
public var tag: ItemListItemTag? {
|
||||||
|
return self.item?.tag
|
||||||
|
}
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
self.backgroundNode = ASDisplayNode()
|
||||||
|
self.backgroundNode.isLayerBacked = true
|
||||||
|
self.backgroundNode.backgroundColor = .white
|
||||||
|
|
||||||
|
self.maskNode = ASImageNode()
|
||||||
|
|
||||||
|
self.topStripeNode = ASDisplayNode()
|
||||||
|
self.topStripeNode.isLayerBacked = true
|
||||||
|
|
||||||
|
self.bottomStripeNode = ASDisplayNode()
|
||||||
|
self.bottomStripeNode.isLayerBacked = true
|
||||||
|
|
||||||
|
self.fieldNode = ASImageNode()
|
||||||
|
self.fieldNode.displaysAsynchronously = false
|
||||||
|
self.fieldNode.displayWithoutProcessing = true
|
||||||
|
|
||||||
|
self.addressNode = TextNode()
|
||||||
|
self.addressNode.isUserInteractionEnabled = false
|
||||||
|
|
||||||
|
self.fieldButtonNode = HighlightTrackingButtonNode()
|
||||||
|
|
||||||
|
self.containerNode = ContextControllerSourceNode()
|
||||||
|
self.containerNode.animateScale = false
|
||||||
|
self.referenceContainerNode = ContextReferenceContentNode()
|
||||||
|
|
||||||
|
self.addressButtonNode = HighlightTrackingButtonNode()
|
||||||
|
self.addressButtonIconNode = ASImageNode()
|
||||||
|
self.addressButtonIconNode.contentMode = .center
|
||||||
|
self.addressButtonIconNode.displaysAsynchronously = false
|
||||||
|
self.addressButtonIconNode.displayWithoutProcessing = true
|
||||||
|
|
||||||
|
self.avatarsButtonNode = HighlightTrackingButtonNode()
|
||||||
|
self.avatarsContext = AnimatedAvatarSetContext()
|
||||||
|
self.avatarsNode = AnimatedAvatarSetNode()
|
||||||
|
self.invitedPeersNode = TextNode()
|
||||||
|
|
||||||
|
self.activateArea = AccessibilityAreaNode()
|
||||||
|
|
||||||
|
super.init(layerBacked: false, dynamicBounce: false)
|
||||||
|
|
||||||
|
self.addSubnode(self.fieldNode)
|
||||||
|
self.addSubnode(self.addressNode)
|
||||||
|
self.addSubnode(self.fieldButtonNode)
|
||||||
|
self.addSubnode(self.avatarsNode)
|
||||||
|
self.addSubnode(self.invitedPeersNode)
|
||||||
|
self.addSubnode(self.avatarsButtonNode)
|
||||||
|
|
||||||
|
self.containerNode.addSubnode(self.referenceContainerNode)
|
||||||
|
self.referenceContainerNode.addSubnode(self.addressButtonIconNode)
|
||||||
|
self.referenceContainerNode.addSubnode(self.addressButtonNode)
|
||||||
|
self.addSubnode(self.containerNode)
|
||||||
|
|
||||||
|
self.addSubnode(self.activateArea)
|
||||||
|
|
||||||
|
self.containerNode.activated = { [weak self] gesture, _ in
|
||||||
|
if let strongSelf = self, let item = strongSelf.item {
|
||||||
|
item.contextAction?(strongSelf.referenceContainerNode, gesture)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.fieldButtonNode.highligthedChanged = { [weak self] highlighted in
|
||||||
|
if let strongSelf = self {
|
||||||
|
if highlighted {
|
||||||
|
strongSelf.addressNode.layer.removeAnimation(forKey: "opacity")
|
||||||
|
strongSelf.addressNode.alpha = 0.4
|
||||||
|
} else {
|
||||||
|
strongSelf.addressNode.alpha = 1.0
|
||||||
|
strongSelf.addressNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.fieldButtonNode.addTarget(self, action: #selector(self.fieldButtonPressed), forControlEvents: .touchUpInside)
|
||||||
|
|
||||||
|
self.addressButtonNode.addTarget(self, action: #selector(self.addressButtonPressed), forControlEvents: .touchUpInside)
|
||||||
|
self.addressButtonNode.highligthedChanged = { [weak self] highlighted in
|
||||||
|
if let strongSelf = self {
|
||||||
|
if highlighted {
|
||||||
|
strongSelf.addressButtonIconNode.layer.removeAnimation(forKey: "opacity")
|
||||||
|
strongSelf.addressButtonIconNode.alpha = 0.4
|
||||||
|
} else {
|
||||||
|
strongSelf.addressButtonIconNode.alpha = 1.0
|
||||||
|
strongSelf.addressButtonIconNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.shareButtonNode?.pressed = { [weak self] in
|
||||||
|
if let strongSelf = self, let item = strongSelf.item {
|
||||||
|
item.shareAction?()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.avatarsButtonNode.highligthedChanged = { [weak self] highlighted in
|
||||||
|
if let strongSelf = self {
|
||||||
|
if highlighted {
|
||||||
|
strongSelf.avatarsNode.layer.removeAnimation(forKey: "opacity")
|
||||||
|
strongSelf.invitedPeersNode.layer.removeAnimation(forKey: "opacity")
|
||||||
|
strongSelf.avatarsNode.alpha = 0.4
|
||||||
|
strongSelf.invitedPeersNode.alpha = 0.4
|
||||||
|
} else {
|
||||||
|
strongSelf.avatarsNode.alpha = 1.0
|
||||||
|
strongSelf.invitedPeersNode.alpha = 1.0
|
||||||
|
strongSelf.avatarsNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
|
||||||
|
strongSelf.invitedPeersNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.avatarsButtonNode.addTarget(self, action: #selector(self.avatarsButtonPressed), forControlEvents: .touchUpInside)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func fieldButtonPressed() {
|
||||||
|
if let item = self.item {
|
||||||
|
item.copyAction?()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func addressButtonPressed() {
|
||||||
|
if let item = self.item {
|
||||||
|
item.contextAction?(self.referenceContainerNode, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func avatarsButtonPressed() {
|
||||||
|
if let item = self.item {
|
||||||
|
item.viewAction?()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func asyncLayout() -> (_ item: ItemListFolderInviteLinkItem, _ params: ListViewItemLayoutParams, _ insets: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
||||||
|
let makeAddressLayout = TextNode.asyncLayout(self.addressNode)
|
||||||
|
let makeInvitedPeersLayout = TextNode.asyncLayout(self.invitedPeersNode)
|
||||||
|
|
||||||
|
let currentItem = self.item
|
||||||
|
let avatarsContext = self.avatarsContext
|
||||||
|
|
||||||
|
return { item, params, neighbors in
|
||||||
|
var updatedTheme: PresentationTheme?
|
||||||
|
if currentItem?.presentationData.theme !== item.presentationData.theme {
|
||||||
|
updatedTheme = item.presentationData.theme
|
||||||
|
}
|
||||||
|
|
||||||
|
let contentSize: CGSize
|
||||||
|
let insets: UIEdgeInsets
|
||||||
|
let separatorHeight = UIScreenPixel
|
||||||
|
let itemBackgroundColor: UIColor
|
||||||
|
let itemSeparatorColor: UIColor
|
||||||
|
|
||||||
|
let leftInset = 16.0 + params.leftInset
|
||||||
|
let rightInset = 16.0 + params.rightInset
|
||||||
|
|
||||||
|
let titleColor: UIColor
|
||||||
|
titleColor = item.presentationData.theme.list.itemInputField.primaryColor
|
||||||
|
|
||||||
|
let alignCentrally = !"".isEmpty//!(item.invite?.link?.contains("joinchat") ?? true)
|
||||||
|
|
||||||
|
let addressFont = Font.regular(!alignCentrally && params.width == 320 ? floor(item.presentationData.fontSize.itemListBaseFontSize * 15.0 / 17.0) : item.presentationData.fontSize.itemListBaseFontSize)
|
||||||
|
let titleFont = Font.regular(item.presentationData.fontSize.itemListBaseFontSize)
|
||||||
|
|
||||||
|
let constrainedWidth = alignCentrally ? params.width - leftInset - rightInset - 90.0 : params.width - leftInset - rightInset - 60.0
|
||||||
|
|
||||||
|
let (addressLayout, addressApply) = makeAddressLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.invite.flatMap({ $0.link.replacingOccurrences(of: "https://", with: "") }) ?? "", font: addressFont, textColor: titleColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .middle, constrainedSize: CGSize(width: constrainedWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
|
let subtitle: String
|
||||||
|
let subtitleColor: UIColor
|
||||||
|
if item.count > 0 {
|
||||||
|
subtitle = item.presentationData.strings.InviteLink_PeopleJoined(item.count)
|
||||||
|
subtitleColor = item.presentationData.theme.list.itemAccentColor
|
||||||
|
} else {
|
||||||
|
subtitle = item.presentationData.strings.InviteLink_PeopleJoinedNone
|
||||||
|
subtitleColor = item.presentationData.theme.list.itemSecondaryTextColor
|
||||||
|
}
|
||||||
|
|
||||||
|
let (invitedPeersLayout, invitedPeersApply) = makeInvitedPeersLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: subtitle, font: titleFont, textColor: subtitleColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.rightInset - 20.0 - leftInset - rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
|
let avatarsContent = avatarsContext.update(peers: item.peers, animated: false)
|
||||||
|
|
||||||
|
let verticalInset: CGFloat = 16.0
|
||||||
|
let fieldHeight: CGFloat = 52.0
|
||||||
|
let fieldSpacing: CGFloat = 16.0
|
||||||
|
let buttonHeight: CGFloat = 50.0
|
||||||
|
|
||||||
|
var height = verticalInset * 2.0 + fieldHeight + fieldSpacing + buttonHeight + 54.0
|
||||||
|
|
||||||
|
switch item.style {
|
||||||
|
case .plain:
|
||||||
|
itemBackgroundColor = item.presentationData.theme.list.plainBackgroundColor
|
||||||
|
itemSeparatorColor = .clear
|
||||||
|
insets = UIEdgeInsets()
|
||||||
|
case .blocks:
|
||||||
|
itemBackgroundColor = item.presentationData.theme.list.itemBlocksBackgroundColor
|
||||||
|
itemSeparatorColor = item.presentationData.theme.list.itemBlocksSeparatorColor
|
||||||
|
insets = itemListNeighborsGroupedInsets(neighbors, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !item.displayImporters {
|
||||||
|
height -= 57.0
|
||||||
|
}
|
||||||
|
if !item.displayButton {
|
||||||
|
height -= 63.0
|
||||||
|
}
|
||||||
|
|
||||||
|
contentSize = CGSize(width: params.width, height: height)
|
||||||
|
|
||||||
|
let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets)
|
||||||
|
|
||||||
|
return (ListViewItemNodeLayout(contentSize: contentSize, insets: insets), { [weak self] in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.item = item
|
||||||
|
strongSelf.avatarsContent = avatarsContent
|
||||||
|
|
||||||
|
strongSelf.activateArea.frame = CGRect(origin: CGPoint(x: params.leftInset, y: 0.0), size: CGSize(width: params.width - params.leftInset - params.rightInset, height: layout.contentSize.height))
|
||||||
|
// strongSelf.activateArea.accessibilityLabel = item.title
|
||||||
|
// strongSelf.activateArea.accessibilityValue = item.label
|
||||||
|
strongSelf.activateArea.accessibilityTraits = []
|
||||||
|
|
||||||
|
if let _ = updatedTheme {
|
||||||
|
strongSelf.topStripeNode.backgroundColor = itemSeparatorColor
|
||||||
|
strongSelf.bottomStripeNode.backgroundColor = itemSeparatorColor
|
||||||
|
strongSelf.backgroundNode.backgroundColor = itemBackgroundColor
|
||||||
|
strongSelf.fieldNode.image = generateStretchableFilledCircleImage(diameter: 18.0, color: item.presentationData.theme.list.itemInputField.backgroundColor)
|
||||||
|
strongSelf.addressButtonIconNode.image = actionButtonImage(color: item.presentationData.theme.list.itemInputField.controlColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = addressApply()
|
||||||
|
let _ = invitedPeersApply()
|
||||||
|
|
||||||
|
switch item.style {
|
||||||
|
case .plain:
|
||||||
|
if strongSelf.backgroundNode.supernode != nil {
|
||||||
|
strongSelf.backgroundNode.removeFromSupernode()
|
||||||
|
}
|
||||||
|
if strongSelf.topStripeNode.supernode != nil {
|
||||||
|
strongSelf.topStripeNode.removeFromSupernode()
|
||||||
|
}
|
||||||
|
if strongSelf.bottomStripeNode.supernode == nil {
|
||||||
|
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0)
|
||||||
|
}
|
||||||
|
if strongSelf.maskNode.supernode != nil {
|
||||||
|
strongSelf.maskNode.removeFromSupernode()
|
||||||
|
}
|
||||||
|
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - leftInset, height: separatorHeight))
|
||||||
|
case .blocks:
|
||||||
|
if strongSelf.backgroundNode.supernode == nil {
|
||||||
|
strongSelf.insertSubnode(strongSelf.backgroundNode, at: 0)
|
||||||
|
}
|
||||||
|
if strongSelf.topStripeNode.supernode == nil {
|
||||||
|
strongSelf.insertSubnode(strongSelf.topStripeNode, at: 1)
|
||||||
|
}
|
||||||
|
if strongSelf.bottomStripeNode.supernode == nil {
|
||||||
|
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
|
||||||
|
}
|
||||||
|
if strongSelf.maskNode.supernode == nil {
|
||||||
|
strongSelf.insertSubnode(strongSelf.maskNode, at: 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
let hasCorners = itemListHasRoundedBlockLayout(params)
|
||||||
|
var hasTopCorners = false
|
||||||
|
var hasBottomCorners = false
|
||||||
|
switch neighbors.top {
|
||||||
|
case .sameSection(false):
|
||||||
|
strongSelf.topStripeNode.isHidden = true
|
||||||
|
default:
|
||||||
|
hasTopCorners = true
|
||||||
|
strongSelf.topStripeNode.isHidden = hasCorners
|
||||||
|
}
|
||||||
|
let bottomStripeInset: CGFloat
|
||||||
|
switch neighbors.bottom {
|
||||||
|
case .sameSection(false):
|
||||||
|
bottomStripeInset = leftInset
|
||||||
|
strongSelf.bottomStripeNode.isHidden = false
|
||||||
|
default:
|
||||||
|
bottomStripeInset = 0.0
|
||||||
|
hasBottomCorners = true
|
||||||
|
strongSelf.bottomStripeNode.isHidden = hasCorners
|
||||||
|
}
|
||||||
|
|
||||||
|
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil
|
||||||
|
|
||||||
|
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
|
||||||
|
strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0)
|
||||||
|
strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: separatorHeight))
|
||||||
|
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - bottomStripeInset, height: separatorHeight))
|
||||||
|
}
|
||||||
|
|
||||||
|
let fieldFrame = CGRect(origin: CGPoint(x: leftInset, y: verticalInset), size: CGSize(width: params.width - leftInset - rightInset, height: fieldHeight))
|
||||||
|
strongSelf.fieldNode.frame = fieldFrame
|
||||||
|
strongSelf.fieldButtonNode.frame = fieldFrame
|
||||||
|
|
||||||
|
strongSelf.addressNode.frame = CGRect(origin: CGPoint(x: fieldFrame.minX + (alignCentrally ? floorToScreenPixels((fieldFrame.width - addressLayout.size.width) / 2.0) : 14.0), y: fieldFrame.minY + floorToScreenPixels((fieldFrame.height - addressLayout.size.height) / 2.0) + 1.0), size: addressLayout.size)
|
||||||
|
|
||||||
|
strongSelf.containerNode.frame = CGRect(origin: CGPoint(x: params.width - rightInset - 38.0 - 14.0, y: verticalInset), size: CGSize(width: 52.0, height: 52.0))
|
||||||
|
strongSelf.addressButtonNode.frame = strongSelf.containerNode.bounds
|
||||||
|
strongSelf.referenceContainerNode.frame = strongSelf.containerNode.bounds
|
||||||
|
strongSelf.addressButtonIconNode.frame = strongSelf.containerNode.bounds
|
||||||
|
|
||||||
|
let shareButtonNode: SolidRoundedButtonNode
|
||||||
|
if let currentShareButtonNode = strongSelf.shareButtonNode {
|
||||||
|
shareButtonNode = currentShareButtonNode
|
||||||
|
} else {
|
||||||
|
let buttonTheme: SolidRoundedButtonTheme
|
||||||
|
if let buttonColor = item.buttonColor {
|
||||||
|
buttonTheme = SolidRoundedButtonTheme(backgroundColor: buttonColor, foregroundColor: item.presentationData.theme.list.itemCheckColors.foregroundColor)
|
||||||
|
} else {
|
||||||
|
buttonTheme = SolidRoundedButtonTheme(theme: item.presentationData.theme)
|
||||||
|
}
|
||||||
|
shareButtonNode = SolidRoundedButtonNode(theme: buttonTheme, height: 50.0, cornerRadius: 11.0)
|
||||||
|
shareButtonNode.pressed = { [weak self] in
|
||||||
|
self?.item?.shareAction?()
|
||||||
|
}
|
||||||
|
strongSelf.addSubnode(shareButtonNode)
|
||||||
|
strongSelf.shareButtonNode = shareButtonNode
|
||||||
|
}
|
||||||
|
|
||||||
|
shareButtonNode.title = item.buttonTitle
|
||||||
|
|
||||||
|
let buttonWidth = contentSize.width - leftInset - rightInset
|
||||||
|
let _ = shareButtonNode.updateLayout(width: buttonWidth, transition: .immediate)
|
||||||
|
shareButtonNode.frame = CGRect(x: leftInset, y: verticalInset + fieldHeight + fieldSpacing, width: buttonWidth, height: buttonHeight)
|
||||||
|
|
||||||
|
var totalWidth = invitedPeersLayout.size.width
|
||||||
|
var leftOrigin: CGFloat = floorToScreenPixels((params.width - invitedPeersLayout.size.width) / 2.0)
|
||||||
|
let avatarSpacing: CGFloat = 21.0
|
||||||
|
if let avatarsContent = strongSelf.avatarsContent {
|
||||||
|
let avatarsSize = strongSelf.avatarsNode.update(context: item.context, content: avatarsContent, itemSize: CGSize(width: 32.0, height: 32.0), animated: true, synchronousLoad: true)
|
||||||
|
|
||||||
|
if !avatarsSize.width.isZero {
|
||||||
|
totalWidth += avatarsSize.width + avatarSpacing
|
||||||
|
}
|
||||||
|
|
||||||
|
let avatarsNodeFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((params.width - totalWidth) / 2.0), y: fieldFrame.maxY + 87.0), size: avatarsSize)
|
||||||
|
strongSelf.avatarsNode.frame = avatarsNodeFrame
|
||||||
|
if !avatarsSize.width.isZero {
|
||||||
|
leftOrigin = avatarsNodeFrame.maxX + avatarSpacing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
strongSelf.invitedPeersNode.frame = CGRect(origin: CGPoint(x: leftOrigin, y: fieldFrame.maxY + 92.0), size: invitedPeersLayout.size)
|
||||||
|
|
||||||
|
strongSelf.avatarsButtonNode.frame = CGRect(x: floorToScreenPixels((params.width - totalWidth) / 2.0), y: fieldFrame.maxY + 87.0, width: totalWidth, height: 32.0)
|
||||||
|
strongSelf.avatarsButtonNode.isUserInteractionEnabled = !item.peers.isEmpty && item.invite != nil
|
||||||
|
|
||||||
|
strongSelf.addressButtonNode.isUserInteractionEnabled = item.invite != nil
|
||||||
|
strongSelf.fieldButtonNode.isUserInteractionEnabled = item.invite != nil
|
||||||
|
strongSelf.addressButtonIconNode.alpha = item.invite != nil ? 1.0 : 0.0
|
||||||
|
|
||||||
|
strongSelf.shareButtonNode?.isUserInteractionEnabled = item.enableButton
|
||||||
|
strongSelf.shareButtonNode?.alpha = item.enableButton ? 1.0 : 0.4
|
||||||
|
strongSelf.shareButtonNode?.isHidden = !item.displayButton
|
||||||
|
strongSelf.avatarsButtonNode.isHidden = !item.displayImporters
|
||||||
|
strongSelf.avatarsNode.isHidden = !item.displayImporters || item.invite == nil
|
||||||
|
strongSelf.invitedPeersNode.isHidden = !item.displayImporters || item.invite == nil
|
||||||
|
|
||||||
|
if item.invite == nil {
|
||||||
|
let shimmerNode: ShimmerEffectNode
|
||||||
|
if let current = strongSelf.shimmerNode {
|
||||||
|
shimmerNode = current
|
||||||
|
} else {
|
||||||
|
shimmerNode = ShimmerEffectNode()
|
||||||
|
strongSelf.shimmerNode = shimmerNode
|
||||||
|
strongSelf.insertSubnode(shimmerNode, belowSubnode: strongSelf.fieldNode)
|
||||||
|
}
|
||||||
|
shimmerNode.frame = CGRect(origin: CGPoint(), size: layout.contentSize)
|
||||||
|
if let (rect, size) = strongSelf.absoluteLocation {
|
||||||
|
shimmerNode.updateAbsoluteRect(rect, within: size)
|
||||||
|
}
|
||||||
|
|
||||||
|
let lineWidth: CGFloat = 180.0
|
||||||
|
let lineDiameter: CGFloat = 12.0
|
||||||
|
let titleFrame = strongSelf.invitedPeersNode.frame
|
||||||
|
|
||||||
|
var shapes: [ShimmerEffectNode.Shape] = []
|
||||||
|
shapes.append(.roundedRectLine(startPoint: CGPoint(x: floor(titleFrame.center.x - lineWidth / 2.0), y: titleFrame.minY + floor((titleFrame.height - lineDiameter) / 2.0)), width: lineWidth, diameter: lineDiameter))
|
||||||
|
shimmerNode.update(backgroundColor: item.presentationData.theme.list.itemBlocksBackgroundColor, foregroundColor: item.presentationData.theme.list.mediaPlaceholderColor, shimmeringColor: item.presentationData.theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), shapes: shapes, size: layout.contentSize)
|
||||||
|
|
||||||
|
let addressShimmerNode: ShimmerEffectNode
|
||||||
|
if let current = strongSelf.addressShimmerNode {
|
||||||
|
addressShimmerNode = current
|
||||||
|
} else {
|
||||||
|
addressShimmerNode = ShimmerEffectNode()
|
||||||
|
strongSelf.addressShimmerNode = addressShimmerNode
|
||||||
|
strongSelf.insertSubnode(addressShimmerNode, aboveSubnode: strongSelf.fieldNode)
|
||||||
|
}
|
||||||
|
addressShimmerNode.frame = strongSelf.fieldNode.frame.insetBy(dx: 18.0, dy: 0.0)
|
||||||
|
if let (rect, size) = strongSelf.absoluteLocation {
|
||||||
|
addressShimmerNode.updateAbsoluteRect(CGRect(x: rect.minX + strongSelf.fieldNode.frame.minX + 18.0, y: rect.minY + strongSelf.fieldNode.frame.minY, width: strongSelf.fieldNode.frame.width - 18.0 * 2.0, height: strongSelf.fieldNode.frame.height), within: size)
|
||||||
|
}
|
||||||
|
|
||||||
|
let addressLineWidth: CGFloat = strongSelf.fieldNode.frame.width - 100.0
|
||||||
|
var addressShapes: [ShimmerEffectNode.Shape] = []
|
||||||
|
addressShapes.append(.roundedRectLine(startPoint: CGPoint(x: floor(addressShimmerNode.frame.width / 2.0 - addressLineWidth / 2.0), y: 16.0 + floor((22.0 - lineDiameter) / 2.0)), width: addressLineWidth, diameter: lineDiameter))
|
||||||
|
addressShimmerNode.update(backgroundColor: item.presentationData.theme.list.itemInputField.backgroundColor, foregroundColor: item.presentationData.theme.list.itemInputField.controlColor.mixedWith(item.presentationData.theme.list.itemInputField.backgroundColor, alpha: 0.7), shimmeringColor: item.presentationData.theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), shapes: addressShapes, size: addressShimmerNode.frame.size)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if let shimmerNode = strongSelf.shimmerNode {
|
||||||
|
strongSelf.shimmerNode = nil
|
||||||
|
shimmerNode.removeFromSupernode()
|
||||||
|
}
|
||||||
|
if let shimmerNode = strongSelf.addressShimmerNode {
|
||||||
|
strongSelf.shimmerNode = nil
|
||||||
|
shimmerNode.removeFromSupernode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
||||||
|
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func animateAdded(_ currentTimestamp: Double, duration: Double) {
|
||||||
|
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||||
|
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
|
||||||
|
var rect = rect
|
||||||
|
rect.origin.y += self.insets.top
|
||||||
|
self.absoluteLocation = (rect, containerSize)
|
||||||
|
if let shimmerNode = self.addressShimmerNode {
|
||||||
|
shimmerNode.updateAbsoluteRect(CGRect(x: rect.minX + self.fieldNode.frame.minX + 18.0, y: rect.minY + self.fieldNode.frame.minY, width: self.fieldNode.frame.width - 18.0 * 2.0, height: self.fieldNode.frame.height), within: containerSize)
|
||||||
|
}
|
||||||
|
if let shimmerNode = self.shimmerNode {
|
||||||
|
shimmerNode.updateAbsoluteRect(rect, within: containerSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,757 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import Display
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import SwiftSignalKit
|
||||||
|
import TelegramPresentationData
|
||||||
|
import ItemListUI
|
||||||
|
import ShimmerEffect
|
||||||
|
import TelegramCore
|
||||||
|
|
||||||
|
private enum ItemBackgroundColor: Equatable {
|
||||||
|
case blue
|
||||||
|
case green
|
||||||
|
case yellow
|
||||||
|
case red
|
||||||
|
case gray
|
||||||
|
|
||||||
|
var colors: (top: UIColor, bottom: UIColor, text: UIColor) {
|
||||||
|
switch self {
|
||||||
|
case .blue:
|
||||||
|
return (UIColor(rgb: 0x00b5f7), UIColor(rgb: 0x00b2f6), UIColor(rgb: 0xa7f4ff))
|
||||||
|
case .green:
|
||||||
|
return (UIColor(rgb: 0x4aca62), UIColor(rgb: 0x43c85c), UIColor(rgb: 0xc5ffe6))
|
||||||
|
case .yellow:
|
||||||
|
return (UIColor(rgb: 0xf8a953), UIColor(rgb: 0xf7a64e), UIColor(rgb: 0xfeffd7))
|
||||||
|
case .red:
|
||||||
|
return (UIColor(rgb: 0xf2656a), UIColor(rgb: 0xf25f65), UIColor(rgb: 0xffd3de))
|
||||||
|
case .gray:
|
||||||
|
return (UIColor(rgb: 0xa8b2bb), UIColor(rgb: 0xa2abb4), UIColor(rgb: 0xe3e6e8))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ItemListFolderInviteLinkListItem: ListViewItem, ItemListItem {
|
||||||
|
let presentationData: ItemListPresentationData
|
||||||
|
let invite: ExportedChatFolderLink?
|
||||||
|
let share: Bool
|
||||||
|
public let sectionId: ItemListSectionId
|
||||||
|
let style: ItemListStyle
|
||||||
|
let tapAction: ((ExportedChatFolderLink) -> Void)?
|
||||||
|
let contextAction: ((ExportedChatFolderLink, ASDisplayNode, ContextGesture?) -> Void)?
|
||||||
|
public let tag: ItemListItemTag?
|
||||||
|
|
||||||
|
public init(
|
||||||
|
presentationData: ItemListPresentationData,
|
||||||
|
invite: ExportedChatFolderLink?,
|
||||||
|
share: Bool,
|
||||||
|
sectionId: ItemListSectionId,
|
||||||
|
style: ItemListStyle,
|
||||||
|
tapAction: ((ExportedChatFolderLink) -> Void)?,
|
||||||
|
contextAction: ((ExportedChatFolderLink, ASDisplayNode, ContextGesture?) -> Void)?,
|
||||||
|
tag: ItemListItemTag? = nil
|
||||||
|
) {
|
||||||
|
self.presentationData = presentationData
|
||||||
|
self.invite = invite
|
||||||
|
self.share = share
|
||||||
|
self.sectionId = sectionId
|
||||||
|
self.style = style
|
||||||
|
self.tapAction = tapAction
|
||||||
|
self.contextAction = contextAction
|
||||||
|
self.tag = tag
|
||||||
|
}
|
||||||
|
|
||||||
|
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||||
|
async {
|
||||||
|
var firstWithHeader = false
|
||||||
|
var last = false
|
||||||
|
if self.style == .plain {
|
||||||
|
if previousItem == nil {
|
||||||
|
firstWithHeader = true
|
||||||
|
}
|
||||||
|
if nextItem == nil {
|
||||||
|
last = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let node = ItemListFolderInviteLinkListItemNode()
|
||||||
|
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem), firstWithHeader, last)
|
||||||
|
|
||||||
|
node.contentSize = layout.contentSize
|
||||||
|
node.insets = layout.insets
|
||||||
|
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
completion(node, {
|
||||||
|
return (nil, { _ in apply() })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
if let nodeValue = node() as? ItemListFolderInviteLinkListItemNode {
|
||||||
|
let makeLayout = nodeValue.asyncLayout()
|
||||||
|
|
||||||
|
async {
|
||||||
|
var firstWithHeader = false
|
||||||
|
var last = false
|
||||||
|
if self.style == .plain {
|
||||||
|
if previousItem == nil {
|
||||||
|
firstWithHeader = true
|
||||||
|
}
|
||||||
|
if nextItem == nil {
|
||||||
|
last = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let (layout, apply) = makeLayout(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem), firstWithHeader, last)
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
completion(layout, { _ in
|
||||||
|
apply()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var selectable: Bool = true
|
||||||
|
|
||||||
|
public func selected(listView: ListView) {
|
||||||
|
listView.clearHighlightAnimated(true)
|
||||||
|
if let invite = self.invite {
|
||||||
|
self.tapAction?(invite)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ItemListFolderInviteLinkListItemNode: ListViewItemNode, ItemListItemNode {
|
||||||
|
private let backgroundNode: ASDisplayNode
|
||||||
|
private let topStripeNode: ASDisplayNode
|
||||||
|
private let bottomStripeNode: ASDisplayNode
|
||||||
|
private let highlightedBackgroundNode: ASDisplayNode
|
||||||
|
private let maskNode: ASImageNode
|
||||||
|
|
||||||
|
private let extractedBackgroundImageNode: ASImageNode
|
||||||
|
|
||||||
|
private let containerNode: ContextControllerSourceNode
|
||||||
|
private let contextSourceNode: ContextExtractedContentContainingNode
|
||||||
|
|
||||||
|
private var extractedRect: CGRect?
|
||||||
|
private var nonExtractedRect: CGRect?
|
||||||
|
|
||||||
|
private let offsetContainerNode: ASDisplayNode
|
||||||
|
|
||||||
|
private let iconBackgroundNode: ASDisplayNode
|
||||||
|
private let iconNode: ASImageNode
|
||||||
|
private var timerNode: TimerNode?
|
||||||
|
|
||||||
|
private let titleNode: TextNode
|
||||||
|
private let subtitleNode: TextNode
|
||||||
|
|
||||||
|
private var placeholderNode: ShimmerEffectNode?
|
||||||
|
private var absoluteLocation: (CGRect, CGSize)?
|
||||||
|
|
||||||
|
private var currentColor: ItemBackgroundColor?
|
||||||
|
private var layoutParams: (ItemListFolderInviteLinkListItem, ListViewItemLayoutParams, ItemListNeighbors, Bool, Bool)?
|
||||||
|
|
||||||
|
public var tag: ItemListItemTag?
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
self.backgroundNode = ASDisplayNode()
|
||||||
|
self.backgroundNode.isLayerBacked = true
|
||||||
|
|
||||||
|
self.topStripeNode = ASDisplayNode()
|
||||||
|
self.topStripeNode.isLayerBacked = true
|
||||||
|
|
||||||
|
self.bottomStripeNode = ASDisplayNode()
|
||||||
|
self.bottomStripeNode.isLayerBacked = true
|
||||||
|
self.maskNode = ASImageNode()
|
||||||
|
|
||||||
|
self.extractedBackgroundImageNode = ASImageNode()
|
||||||
|
self.extractedBackgroundImageNode.displaysAsynchronously = false
|
||||||
|
self.extractedBackgroundImageNode.alpha = 0.0
|
||||||
|
|
||||||
|
self.contextSourceNode = ContextExtractedContentContainingNode()
|
||||||
|
self.containerNode = ContextControllerSourceNode()
|
||||||
|
|
||||||
|
self.offsetContainerNode = ASDisplayNode()
|
||||||
|
|
||||||
|
self.iconBackgroundNode = ASDisplayNode()
|
||||||
|
self.iconBackgroundNode.setLayerBlock { () -> CALayer in
|
||||||
|
return CAShapeLayer()
|
||||||
|
}
|
||||||
|
|
||||||
|
self.iconNode = ASImageNode()
|
||||||
|
self.iconNode.displaysAsynchronously = false
|
||||||
|
self.iconNode.displayWithoutProcessing = true
|
||||||
|
self.iconNode.contentMode = .center
|
||||||
|
|
||||||
|
self.titleNode = TextNode()
|
||||||
|
self.titleNode.isUserInteractionEnabled = false
|
||||||
|
self.titleNode.contentMode = .left
|
||||||
|
self.titleNode.contentsScale = UIScreen.main.scale
|
||||||
|
|
||||||
|
self.subtitleNode = TextNode()
|
||||||
|
self.subtitleNode.isUserInteractionEnabled = false
|
||||||
|
self.subtitleNode.contentMode = .left
|
||||||
|
self.subtitleNode.contentsScale = UIScreen.main.scale
|
||||||
|
|
||||||
|
self.highlightedBackgroundNode = ASDisplayNode()
|
||||||
|
self.highlightedBackgroundNode.isLayerBacked = true
|
||||||
|
|
||||||
|
super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false)
|
||||||
|
|
||||||
|
self.isAccessibilityElement = true
|
||||||
|
|
||||||
|
self.containerNode.addSubnode(self.contextSourceNode)
|
||||||
|
self.containerNode.targetNodeForActivationProgress = self.contextSourceNode.contentNode
|
||||||
|
self.addSubnode(self.containerNode)
|
||||||
|
|
||||||
|
self.contextSourceNode.contentNode.addSubnode(self.extractedBackgroundImageNode)
|
||||||
|
self.contextSourceNode.contentNode.addSubnode(self.offsetContainerNode)
|
||||||
|
|
||||||
|
self.offsetContainerNode.addSubnode(self.iconBackgroundNode)
|
||||||
|
self.offsetContainerNode.addSubnode(self.iconNode)
|
||||||
|
self.offsetContainerNode.addSubnode(self.titleNode)
|
||||||
|
self.offsetContainerNode.addSubnode(self.subtitleNode)
|
||||||
|
|
||||||
|
self.containerNode.activated = { [weak self] gesture, _ in
|
||||||
|
guard let strongSelf = self, let item = strongSelf.layoutParams?.0, let invite = item.invite, let contextAction = item.contextAction else {
|
||||||
|
gesture.cancel()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
contextAction(invite, strongSelf.contextSourceNode, gesture)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.contextSourceNode.willUpdateIsExtractedToContextPreview = { [weak self] isExtracted, transition in
|
||||||
|
guard let strongSelf = self, let item = strongSelf.layoutParams?.0 else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if isExtracted {
|
||||||
|
strongSelf.extractedBackgroundImageNode.image = generateStretchableFilledCircleImage(diameter: 28.0, color: item.presentationData.theme.list.plainBackgroundColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let extractedRect = strongSelf.extractedRect, let nonExtractedRect = strongSelf.nonExtractedRect {
|
||||||
|
let rect = isExtracted ? extractedRect : nonExtractedRect
|
||||||
|
transition.updateFrame(node: strongSelf.extractedBackgroundImageNode, frame: rect)
|
||||||
|
}
|
||||||
|
|
||||||
|
transition.updateSublayerTransformOffset(layer: strongSelf.offsetContainerNode.layer, offset: CGPoint(x: isExtracted ? 12.0 : 0.0, y: 0.0))
|
||||||
|
transition.updateAlpha(node: strongSelf.extractedBackgroundImageNode, alpha: isExtracted ? 1.0 : 0.0, completion: { _ in
|
||||||
|
if !isExtracted {
|
||||||
|
self?.extractedBackgroundImageNode.image = nil
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func didLoad() {
|
||||||
|
super.didLoad()
|
||||||
|
|
||||||
|
if let shapeLayer = self.iconBackgroundNode.layer as? CAShapeLayer {
|
||||||
|
shapeLayer.path = UIBezierPath(ovalIn: CGRect(x: 0.0, y: 0.0, width: 40.0, height: 40.0)).cgPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func asyncLayout() -> (_ item: ItemListFolderInviteLinkListItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors, _ firstWithHeader: Bool, _ last: Bool) -> (ListViewItemNodeLayout, () -> Void) {
|
||||||
|
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
||||||
|
let makeSubtitleLayout = TextNode.asyncLayout(self.subtitleNode)
|
||||||
|
|
||||||
|
let currentItem = self.layoutParams?.0
|
||||||
|
|
||||||
|
return { item, params, neighbors, firstWithHeader, last in
|
||||||
|
var updatedTheme: PresentationTheme?
|
||||||
|
|
||||||
|
let titleFont = Font.regular(item.presentationData.fontSize.itemListBaseFontSize)
|
||||||
|
let subtitleFont = Font.regular(floor(item.presentationData.fontSize.itemListBaseFontSize * 14.0 / 17.0))
|
||||||
|
|
||||||
|
if currentItem?.presentationData.theme !== item.presentationData.theme {
|
||||||
|
updatedTheme = item.presentationData.theme
|
||||||
|
}
|
||||||
|
|
||||||
|
let color: ItemBackgroundColor
|
||||||
|
let nextColor: ItemBackgroundColor
|
||||||
|
let transitionFraction: CGFloat
|
||||||
|
|
||||||
|
color = .green
|
||||||
|
nextColor = .yellow
|
||||||
|
transitionFraction = 1.0
|
||||||
|
|
||||||
|
let topColor = color.colors.top
|
||||||
|
let nextTopColor = nextColor.colors.top
|
||||||
|
let iconColor: UIColor
|
||||||
|
if let _ = item.invite {
|
||||||
|
if case .blue = color {
|
||||||
|
iconColor = item.presentationData.theme.list.itemAccentColor
|
||||||
|
} else {
|
||||||
|
iconColor = nextTopColor.mixedWith(topColor, alpha: transitionFraction)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
iconColor = item.presentationData.theme.list.mediaPlaceholderColor
|
||||||
|
}
|
||||||
|
|
||||||
|
let inviteLink = item.invite?.link.replacingOccurrences(of: "https://", with: "") ?? ""
|
||||||
|
var titleText = inviteLink
|
||||||
|
var subtitleText: String = ""
|
||||||
|
|
||||||
|
if let invite = item.invite {
|
||||||
|
if !invite.title.isEmpty {
|
||||||
|
titleText = invite.title
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO:localize
|
||||||
|
if invite.peerIds.count == 1 {
|
||||||
|
subtitleText = "includes 1 chat"
|
||||||
|
} else {
|
||||||
|
subtitleText = "includes \(invite.peerIds.count) chats"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
titleText = " "
|
||||||
|
subtitleText = " "
|
||||||
|
}
|
||||||
|
|
||||||
|
let titleAttributedString = NSAttributedString(string: titleText, font: titleFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor)
|
||||||
|
let subtitleAttributedString = NSAttributedString(string: subtitleText, font: subtitleFont, textColor: item.presentationData.theme.list.itemSecondaryTextColor)
|
||||||
|
|
||||||
|
let leftInset: CGFloat = 65.0 + params.leftInset
|
||||||
|
let rightInset: CGFloat = 16.0 + params.rightInset
|
||||||
|
let verticalInset: CGFloat = subtitleAttributedString.string.isEmpty ? 14.0 : 8.0
|
||||||
|
|
||||||
|
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
let (subtitleLayout, subtitleApply) = makeSubtitleLayout(TextNodeLayoutArguments(attributedString: subtitleAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
|
let titleSpacing: CGFloat = 1.0
|
||||||
|
|
||||||
|
let minHeight: CGFloat = titleLayout.size.height + verticalInset * 2.0
|
||||||
|
let rawHeight: CGFloat = verticalInset * 2.0 + titleLayout.size.height + titleSpacing + subtitleLayout.size.height
|
||||||
|
|
||||||
|
var insets: UIEdgeInsets
|
||||||
|
let itemBackgroundColor: UIColor
|
||||||
|
let itemSeparatorColor: UIColor
|
||||||
|
switch item.style {
|
||||||
|
case .plain:
|
||||||
|
itemBackgroundColor = item.presentationData.theme.list.plainBackgroundColor
|
||||||
|
itemSeparatorColor = item.presentationData.theme.list.itemPlainSeparatorColor
|
||||||
|
insets = itemListNeighborsPlainInsets(neighbors)
|
||||||
|
insets.top = firstWithHeader ? 29.0 : 0.0
|
||||||
|
insets.bottom = 0.0
|
||||||
|
case .blocks:
|
||||||
|
itemBackgroundColor = item.presentationData.theme.list.itemBlocksBackgroundColor
|
||||||
|
itemSeparatorColor = item.presentationData.theme.list.itemBlocksSeparatorColor
|
||||||
|
insets = itemListNeighborsGroupedInsets(neighbors, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
let contentSize = CGSize(width: params.width, height: max(minHeight, rawHeight))
|
||||||
|
let separatorHeight = UIScreenPixel
|
||||||
|
|
||||||
|
let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets)
|
||||||
|
|
||||||
|
return (layout, { [weak self] in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.layoutParams = (item, params, neighbors, firstWithHeader, last)
|
||||||
|
|
||||||
|
strongSelf.accessibilityLabel = titleAttributedString.string
|
||||||
|
strongSelf.accessibilityValue = subtitleAttributedString.string
|
||||||
|
|
||||||
|
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: layout.contentSize)
|
||||||
|
strongSelf.contextSourceNode.frame = CGRect(origin: CGPoint(), size: layout.contentSize)
|
||||||
|
strongSelf.offsetContainerNode.frame = CGRect(origin: CGPoint(), size: layout.contentSize)
|
||||||
|
strongSelf.contextSourceNode.contentNode.frame = CGRect(origin: CGPoint(), size: layout.contentSize)
|
||||||
|
strongSelf.containerNode.isGestureEnabled = item.contextAction != nil
|
||||||
|
|
||||||
|
let nonExtractedRect = CGRect(origin: CGPoint(), size: CGSize(width: layout.contentSize.width - 16.0, height: layout.contentSize.height))
|
||||||
|
let extractedRect = CGRect(origin: CGPoint(), size: layout.contentSize).insetBy(dx: 16.0 + params.leftInset, dy: 0.0)
|
||||||
|
strongSelf.extractedRect = extractedRect
|
||||||
|
strongSelf.nonExtractedRect = nonExtractedRect
|
||||||
|
|
||||||
|
if strongSelf.contextSourceNode.isExtractedToContextPreview {
|
||||||
|
strongSelf.extractedBackgroundImageNode.frame = extractedRect
|
||||||
|
} else {
|
||||||
|
strongSelf.extractedBackgroundImageNode.frame = nonExtractedRect
|
||||||
|
}
|
||||||
|
strongSelf.contextSourceNode.contentRect = extractedRect
|
||||||
|
|
||||||
|
if let layer = strongSelf.iconBackgroundNode.layer as? CAShapeLayer {
|
||||||
|
layer.fillColor = iconColor.cgColor
|
||||||
|
}
|
||||||
|
|
||||||
|
if let _ = updatedTheme {
|
||||||
|
strongSelf.topStripeNode.backgroundColor = itemSeparatorColor
|
||||||
|
strongSelf.bottomStripeNode.backgroundColor = itemSeparatorColor
|
||||||
|
strongSelf.backgroundNode.backgroundColor = itemBackgroundColor
|
||||||
|
strongSelf.highlightedBackgroundNode.backgroundColor = item.presentationData.theme.list.itemHighlightedBackgroundColor
|
||||||
|
|
||||||
|
strongSelf.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Link"), color: item.presentationData.theme.list.itemCheckColors.foregroundColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
let transition = ContainedViewLayoutTransition.immediate
|
||||||
|
|
||||||
|
let _ = titleApply()
|
||||||
|
let _ = subtitleApply()
|
||||||
|
|
||||||
|
switch item.style {
|
||||||
|
case .plain:
|
||||||
|
if strongSelf.backgroundNode.supernode != nil {
|
||||||
|
strongSelf.backgroundNode.removeFromSupernode()
|
||||||
|
}
|
||||||
|
if strongSelf.topStripeNode.supernode != nil {
|
||||||
|
strongSelf.topStripeNode.removeFromSupernode()
|
||||||
|
}
|
||||||
|
if strongSelf.bottomStripeNode.supernode == nil {
|
||||||
|
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0)
|
||||||
|
}
|
||||||
|
if strongSelf.maskNode.supernode != nil {
|
||||||
|
strongSelf.maskNode.removeFromSupernode()
|
||||||
|
}
|
||||||
|
|
||||||
|
let stripeInset: CGFloat
|
||||||
|
if case .none = neighbors.bottom {
|
||||||
|
stripeInset = 0.0
|
||||||
|
} else {
|
||||||
|
stripeInset = leftInset
|
||||||
|
}
|
||||||
|
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: stripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - stripeInset, height: separatorHeight))
|
||||||
|
strongSelf.bottomStripeNode.isHidden = last
|
||||||
|
case .blocks:
|
||||||
|
if strongSelf.backgroundNode.supernode == nil {
|
||||||
|
strongSelf.insertSubnode(strongSelf.backgroundNode, at: 0)
|
||||||
|
}
|
||||||
|
if strongSelf.topStripeNode.supernode == nil {
|
||||||
|
strongSelf.insertSubnode(strongSelf.topStripeNode, at: 1)
|
||||||
|
}
|
||||||
|
if strongSelf.bottomStripeNode.supernode == nil {
|
||||||
|
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
|
||||||
|
}
|
||||||
|
if strongSelf.maskNode.supernode == nil {
|
||||||
|
strongSelf.insertSubnode(strongSelf.maskNode, at: 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
let hasCorners = itemListHasRoundedBlockLayout(params)
|
||||||
|
var hasTopCorners = false
|
||||||
|
var hasBottomCorners = false
|
||||||
|
switch neighbors.top {
|
||||||
|
case .sameSection(false):
|
||||||
|
strongSelf.topStripeNode.isHidden = true
|
||||||
|
default:
|
||||||
|
hasTopCorners = true
|
||||||
|
strongSelf.topStripeNode.isHidden = hasCorners
|
||||||
|
}
|
||||||
|
let bottomStripeInset: CGFloat
|
||||||
|
switch neighbors.bottom {
|
||||||
|
case .sameSection(false):
|
||||||
|
bottomStripeInset = leftInset
|
||||||
|
strongSelf.bottomStripeNode.isHidden = false
|
||||||
|
default:
|
||||||
|
bottomStripeInset = 0.0
|
||||||
|
hasBottomCorners = true
|
||||||
|
strongSelf.bottomStripeNode.isHidden = hasCorners
|
||||||
|
}
|
||||||
|
|
||||||
|
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil
|
||||||
|
|
||||||
|
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
|
||||||
|
strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0)
|
||||||
|
strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: separatorHeight))
|
||||||
|
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - bottomStripeInset, height: separatorHeight))
|
||||||
|
}
|
||||||
|
|
||||||
|
let iconSize: CGSize = CGSize(width: 40.0, height: 40.0)
|
||||||
|
let iconFrame = CGRect(origin: CGPoint(x: params.leftInset + 12.0, y: floorToScreenPixels((layout.contentSize.height - iconSize.height) / 2.0)), size: iconSize)
|
||||||
|
strongSelf.iconBackgroundNode.bounds = CGRect(origin: CGPoint(), size: iconSize)
|
||||||
|
strongSelf.iconBackgroundNode.position = iconFrame.center
|
||||||
|
strongSelf.iconNode.frame = iconFrame
|
||||||
|
|
||||||
|
transition.updateTransformScale(node: strongSelf.iconBackgroundNode, scale: 1.0)
|
||||||
|
|
||||||
|
strongSelf.timerNode?.frame = iconFrame.insetBy(dx: -5.0, dy: -5.0)
|
||||||
|
|
||||||
|
transition.updateFrame(node: strongSelf.titleNode, frame: CGRect(origin: CGPoint(x: leftInset, y: verticalInset), size: titleLayout.size))
|
||||||
|
transition.updateFrame(node: strongSelf.subtitleNode, frame: CGRect(origin: CGPoint(x: leftInset, y: verticalInset + titleLayout.size.height + titleSpacing), size: subtitleLayout.size))
|
||||||
|
|
||||||
|
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: params.width, height: contentSize.height + UIScreenPixel + UIScreenPixel))
|
||||||
|
|
||||||
|
if item.invite == nil {
|
||||||
|
let shimmerNode: ShimmerEffectNode
|
||||||
|
if let current = strongSelf.placeholderNode {
|
||||||
|
shimmerNode = current
|
||||||
|
} else {
|
||||||
|
shimmerNode = ShimmerEffectNode()
|
||||||
|
strongSelf.placeholderNode = shimmerNode
|
||||||
|
strongSelf.addSubnode(shimmerNode)
|
||||||
|
}
|
||||||
|
shimmerNode.frame = CGRect(origin: CGPoint(), size: layout.contentSize)
|
||||||
|
if let (rect, size) = strongSelf.absoluteLocation {
|
||||||
|
shimmerNode.updateAbsoluteRect(rect, within: size)
|
||||||
|
}
|
||||||
|
|
||||||
|
var shapes: [ShimmerEffectNode.Shape] = []
|
||||||
|
|
||||||
|
let titleLineWidth: CGFloat = 180.0
|
||||||
|
let subtitleLineWidth: CGFloat = 60.0
|
||||||
|
let lineDiameter: CGFloat = 10.0
|
||||||
|
|
||||||
|
let iconFrame = strongSelf.iconBackgroundNode.frame
|
||||||
|
shapes.append(.circle(iconFrame))
|
||||||
|
|
||||||
|
let titleFrame = strongSelf.titleNode.frame
|
||||||
|
shapes.append(.roundedRectLine(startPoint: CGPoint(x: titleFrame.minX, y: titleFrame.minY + floor((titleFrame.height - lineDiameter) / 2.0)), width: titleLineWidth, diameter: lineDiameter))
|
||||||
|
|
||||||
|
let subtitleFrame = strongSelf.subtitleNode.frame
|
||||||
|
shapes.append(.roundedRectLine(startPoint: CGPoint(x: subtitleFrame.minX, y: subtitleFrame.minY + floor((subtitleFrame.height - lineDiameter) / 2.0)), width: subtitleLineWidth, diameter: lineDiameter))
|
||||||
|
|
||||||
|
shimmerNode.update(backgroundColor: item.presentationData.theme.list.itemBlocksBackgroundColor, foregroundColor: item.presentationData.theme.list.mediaPlaceholderColor, shimmeringColor: item.presentationData.theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), shapes: shapes, size: layout.contentSize)
|
||||||
|
} else if let shimmerNode = strongSelf.placeholderNode {
|
||||||
|
strongSelf.placeholderNode = nil
|
||||||
|
shimmerNode.removeFromSupernode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func setHighlighted(_ highlighted: Bool, at point: CGPoint, animated: Bool) {
|
||||||
|
super.setHighlighted(highlighted, at: point, animated: animated)
|
||||||
|
|
||||||
|
if highlighted {
|
||||||
|
self.highlightedBackgroundNode.alpha = 1.0
|
||||||
|
if self.highlightedBackgroundNode.supernode == nil {
|
||||||
|
var anchorNode: ASDisplayNode?
|
||||||
|
if self.bottomStripeNode.supernode != nil {
|
||||||
|
anchorNode = self.bottomStripeNode
|
||||||
|
} else if self.topStripeNode.supernode != nil {
|
||||||
|
anchorNode = self.topStripeNode
|
||||||
|
} else if self.backgroundNode.supernode != nil {
|
||||||
|
anchorNode = self.backgroundNode
|
||||||
|
}
|
||||||
|
if let anchorNode = anchorNode {
|
||||||
|
self.insertSubnode(self.highlightedBackgroundNode, aboveSubnode: anchorNode)
|
||||||
|
} else {
|
||||||
|
self.addSubnode(self.highlightedBackgroundNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if self.highlightedBackgroundNode.supernode != nil {
|
||||||
|
if animated {
|
||||||
|
self.highlightedBackgroundNode.layer.animateAlpha(from: self.highlightedBackgroundNode.alpha, to: 0.0, duration: 0.4, completion: { [weak self] completed in
|
||||||
|
if let strongSelf = self {
|
||||||
|
if completed {
|
||||||
|
strongSelf.highlightedBackgroundNode.removeFromSupernode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
self.highlightedBackgroundNode.alpha = 0.0
|
||||||
|
} else {
|
||||||
|
self.highlightedBackgroundNode.removeFromSupernode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
||||||
|
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||||
|
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
|
||||||
|
var rect = rect
|
||||||
|
rect.origin.y += self.insets.top
|
||||||
|
self.absoluteLocation = (rect, containerSize)
|
||||||
|
if let shimmerNode = self.placeholderNode {
|
||||||
|
shimmerNode.updateAbsoluteRect(rect, within: containerSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct ContentParticle {
|
||||||
|
var position: CGPoint
|
||||||
|
var direction: CGPoint
|
||||||
|
var velocity: CGFloat
|
||||||
|
var alpha: CGFloat
|
||||||
|
var lifetime: Double
|
||||||
|
var beginTime: Double
|
||||||
|
|
||||||
|
init(position: CGPoint, direction: CGPoint, velocity: CGFloat, alpha: CGFloat, lifetime: Double, beginTime: Double) {
|
||||||
|
self.position = position
|
||||||
|
self.direction = direction
|
||||||
|
self.velocity = velocity
|
||||||
|
self.alpha = alpha
|
||||||
|
self.lifetime = lifetime
|
||||||
|
self.beginTime = beginTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class TimerNode: ASDisplayNode {
|
||||||
|
enum Value: Equatable {
|
||||||
|
case timestamp(creation: Int32, deadline: Int32)
|
||||||
|
case fraction(CGFloat)
|
||||||
|
}
|
||||||
|
private struct Params: Equatable {
|
||||||
|
var color: UIColor
|
||||||
|
var value: Value
|
||||||
|
}
|
||||||
|
|
||||||
|
private let hierarchyTrackingNode: HierarchyTrackingNode
|
||||||
|
private var inHierarchyValue: Bool = false
|
||||||
|
|
||||||
|
private var animator: ConstantDisplayLinkAnimator?
|
||||||
|
private let contentNode: ASDisplayNode
|
||||||
|
private var particles: [ContentParticle] = []
|
||||||
|
|
||||||
|
private var currentParams: Params?
|
||||||
|
|
||||||
|
var reachedTimeout: (() -> Void)?
|
||||||
|
|
||||||
|
override init() {
|
||||||
|
var updateInHierarchy: ((Bool) -> Void)?
|
||||||
|
self.hierarchyTrackingNode = HierarchyTrackingNode({ value in
|
||||||
|
updateInHierarchy?(value)
|
||||||
|
})
|
||||||
|
|
||||||
|
self.contentNode = ASDisplayNode()
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
self.addSubnode(self.contentNode)
|
||||||
|
|
||||||
|
updateInHierarchy = { [weak self] value in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strongSelf.inHierarchyValue = value
|
||||||
|
strongSelf.animator?.isPaused = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
self.animator?.invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(color: UIColor, value: Value) {
|
||||||
|
let params = Params(
|
||||||
|
color: color,
|
||||||
|
value: value
|
||||||
|
)
|
||||||
|
self.currentParams = params
|
||||||
|
|
||||||
|
self.updateValues()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateValues() {
|
||||||
|
guard let params = self.currentParams else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let color = params.color
|
||||||
|
|
||||||
|
let currentTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
|
||||||
|
var fraction: CGFloat
|
||||||
|
switch params.value {
|
||||||
|
case let .fraction(value):
|
||||||
|
fraction = value
|
||||||
|
case let .timestamp(creation, deadline):
|
||||||
|
fraction = CGFloat(deadline - currentTimestamp) / CGFloat(deadline - creation)
|
||||||
|
}
|
||||||
|
fraction = max(0.0001, 1.0 - max(0.0, min(1.0, fraction)))
|
||||||
|
|
||||||
|
let image: UIImage?
|
||||||
|
|
||||||
|
let diameter: CGFloat = 42.0
|
||||||
|
let inset: CGFloat = 8.0
|
||||||
|
let lineWidth: CGFloat = 2.0
|
||||||
|
|
||||||
|
let timestamp = CACurrentMediaTime()
|
||||||
|
|
||||||
|
let center = CGPoint(x: (diameter + inset) / 2.0, y: (diameter + inset) / 2.0)
|
||||||
|
let radius: CGFloat = (diameter - lineWidth / 2.0) / 2.0
|
||||||
|
|
||||||
|
let startAngle: CGFloat = -CGFloat.pi / 2.0
|
||||||
|
let endAngle: CGFloat = -CGFloat.pi / 2.0 + 2.0 * CGFloat.pi * fraction
|
||||||
|
|
||||||
|
let sparks = fraction > 0.05 && fraction != 1.0
|
||||||
|
if sparks {
|
||||||
|
let v = CGPoint(x: sin(endAngle), y: -cos(endAngle))
|
||||||
|
let c = CGPoint(x: -v.y * radius + center.x, y: v.x * radius + center.y)
|
||||||
|
|
||||||
|
let dt: CGFloat = 1.0 / 60.0
|
||||||
|
var removeIndices: [Int] = []
|
||||||
|
for i in 0 ..< self.particles.count {
|
||||||
|
let currentTime = timestamp - self.particles[i].beginTime
|
||||||
|
if currentTime > self.particles[i].lifetime {
|
||||||
|
removeIndices.append(i)
|
||||||
|
} else {
|
||||||
|
let input: CGFloat = CGFloat(currentTime / self.particles[i].lifetime)
|
||||||
|
let decelerated: CGFloat = (1.0 - (1.0 - input) * (1.0 - input))
|
||||||
|
self.particles[i].alpha = 1.0 - decelerated
|
||||||
|
|
||||||
|
var p = self.particles[i].position
|
||||||
|
let d = self.particles[i].direction
|
||||||
|
let v = self.particles[i].velocity
|
||||||
|
p = CGPoint(x: p.x + d.x * v * dt, y: p.y + d.y * v * dt)
|
||||||
|
self.particles[i].position = p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in removeIndices.reversed() {
|
||||||
|
self.particles.remove(at: i)
|
||||||
|
}
|
||||||
|
|
||||||
|
let newParticleCount = 1
|
||||||
|
for _ in 0 ..< newParticleCount {
|
||||||
|
let degrees: CGFloat = CGFloat(arc4random_uniform(140)) - 40.0
|
||||||
|
let angle: CGFloat = degrees * CGFloat.pi / 180.0
|
||||||
|
|
||||||
|
let direction = CGPoint(x: v.x * cos(angle) - v.y * sin(angle), y: v.x * sin(angle) + v.y * cos(angle))
|
||||||
|
let velocity = (20.0 + (CGFloat(arc4random()) / CGFloat(UINT32_MAX)) * 4.0) * 0.3
|
||||||
|
|
||||||
|
let lifetime = Double(0.4 + CGFloat(arc4random_uniform(100)) * 0.01)
|
||||||
|
|
||||||
|
let particle = ContentParticle(position: c, direction: direction, velocity: velocity, alpha: 1.0, lifetime: lifetime, beginTime: timestamp)
|
||||||
|
self.particles.append(particle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
image = generateImage(CGSize(width: diameter + inset, height: diameter + inset), rotatedContext: { size, context in
|
||||||
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
|
context.setStrokeColor(color.cgColor)
|
||||||
|
context.setFillColor(color.cgColor)
|
||||||
|
context.setLineWidth(lineWidth)
|
||||||
|
context.setLineCap(.round)
|
||||||
|
|
||||||
|
let path = CGMutablePath()
|
||||||
|
path.addArc(center: center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
|
||||||
|
context.addPath(path)
|
||||||
|
context.strokePath()
|
||||||
|
|
||||||
|
if sparks {
|
||||||
|
for particle in self.particles {
|
||||||
|
let size: CGFloat = 2.0
|
||||||
|
context.setAlpha(particle.alpha)
|
||||||
|
context.fillEllipse(in: CGRect(origin: CGPoint(x: particle.position.x - size / 2.0, y: particle.position.y - size / 2.0), size: CGSize(width: size, height: size)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
self.contentNode.contents = image?.cgImage
|
||||||
|
if let image = image {
|
||||||
|
self.contentNode.frame = CGRect(origin: CGPoint(), size: image.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
if fraction <= .ulpOfOne {
|
||||||
|
self.animator?.invalidate()
|
||||||
|
self.animator = nil
|
||||||
|
} else {
|
||||||
|
if self.animator == nil {
|
||||||
|
let animator = ConstantDisplayLinkAnimator(update: { [weak self] in
|
||||||
|
self?.updateValues()
|
||||||
|
})
|
||||||
|
self.animator = animator
|
||||||
|
animator.isPaused = self.inHierarchyValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -26,6 +26,7 @@ swift_library(
|
|||||||
"//submodules/AccountContext:AccountContext",
|
"//submodules/AccountContext:AccountContext",
|
||||||
"//submodules/ComponentFlow:ComponentFlow",
|
"//submodules/ComponentFlow:ComponentFlow",
|
||||||
"//submodules/TelegramUI/Components/EmojiStatusComponent:EmojiStatusComponent",
|
"//submodules/TelegramUI/Components/EmojiStatusComponent:EmojiStatusComponent",
|
||||||
|
"//submodules/CheckNode",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -16,6 +16,7 @@ import ContextUI
|
|||||||
import AccountContext
|
import AccountContext
|
||||||
import ComponentFlow
|
import ComponentFlow
|
||||||
import EmojiStatusComponent
|
import EmojiStatusComponent
|
||||||
|
import CheckNode
|
||||||
|
|
||||||
private final class ShimmerEffectNode: ASDisplayNode {
|
private final class ShimmerEffectNode: ASDisplayNode {
|
||||||
private var currentBackgroundColor: UIColor?
|
private var currentBackgroundColor: UIColor?
|
||||||
@ -262,6 +263,7 @@ public struct ItemListPeerItemSwitch {
|
|||||||
public enum ItemListPeerItemSwitchStyle {
|
public enum ItemListPeerItemSwitchStyle {
|
||||||
case standard
|
case standard
|
||||||
case check
|
case check
|
||||||
|
case leftCheck
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ItemListPeerItemAliasHandling {
|
public enum ItemListPeerItemAliasHandling {
|
||||||
@ -474,6 +476,7 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
|||||||
private var credibilityIconView: ComponentHostView<Empty>?
|
private var credibilityIconView: ComponentHostView<Empty>?
|
||||||
private var switchNode: SwitchNode?
|
private var switchNode: SwitchNode?
|
||||||
private var checkNode: ASImageNode?
|
private var checkNode: ASImageNode?
|
||||||
|
private var leftCheckNode: CheckNode?
|
||||||
|
|
||||||
private var shimmerNode: LoadingShimmerNode?
|
private var shimmerNode: LoadingShimmerNode?
|
||||||
private var absoluteLocation: (CGRect, CGSize)?
|
private var absoluteLocation: (CGRect, CGSize)?
|
||||||
@ -736,6 +739,8 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
|||||||
peerRevealOptions = []
|
peerRevealOptions = []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var additionalLeftInset: CGFloat = 0.0
|
||||||
|
var leftInset: CGFloat = params.leftInset
|
||||||
var rightInset: CGFloat = params.rightInset
|
var rightInset: CGFloat = params.rightInset
|
||||||
let switchSize = CGSize(width: 51.0, height: 31.0)
|
let switchSize = CGSize(width: 51.0, height: 31.0)
|
||||||
var checkImage: UIImage?
|
var checkImage: UIImage?
|
||||||
@ -755,6 +760,11 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
|||||||
}
|
}
|
||||||
rightInset += 24.0
|
rightInset += 24.0
|
||||||
currentSwitchNode = nil
|
currentSwitchNode = nil
|
||||||
|
case .leftCheck:
|
||||||
|
additionalLeftInset += 40.0
|
||||||
|
leftInset += additionalLeftInset
|
||||||
|
currentSwitchNode = nil
|
||||||
|
currentCheckNode = nil
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
currentSwitchNode = nil
|
currentSwitchNode = nil
|
||||||
@ -842,7 +852,6 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
let leftInset: CGFloat
|
|
||||||
let verticalInset: CGFloat
|
let verticalInset: CGFloat
|
||||||
let verticalOffset: CGFloat
|
let verticalOffset: CGFloat
|
||||||
let avatarSize: CGFloat
|
let avatarSize: CGFloat
|
||||||
@ -856,7 +865,7 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
|||||||
}
|
}
|
||||||
verticalOffset = 0.0
|
verticalOffset = 0.0
|
||||||
avatarSize = 31.0
|
avatarSize = 31.0
|
||||||
leftInset = 59.0 + params.leftInset
|
leftInset += 59.0
|
||||||
avatarFontSize = floor(31.0 * 16.0 / 37.0)
|
avatarFontSize = floor(31.0 * 16.0 / 37.0)
|
||||||
case .peerList:
|
case .peerList:
|
||||||
if case .none = item.text {
|
if case .none = item.text {
|
||||||
@ -866,7 +875,7 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
|||||||
}
|
}
|
||||||
verticalOffset = 0.0
|
verticalOffset = 0.0
|
||||||
avatarSize = 40.0
|
avatarSize = 40.0
|
||||||
leftInset = 65.0 + params.leftInset
|
leftInset += 65.0
|
||||||
avatarFontSize = floor(40.0 * 16.0 / 37.0)
|
avatarFontSize = floor(40.0 * 16.0 / 37.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1234,9 +1243,27 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
|||||||
|
|
||||||
strongSelf.labelBadgeNode.frame = CGRect(origin: CGPoint(x: revealOffset + params.width - rightLabelInset - badgeWidth, y: labelFrame.minY - 1.0), size: CGSize(width: badgeWidth, height: badgeDiameter))
|
strongSelf.labelBadgeNode.frame = CGRect(origin: CGPoint(x: revealOffset + params.width - rightLabelInset - badgeWidth, y: labelFrame.minY - 1.0), size: CGSize(width: badgeWidth, height: badgeDiameter))
|
||||||
|
|
||||||
let avatarFrame = CGRect(origin: CGPoint(x: params.leftInset + revealOffset + editingOffset + 15.0, y: floorToScreenPixels((layout.contentSize.height - avatarSize) / 2.0)), size: CGSize(width: avatarSize, height: avatarSize))
|
let avatarFrame = CGRect(origin: CGPoint(x: params.leftInset + additionalLeftInset + revealOffset + editingOffset + 15.0, y: floorToScreenPixels((layout.contentSize.height - avatarSize) / 2.0)), size: CGSize(width: avatarSize, height: avatarSize))
|
||||||
transition.updateFrame(node: strongSelf.avatarNode, frame: avatarFrame)
|
transition.updateFrame(node: strongSelf.avatarNode, frame: avatarFrame)
|
||||||
|
|
||||||
|
if let switchValue = item.switchValue, case .leftCheck = switchValue.style {
|
||||||
|
let leftCheckNode: CheckNode
|
||||||
|
if let current = strongSelf.leftCheckNode {
|
||||||
|
leftCheckNode = current
|
||||||
|
} else {
|
||||||
|
leftCheckNode = CheckNode(theme: CheckNodeTheme(theme: item.presentationData.theme, style: .plain))
|
||||||
|
strongSelf.leftCheckNode = leftCheckNode
|
||||||
|
strongSelf.avatarNode.supernode?.addSubnode(leftCheckNode)
|
||||||
|
}
|
||||||
|
leftCheckNode.frame = CGRect(origin: CGPoint(x: params.leftInset + 16.0, y: floor((layout.contentSize.height - 22.0) / 2.0)), size: CGSize(width: 22.0, height: 22.0))
|
||||||
|
leftCheckNode.setSelected(switchValue.value, animated: animated)
|
||||||
|
} else {
|
||||||
|
if let leftCheckNode = strongSelf.leftCheckNode {
|
||||||
|
strongSelf.leftCheckNode = nil
|
||||||
|
leftCheckNode.removeFromSupernode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let threadInfo = item.threadInfo {
|
if let threadInfo = item.threadInfo {
|
||||||
let threadIconSize = floor(avatarSize * 0.9)
|
let threadIconSize = floor(avatarSize * 0.9)
|
||||||
let threadIconFrame = CGRect(origin: CGPoint(x: avatarFrame.minX + floor((avatarFrame.width - threadIconSize) / 2.0), y: avatarFrame.minY + floor((avatarFrame.height - threadIconSize) / 2.0)), size: CGSize(width: threadIconSize, height: threadIconSize))
|
let threadIconFrame = CGRect(origin: CGPoint(x: avatarFrame.minX + floor((avatarFrame.width - threadIconSize) / 2.0), y: avatarFrame.minY + floor((avatarFrame.height - threadIconSize) / 2.0)), size: CGSize(width: threadIconSize, height: threadIconSize))
|
||||||
|
@ -3,6 +3,8 @@ public enum Api {
|
|||||||
public enum account {}
|
public enum account {}
|
||||||
public enum auth {}
|
public enum auth {}
|
||||||
public enum channels {}
|
public enum channels {}
|
||||||
|
public enum communities {}
|
||||||
|
public enum community {}
|
||||||
public enum contacts {}
|
public enum contacts {}
|
||||||
public enum help {}
|
public enum help {}
|
||||||
public enum messages {}
|
public enum messages {}
|
||||||
@ -20,6 +22,7 @@ public enum Api {
|
|||||||
public enum auth {}
|
public enum auth {}
|
||||||
public enum bots {}
|
public enum bots {}
|
||||||
public enum channels {}
|
public enum channels {}
|
||||||
|
public enum communities {}
|
||||||
public enum contacts {}
|
public enum contacts {}
|
||||||
public enum folders {}
|
public enum folders {}
|
||||||
public enum help {}
|
public enum help {}
|
||||||
@ -190,6 +193,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-712374074] = { return Api.Dialog.parse_dialog($0) }
|
dict[-712374074] = { return Api.Dialog.parse_dialog($0) }
|
||||||
dict[1908216652] = { return Api.Dialog.parse_dialogFolder($0) }
|
dict[1908216652] = { return Api.Dialog.parse_dialogFolder($0) }
|
||||||
dict[1949890536] = { return Api.DialogFilter.parse_dialogFilter($0) }
|
dict[1949890536] = { return Api.DialogFilter.parse_dialogFilter($0) }
|
||||||
|
dict[-665432009] = { return Api.DialogFilter.parse_dialogFilterCommunity($0) }
|
||||||
dict[909284270] = { return Api.DialogFilter.parse_dialogFilterDefault($0) }
|
dict[909284270] = { return Api.DialogFilter.parse_dialogFilterDefault($0) }
|
||||||
dict[2004110666] = { return Api.DialogFilterSuggested.parse_dialogFilterSuggested($0) }
|
dict[2004110666] = { return Api.DialogFilterSuggested.parse_dialogFilterSuggested($0) }
|
||||||
dict[-445792507] = { return Api.DialogPeer.parse_dialogPeer($0) }
|
dict[-445792507] = { return Api.DialogPeer.parse_dialogPeer($0) }
|
||||||
@ -234,6 +238,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[594758406] = { return Api.EncryptedMessage.parse_encryptedMessageService($0) }
|
dict[594758406] = { return Api.EncryptedMessage.parse_encryptedMessageService($0) }
|
||||||
dict[179611673] = { return Api.ExportedChatInvite.parse_chatInviteExported($0) }
|
dict[179611673] = { return Api.ExportedChatInvite.parse_chatInviteExported($0) }
|
||||||
dict[-317687113] = { return Api.ExportedChatInvite.parse_chatInvitePublicJoinRequests($0) }
|
dict[-317687113] = { return Api.ExportedChatInvite.parse_chatInvitePublicJoinRequests($0) }
|
||||||
|
dict[-1350894801] = { return Api.ExportedCommunityInvite.parse_exportedCommunityInvite($0) }
|
||||||
dict[1103040667] = { return Api.ExportedContactToken.parse_exportedContactToken($0) }
|
dict[1103040667] = { return Api.ExportedContactToken.parse_exportedContactToken($0) }
|
||||||
dict[1571494644] = { return Api.ExportedMessageLink.parse_exportedMessageLink($0) }
|
dict[1571494644] = { return Api.ExportedMessageLink.parse_exportedMessageLink($0) }
|
||||||
dict[-207944868] = { return Api.FileHash.parse_fileHash($0) }
|
dict[-207944868] = { return Api.FileHash.parse_fileHash($0) }
|
||||||
@ -285,6 +290,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-1736378792] = { return Api.InputCheckPasswordSRP.parse_inputCheckPasswordEmpty($0) }
|
dict[-1736378792] = { return Api.InputCheckPasswordSRP.parse_inputCheckPasswordEmpty($0) }
|
||||||
dict[-763367294] = { return Api.InputCheckPasswordSRP.parse_inputCheckPasswordSRP($0) }
|
dict[-763367294] = { return Api.InputCheckPasswordSRP.parse_inputCheckPasswordSRP($0) }
|
||||||
dict[1968737087] = { return Api.InputClientProxy.parse_inputClientProxy($0) }
|
dict[1968737087] = { return Api.InputClientProxy.parse_inputClientProxy($0) }
|
||||||
|
dict[450955169] = { return Api.InputCommunity.parse_inputCommunityDialogFilter($0) }
|
||||||
dict[-208488460] = { return Api.InputContact.parse_inputPhoneContact($0) }
|
dict[-208488460] = { return Api.InputContact.parse_inputPhoneContact($0) }
|
||||||
dict[-55902537] = { return Api.InputDialogPeer.parse_inputDialogPeer($0) }
|
dict[-55902537] = { return Api.InputDialogPeer.parse_inputDialogPeer($0) }
|
||||||
dict[1684014375] = { return Api.InputDialogPeer.parse_inputDialogPeerFolder($0) }
|
dict[1684014375] = { return Api.InputDialogPeer.parse_inputDialogPeerFolder($0) }
|
||||||
@ -990,6 +996,10 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-1699676497] = { return Api.channels.ChannelParticipants.parse_channelParticipants($0) }
|
dict[-1699676497] = { return Api.channels.ChannelParticipants.parse_channelParticipants($0) }
|
||||||
dict[-266911767] = { return Api.channels.ChannelParticipants.parse_channelParticipantsNotModified($0) }
|
dict[-266911767] = { return Api.channels.ChannelParticipants.parse_channelParticipantsNotModified($0) }
|
||||||
dict[-191450938] = { return Api.channels.SendAsPeers.parse_sendAsPeers($0) }
|
dict[-191450938] = { return Api.channels.SendAsPeers.parse_sendAsPeers($0) }
|
||||||
|
dict[1805101290] = { return Api.communities.ExportedCommunityInvite.parse_exportedCommunityInvite($0) }
|
||||||
|
dict[-2662489] = { return Api.communities.ExportedInvites.parse_exportedInvites($0) }
|
||||||
|
dict[408604768] = { return Api.community.CommunityInvite.parse_communityInvite($0) }
|
||||||
|
dict[74184410] = { return Api.community.CommunityInvite.parse_communityInviteAlready($0) }
|
||||||
dict[182326673] = { return Api.contacts.Blocked.parse_blocked($0) }
|
dict[182326673] = { return Api.contacts.Blocked.parse_blocked($0) }
|
||||||
dict[-513392236] = { return Api.contacts.Blocked.parse_blockedSlice($0) }
|
dict[-513392236] = { return Api.contacts.Blocked.parse_blockedSlice($0) }
|
||||||
dict[-353862078] = { return Api.contacts.Contacts.parse_contacts($0) }
|
dict[-353862078] = { return Api.contacts.Contacts.parse_contacts($0) }
|
||||||
@ -1341,6 +1351,8 @@ public extension Api {
|
|||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.ExportedChatInvite:
|
case let _1 as Api.ExportedChatInvite:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
|
case let _1 as Api.ExportedCommunityInvite:
|
||||||
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.ExportedContactToken:
|
case let _1 as Api.ExportedContactToken:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.ExportedMessageLink:
|
case let _1 as Api.ExportedMessageLink:
|
||||||
@ -1397,6 +1409,8 @@ public extension Api {
|
|||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.InputClientProxy:
|
case let _1 as Api.InputClientProxy:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
|
case let _1 as Api.InputCommunity:
|
||||||
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.InputContact:
|
case let _1 as Api.InputContact:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.InputDialogPeer:
|
case let _1 as Api.InputDialogPeer:
|
||||||
@ -1783,6 +1797,12 @@ public extension Api {
|
|||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.channels.SendAsPeers:
|
case let _1 as Api.channels.SendAsPeers:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
|
case let _1 as Api.communities.ExportedCommunityInvite:
|
||||||
|
_1.serialize(buffer, boxed)
|
||||||
|
case let _1 as Api.communities.ExportedInvites:
|
||||||
|
_1.serialize(buffer, boxed)
|
||||||
|
case let _1 as Api.community.CommunityInvite:
|
||||||
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.contacts.Blocked:
|
case let _1 as Api.contacts.Blocked:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.contacts.Contacts:
|
case let _1 as Api.contacts.Contacts:
|
||||||
|
@ -850,6 +850,224 @@ public extension Api.channels {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public extension Api.communities {
|
||||||
|
enum ExportedCommunityInvite: TypeConstructorDescription {
|
||||||
|
case exportedCommunityInvite(filter: Api.DialogFilter, invite: Api.ExportedCommunityInvite)
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .exportedCommunityInvite(let filter, let invite):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(1805101290)
|
||||||
|
}
|
||||||
|
filter.serialize(buffer, true)
|
||||||
|
invite.serialize(buffer, true)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .exportedCommunityInvite(let filter, let invite):
|
||||||
|
return ("exportedCommunityInvite", [("filter", filter as Any), ("invite", invite as Any)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_exportedCommunityInvite(_ reader: BufferReader) -> ExportedCommunityInvite? {
|
||||||
|
var _1: Api.DialogFilter?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
_1 = Api.parse(reader, signature: signature) as? Api.DialogFilter
|
||||||
|
}
|
||||||
|
var _2: Api.ExportedCommunityInvite?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
_2 = Api.parse(reader, signature: signature) as? Api.ExportedCommunityInvite
|
||||||
|
}
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
if _c1 && _c2 {
|
||||||
|
return Api.communities.ExportedCommunityInvite.exportedCommunityInvite(filter: _1!, invite: _2!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public extension Api.communities {
|
||||||
|
enum ExportedInvites: TypeConstructorDescription {
|
||||||
|
case exportedInvites(invites: [Api.ExportedCommunityInvite], chats: [Api.Chat], users: [Api.User])
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .exportedInvites(let invites, let chats, let users):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-2662489)
|
||||||
|
}
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(invites.count))
|
||||||
|
for item in invites {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(chats.count))
|
||||||
|
for item in chats {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(users.count))
|
||||||
|
for item in users {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .exportedInvites(let invites, let chats, let users):
|
||||||
|
return ("exportedInvites", [("invites", invites as Any), ("chats", chats as Any), ("users", users as Any)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_exportedInvites(_ reader: BufferReader) -> ExportedInvites? {
|
||||||
|
var _1: [Api.ExportedCommunityInvite]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ExportedCommunityInvite.self)
|
||||||
|
}
|
||||||
|
var _2: [Api.Chat]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
|
||||||
|
}
|
||||||
|
var _3: [Api.User]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
||||||
|
}
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = _3 != nil
|
||||||
|
if _c1 && _c2 && _c3 {
|
||||||
|
return Api.communities.ExportedInvites.exportedInvites(invites: _1!, chats: _2!, users: _3!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public extension Api.community {
|
||||||
|
enum CommunityInvite: TypeConstructorDescription {
|
||||||
|
case communityInvite(peers: [Api.Peer], chats: [Api.Chat], users: [Api.User])
|
||||||
|
case communityInviteAlready(filterId: Int32, missingPeers: [Api.Peer], chats: [Api.Chat], users: [Api.User])
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .communityInvite(let peers, let chats, let users):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(408604768)
|
||||||
|
}
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(peers.count))
|
||||||
|
for item in peers {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(chats.count))
|
||||||
|
for item in chats {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(users.count))
|
||||||
|
for item in users {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case .communityInviteAlready(let filterId, let missingPeers, let chats, let users):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(74184410)
|
||||||
|
}
|
||||||
|
serializeInt32(filterId, buffer: buffer, boxed: false)
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(missingPeers.count))
|
||||||
|
for item in missingPeers {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(chats.count))
|
||||||
|
for item in chats {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(users.count))
|
||||||
|
for item in users {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .communityInvite(let peers, let chats, let users):
|
||||||
|
return ("communityInvite", [("peers", peers as Any), ("chats", chats as Any), ("users", users as Any)])
|
||||||
|
case .communityInviteAlready(let filterId, let missingPeers, let chats, let users):
|
||||||
|
return ("communityInviteAlready", [("filterId", filterId as Any), ("missingPeers", missingPeers as Any), ("chats", chats as Any), ("users", users as Any)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_communityInvite(_ reader: BufferReader) -> CommunityInvite? {
|
||||||
|
var _1: [Api.Peer]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Peer.self)
|
||||||
|
}
|
||||||
|
var _2: [Api.Chat]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
|
||||||
|
}
|
||||||
|
var _3: [Api.User]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
||||||
|
}
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = _3 != nil
|
||||||
|
if _c1 && _c2 && _c3 {
|
||||||
|
return Api.community.CommunityInvite.communityInvite(peers: _1!, chats: _2!, users: _3!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_communityInviteAlready(_ reader: BufferReader) -> CommunityInvite? {
|
||||||
|
var _1: Int32?
|
||||||
|
_1 = reader.readInt32()
|
||||||
|
var _2: [Api.Peer]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Peer.self)
|
||||||
|
}
|
||||||
|
var _3: [Api.Chat]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
|
||||||
|
}
|
||||||
|
var _4: [Api.User]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
||||||
|
}
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = _3 != nil
|
||||||
|
let _c4 = _4 != nil
|
||||||
|
if _c1 && _c2 && _c3 && _c4 {
|
||||||
|
return Api.community.CommunityInvite.communityInviteAlready(filterId: _1!, missingPeers: _2!, chats: _3!, users: _4!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api.contacts {
|
public extension Api.contacts {
|
||||||
enum Blocked: TypeConstructorDescription {
|
enum Blocked: TypeConstructorDescription {
|
||||||
case blocked(blocked: [Api.PeerBlocked], chats: [Api.Chat], users: [Api.User])
|
case blocked(blocked: [Api.PeerBlocked], chats: [Api.Chat], users: [Api.User])
|
||||||
@ -962,143 +1180,3 @@ public extension Api.contacts {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public extension Api.contacts {
|
|
||||||
enum Contacts: TypeConstructorDescription {
|
|
||||||
case contacts(contacts: [Api.Contact], savedCount: Int32, users: [Api.User])
|
|
||||||
case contactsNotModified
|
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
|
||||||
switch self {
|
|
||||||
case .contacts(let contacts, let savedCount, let users):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-353862078)
|
|
||||||
}
|
|
||||||
buffer.appendInt32(481674261)
|
|
||||||
buffer.appendInt32(Int32(contacts.count))
|
|
||||||
for item in contacts {
|
|
||||||
item.serialize(buffer, true)
|
|
||||||
}
|
|
||||||
serializeInt32(savedCount, buffer: buffer, boxed: false)
|
|
||||||
buffer.appendInt32(481674261)
|
|
||||||
buffer.appendInt32(Int32(users.count))
|
|
||||||
for item in users {
|
|
||||||
item.serialize(buffer, true)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case .contactsNotModified:
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-1219778094)
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
|
||||||
switch self {
|
|
||||||
case .contacts(let contacts, let savedCount, let users):
|
|
||||||
return ("contacts", [("contacts", contacts as Any), ("savedCount", savedCount as Any), ("users", users as Any)])
|
|
||||||
case .contactsNotModified:
|
|
||||||
return ("contactsNotModified", [])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func parse_contacts(_ reader: BufferReader) -> Contacts? {
|
|
||||||
var _1: [Api.Contact]?
|
|
||||||
if let _ = reader.readInt32() {
|
|
||||||
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Contact.self)
|
|
||||||
}
|
|
||||||
var _2: Int32?
|
|
||||||
_2 = reader.readInt32()
|
|
||||||
var _3: [Api.User]?
|
|
||||||
if let _ = reader.readInt32() {
|
|
||||||
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
|
||||||
}
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
let _c3 = _3 != nil
|
|
||||||
if _c1 && _c2 && _c3 {
|
|
||||||
return Api.contacts.Contacts.contacts(contacts: _1!, savedCount: _2!, users: _3!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_contactsNotModified(_ reader: BufferReader) -> Contacts? {
|
|
||||||
return Api.contacts.Contacts.contactsNotModified
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public extension Api.contacts {
|
|
||||||
enum Found: TypeConstructorDescription {
|
|
||||||
case found(myResults: [Api.Peer], results: [Api.Peer], chats: [Api.Chat], users: [Api.User])
|
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
|
||||||
switch self {
|
|
||||||
case .found(let myResults, let results, let chats, let users):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-1290580579)
|
|
||||||
}
|
|
||||||
buffer.appendInt32(481674261)
|
|
||||||
buffer.appendInt32(Int32(myResults.count))
|
|
||||||
for item in myResults {
|
|
||||||
item.serialize(buffer, true)
|
|
||||||
}
|
|
||||||
buffer.appendInt32(481674261)
|
|
||||||
buffer.appendInt32(Int32(results.count))
|
|
||||||
for item in results {
|
|
||||||
item.serialize(buffer, true)
|
|
||||||
}
|
|
||||||
buffer.appendInt32(481674261)
|
|
||||||
buffer.appendInt32(Int32(chats.count))
|
|
||||||
for item in chats {
|
|
||||||
item.serialize(buffer, true)
|
|
||||||
}
|
|
||||||
buffer.appendInt32(481674261)
|
|
||||||
buffer.appendInt32(Int32(users.count))
|
|
||||||
for item in users {
|
|
||||||
item.serialize(buffer, true)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
|
||||||
switch self {
|
|
||||||
case .found(let myResults, let results, let chats, let users):
|
|
||||||
return ("found", [("myResults", myResults as Any), ("results", results as Any), ("chats", chats as Any), ("users", users as Any)])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func parse_found(_ reader: BufferReader) -> Found? {
|
|
||||||
var _1: [Api.Peer]?
|
|
||||||
if let _ = reader.readInt32() {
|
|
||||||
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Peer.self)
|
|
||||||
}
|
|
||||||
var _2: [Api.Peer]?
|
|
||||||
if let _ = reader.readInt32() {
|
|
||||||
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Peer.self)
|
|
||||||
}
|
|
||||||
var _3: [Api.Chat]?
|
|
||||||
if let _ = reader.readInt32() {
|
|
||||||
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
|
|
||||||
}
|
|
||||||
var _4: [Api.User]?
|
|
||||||
if let _ = reader.readInt32() {
|
|
||||||
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
|
||||||
}
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
let _c3 = _3 != nil
|
|
||||||
let _c4 = _4 != nil
|
|
||||||
if _c1 && _c2 && _c3 && _c4 {
|
|
||||||
return Api.contacts.Found.found(myResults: _1!, results: _2!, chats: _3!, users: _4!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,3 +1,143 @@
|
|||||||
|
public extension Api.contacts {
|
||||||
|
enum Contacts: TypeConstructorDescription {
|
||||||
|
case contacts(contacts: [Api.Contact], savedCount: Int32, users: [Api.User])
|
||||||
|
case contactsNotModified
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .contacts(let contacts, let savedCount, let users):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-353862078)
|
||||||
|
}
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(contacts.count))
|
||||||
|
for item in contacts {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
serializeInt32(savedCount, buffer: buffer, boxed: false)
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(users.count))
|
||||||
|
for item in users {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case .contactsNotModified:
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-1219778094)
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .contacts(let contacts, let savedCount, let users):
|
||||||
|
return ("contacts", [("contacts", contacts as Any), ("savedCount", savedCount as Any), ("users", users as Any)])
|
||||||
|
case .contactsNotModified:
|
||||||
|
return ("contactsNotModified", [])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_contacts(_ reader: BufferReader) -> Contacts? {
|
||||||
|
var _1: [Api.Contact]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Contact.self)
|
||||||
|
}
|
||||||
|
var _2: Int32?
|
||||||
|
_2 = reader.readInt32()
|
||||||
|
var _3: [Api.User]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
||||||
|
}
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = _3 != nil
|
||||||
|
if _c1 && _c2 && _c3 {
|
||||||
|
return Api.contacts.Contacts.contacts(contacts: _1!, savedCount: _2!, users: _3!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_contactsNotModified(_ reader: BufferReader) -> Contacts? {
|
||||||
|
return Api.contacts.Contacts.contactsNotModified
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public extension Api.contacts {
|
||||||
|
enum Found: TypeConstructorDescription {
|
||||||
|
case found(myResults: [Api.Peer], results: [Api.Peer], chats: [Api.Chat], users: [Api.User])
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .found(let myResults, let results, let chats, let users):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-1290580579)
|
||||||
|
}
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(myResults.count))
|
||||||
|
for item in myResults {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(results.count))
|
||||||
|
for item in results {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(chats.count))
|
||||||
|
for item in chats {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(users.count))
|
||||||
|
for item in users {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .found(let myResults, let results, let chats, let users):
|
||||||
|
return ("found", [("myResults", myResults as Any), ("results", results as Any), ("chats", chats as Any), ("users", users as Any)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_found(_ reader: BufferReader) -> Found? {
|
||||||
|
var _1: [Api.Peer]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Peer.self)
|
||||||
|
}
|
||||||
|
var _2: [Api.Peer]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Peer.self)
|
||||||
|
}
|
||||||
|
var _3: [Api.Chat]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
|
||||||
|
}
|
||||||
|
var _4: [Api.User]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
||||||
|
}
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = _3 != nil
|
||||||
|
let _c4 = _4 != nil
|
||||||
|
if _c1 && _c2 && _c3 && _c4 {
|
||||||
|
return Api.contacts.Found.found(myResults: _1!, results: _2!, chats: _3!, users: _4!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api.contacts {
|
public extension Api.contacts {
|
||||||
enum ImportedContacts: TypeConstructorDescription {
|
enum ImportedContacts: TypeConstructorDescription {
|
||||||
case importedContacts(imported: [Api.ImportedContact], popularInvites: [Api.PopularContact], retryContacts: [Int64], users: [Api.User])
|
case importedContacts(imported: [Api.ImportedContact], popularInvites: [Api.PopularContact], retryContacts: [Int64], users: [Api.User])
|
||||||
@ -1190,141 +1330,3 @@ public extension Api.help {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public extension Api.messages {
|
|
||||||
enum AffectedFoundMessages: TypeConstructorDescription {
|
|
||||||
case affectedFoundMessages(pts: Int32, ptsCount: Int32, offset: Int32, messages: [Int32])
|
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
|
||||||
switch self {
|
|
||||||
case .affectedFoundMessages(let pts, let ptsCount, let offset, let messages):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-275956116)
|
|
||||||
}
|
|
||||||
serializeInt32(pts, buffer: buffer, boxed: false)
|
|
||||||
serializeInt32(ptsCount, buffer: buffer, boxed: false)
|
|
||||||
serializeInt32(offset, buffer: buffer, boxed: false)
|
|
||||||
buffer.appendInt32(481674261)
|
|
||||||
buffer.appendInt32(Int32(messages.count))
|
|
||||||
for item in messages {
|
|
||||||
serializeInt32(item, buffer: buffer, boxed: false)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
|
||||||
switch self {
|
|
||||||
case .affectedFoundMessages(let pts, let ptsCount, let offset, let messages):
|
|
||||||
return ("affectedFoundMessages", [("pts", pts as Any), ("ptsCount", ptsCount as Any), ("offset", offset as Any), ("messages", messages as Any)])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func parse_affectedFoundMessages(_ reader: BufferReader) -> AffectedFoundMessages? {
|
|
||||||
var _1: Int32?
|
|
||||||
_1 = reader.readInt32()
|
|
||||||
var _2: Int32?
|
|
||||||
_2 = reader.readInt32()
|
|
||||||
var _3: Int32?
|
|
||||||
_3 = reader.readInt32()
|
|
||||||
var _4: [Int32]?
|
|
||||||
if let _ = reader.readInt32() {
|
|
||||||
_4 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self)
|
|
||||||
}
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
let _c3 = _3 != nil
|
|
||||||
let _c4 = _4 != nil
|
|
||||||
if _c1 && _c2 && _c3 && _c4 {
|
|
||||||
return Api.messages.AffectedFoundMessages.affectedFoundMessages(pts: _1!, ptsCount: _2!, offset: _3!, messages: _4!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public extension Api.messages {
|
|
||||||
enum AffectedHistory: TypeConstructorDescription {
|
|
||||||
case affectedHistory(pts: Int32, ptsCount: Int32, offset: Int32)
|
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
|
||||||
switch self {
|
|
||||||
case .affectedHistory(let pts, let ptsCount, let offset):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-1269012015)
|
|
||||||
}
|
|
||||||
serializeInt32(pts, buffer: buffer, boxed: false)
|
|
||||||
serializeInt32(ptsCount, buffer: buffer, boxed: false)
|
|
||||||
serializeInt32(offset, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
|
||||||
switch self {
|
|
||||||
case .affectedHistory(let pts, let ptsCount, let offset):
|
|
||||||
return ("affectedHistory", [("pts", pts as Any), ("ptsCount", ptsCount as Any), ("offset", offset as Any)])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func parse_affectedHistory(_ reader: BufferReader) -> AffectedHistory? {
|
|
||||||
var _1: Int32?
|
|
||||||
_1 = reader.readInt32()
|
|
||||||
var _2: Int32?
|
|
||||||
_2 = reader.readInt32()
|
|
||||||
var _3: Int32?
|
|
||||||
_3 = reader.readInt32()
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
let _c3 = _3 != nil
|
|
||||||
if _c1 && _c2 && _c3 {
|
|
||||||
return Api.messages.AffectedHistory.affectedHistory(pts: _1!, ptsCount: _2!, offset: _3!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public extension Api.messages {
|
|
||||||
enum AffectedMessages: TypeConstructorDescription {
|
|
||||||
case affectedMessages(pts: Int32, ptsCount: Int32)
|
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
|
||||||
switch self {
|
|
||||||
case .affectedMessages(let pts, let ptsCount):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-2066640507)
|
|
||||||
}
|
|
||||||
serializeInt32(pts, buffer: buffer, boxed: false)
|
|
||||||
serializeInt32(ptsCount, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
|
||||||
switch self {
|
|
||||||
case .affectedMessages(let pts, let ptsCount):
|
|
||||||
return ("affectedMessages", [("pts", pts as Any), ("ptsCount", ptsCount as Any)])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func parse_affectedMessages(_ reader: BufferReader) -> AffectedMessages? {
|
|
||||||
var _1: Int32?
|
|
||||||
_1 = reader.readInt32()
|
|
||||||
var _2: Int32?
|
|
||||||
_2 = reader.readInt32()
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
if _c1 && _c2 {
|
|
||||||
return Api.messages.AffectedMessages.affectedMessages(pts: _1!, ptsCount: _2!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,3 +1,141 @@
|
|||||||
|
public extension Api.messages {
|
||||||
|
enum AffectedFoundMessages: TypeConstructorDescription {
|
||||||
|
case affectedFoundMessages(pts: Int32, ptsCount: Int32, offset: Int32, messages: [Int32])
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .affectedFoundMessages(let pts, let ptsCount, let offset, let messages):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-275956116)
|
||||||
|
}
|
||||||
|
serializeInt32(pts, buffer: buffer, boxed: false)
|
||||||
|
serializeInt32(ptsCount, buffer: buffer, boxed: false)
|
||||||
|
serializeInt32(offset, buffer: buffer, boxed: false)
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(messages.count))
|
||||||
|
for item in messages {
|
||||||
|
serializeInt32(item, buffer: buffer, boxed: false)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .affectedFoundMessages(let pts, let ptsCount, let offset, let messages):
|
||||||
|
return ("affectedFoundMessages", [("pts", pts as Any), ("ptsCount", ptsCount as Any), ("offset", offset as Any), ("messages", messages as Any)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_affectedFoundMessages(_ reader: BufferReader) -> AffectedFoundMessages? {
|
||||||
|
var _1: Int32?
|
||||||
|
_1 = reader.readInt32()
|
||||||
|
var _2: Int32?
|
||||||
|
_2 = reader.readInt32()
|
||||||
|
var _3: Int32?
|
||||||
|
_3 = reader.readInt32()
|
||||||
|
var _4: [Int32]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_4 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self)
|
||||||
|
}
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = _3 != nil
|
||||||
|
let _c4 = _4 != nil
|
||||||
|
if _c1 && _c2 && _c3 && _c4 {
|
||||||
|
return Api.messages.AffectedFoundMessages.affectedFoundMessages(pts: _1!, ptsCount: _2!, offset: _3!, messages: _4!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public extension Api.messages {
|
||||||
|
enum AffectedHistory: TypeConstructorDescription {
|
||||||
|
case affectedHistory(pts: Int32, ptsCount: Int32, offset: Int32)
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .affectedHistory(let pts, let ptsCount, let offset):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-1269012015)
|
||||||
|
}
|
||||||
|
serializeInt32(pts, buffer: buffer, boxed: false)
|
||||||
|
serializeInt32(ptsCount, buffer: buffer, boxed: false)
|
||||||
|
serializeInt32(offset, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .affectedHistory(let pts, let ptsCount, let offset):
|
||||||
|
return ("affectedHistory", [("pts", pts as Any), ("ptsCount", ptsCount as Any), ("offset", offset as Any)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_affectedHistory(_ reader: BufferReader) -> AffectedHistory? {
|
||||||
|
var _1: Int32?
|
||||||
|
_1 = reader.readInt32()
|
||||||
|
var _2: Int32?
|
||||||
|
_2 = reader.readInt32()
|
||||||
|
var _3: Int32?
|
||||||
|
_3 = reader.readInt32()
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = _3 != nil
|
||||||
|
if _c1 && _c2 && _c3 {
|
||||||
|
return Api.messages.AffectedHistory.affectedHistory(pts: _1!, ptsCount: _2!, offset: _3!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public extension Api.messages {
|
||||||
|
enum AffectedMessages: TypeConstructorDescription {
|
||||||
|
case affectedMessages(pts: Int32, ptsCount: Int32)
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .affectedMessages(let pts, let ptsCount):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-2066640507)
|
||||||
|
}
|
||||||
|
serializeInt32(pts, buffer: buffer, boxed: false)
|
||||||
|
serializeInt32(ptsCount, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .affectedMessages(let pts, let ptsCount):
|
||||||
|
return ("affectedMessages", [("pts", pts as Any), ("ptsCount", ptsCount as Any)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_affectedMessages(_ reader: BufferReader) -> AffectedMessages? {
|
||||||
|
var _1: Int32?
|
||||||
|
_1 = reader.readInt32()
|
||||||
|
var _2: Int32?
|
||||||
|
_2 = reader.readInt32()
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
if _c1 && _c2 {
|
||||||
|
return Api.messages.AffectedMessages.affectedMessages(pts: _1!, ptsCount: _2!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api.messages {
|
public extension Api.messages {
|
||||||
enum AllStickers: TypeConstructorDescription {
|
enum AllStickers: TypeConstructorDescription {
|
||||||
case allStickers(hash: Int64, sets: [Api.StickerSet])
|
case allStickers(hash: Int64, sets: [Api.StickerSet])
|
||||||
@ -1258,145 +1396,3 @@ public extension Api.messages {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public extension Api.messages {
|
|
||||||
enum ForumTopics: TypeConstructorDescription {
|
|
||||||
case forumTopics(flags: Int32, count: Int32, topics: [Api.ForumTopic], messages: [Api.Message], chats: [Api.Chat], users: [Api.User], pts: Int32)
|
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
|
||||||
switch self {
|
|
||||||
case .forumTopics(let flags, let count, let topics, let messages, let chats, let users, let pts):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(913709011)
|
|
||||||
}
|
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
|
||||||
serializeInt32(count, buffer: buffer, boxed: false)
|
|
||||||
buffer.appendInt32(481674261)
|
|
||||||
buffer.appendInt32(Int32(topics.count))
|
|
||||||
for item in topics {
|
|
||||||
item.serialize(buffer, true)
|
|
||||||
}
|
|
||||||
buffer.appendInt32(481674261)
|
|
||||||
buffer.appendInt32(Int32(messages.count))
|
|
||||||
for item in messages {
|
|
||||||
item.serialize(buffer, true)
|
|
||||||
}
|
|
||||||
buffer.appendInt32(481674261)
|
|
||||||
buffer.appendInt32(Int32(chats.count))
|
|
||||||
for item in chats {
|
|
||||||
item.serialize(buffer, true)
|
|
||||||
}
|
|
||||||
buffer.appendInt32(481674261)
|
|
||||||
buffer.appendInt32(Int32(users.count))
|
|
||||||
for item in users {
|
|
||||||
item.serialize(buffer, true)
|
|
||||||
}
|
|
||||||
serializeInt32(pts, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
|
||||||
switch self {
|
|
||||||
case .forumTopics(let flags, let count, let topics, let messages, let chats, let users, let pts):
|
|
||||||
return ("forumTopics", [("flags", flags as Any), ("count", count as Any), ("topics", topics as Any), ("messages", messages as Any), ("chats", chats as Any), ("users", users as Any), ("pts", pts as Any)])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func parse_forumTopics(_ reader: BufferReader) -> ForumTopics? {
|
|
||||||
var _1: Int32?
|
|
||||||
_1 = reader.readInt32()
|
|
||||||
var _2: Int32?
|
|
||||||
_2 = reader.readInt32()
|
|
||||||
var _3: [Api.ForumTopic]?
|
|
||||||
if let _ = reader.readInt32() {
|
|
||||||
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ForumTopic.self)
|
|
||||||
}
|
|
||||||
var _4: [Api.Message]?
|
|
||||||
if let _ = reader.readInt32() {
|
|
||||||
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self)
|
|
||||||
}
|
|
||||||
var _5: [Api.Chat]?
|
|
||||||
if let _ = reader.readInt32() {
|
|
||||||
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
|
|
||||||
}
|
|
||||||
var _6: [Api.User]?
|
|
||||||
if let _ = reader.readInt32() {
|
|
||||||
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
|
||||||
}
|
|
||||||
var _7: Int32?
|
|
||||||
_7 = reader.readInt32()
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
let _c3 = _3 != nil
|
|
||||||
let _c4 = _4 != nil
|
|
||||||
let _c5 = _5 != nil
|
|
||||||
let _c6 = _6 != nil
|
|
||||||
let _c7 = _7 != nil
|
|
||||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
|
|
||||||
return Api.messages.ForumTopics.forumTopics(flags: _1!, count: _2!, topics: _3!, messages: _4!, chats: _5!, users: _6!, pts: _7!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public extension Api.messages {
|
|
||||||
enum FoundStickerSets: TypeConstructorDescription {
|
|
||||||
case foundStickerSets(hash: Int64, sets: [Api.StickerSetCovered])
|
|
||||||
case foundStickerSetsNotModified
|
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
|
||||||
switch self {
|
|
||||||
case .foundStickerSets(let hash, let sets):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-1963942446)
|
|
||||||
}
|
|
||||||
serializeInt64(hash, buffer: buffer, boxed: false)
|
|
||||||
buffer.appendInt32(481674261)
|
|
||||||
buffer.appendInt32(Int32(sets.count))
|
|
||||||
for item in sets {
|
|
||||||
item.serialize(buffer, true)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case .foundStickerSetsNotModified:
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(223655517)
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
|
||||||
switch self {
|
|
||||||
case .foundStickerSets(let hash, let sets):
|
|
||||||
return ("foundStickerSets", [("hash", hash as Any), ("sets", sets as Any)])
|
|
||||||
case .foundStickerSetsNotModified:
|
|
||||||
return ("foundStickerSetsNotModified", [])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func parse_foundStickerSets(_ reader: BufferReader) -> FoundStickerSets? {
|
|
||||||
var _1: Int64?
|
|
||||||
_1 = reader.readInt64()
|
|
||||||
var _2: [Api.StickerSetCovered]?
|
|
||||||
if let _ = reader.readInt32() {
|
|
||||||
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerSetCovered.self)
|
|
||||||
}
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
if _c1 && _c2 {
|
|
||||||
return Api.messages.FoundStickerSets.foundStickerSets(hash: _1!, sets: _2!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_foundStickerSetsNotModified(_ reader: BufferReader) -> FoundStickerSets? {
|
|
||||||
return Api.messages.FoundStickerSets.foundStickerSetsNotModified
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,3 +1,145 @@
|
|||||||
|
public extension Api.messages {
|
||||||
|
enum ForumTopics: TypeConstructorDescription {
|
||||||
|
case forumTopics(flags: Int32, count: Int32, topics: [Api.ForumTopic], messages: [Api.Message], chats: [Api.Chat], users: [Api.User], pts: Int32)
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .forumTopics(let flags, let count, let topics, let messages, let chats, let users, let pts):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(913709011)
|
||||||
|
}
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
|
serializeInt32(count, buffer: buffer, boxed: false)
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(topics.count))
|
||||||
|
for item in topics {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(messages.count))
|
||||||
|
for item in messages {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(chats.count))
|
||||||
|
for item in chats {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(users.count))
|
||||||
|
for item in users {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
serializeInt32(pts, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .forumTopics(let flags, let count, let topics, let messages, let chats, let users, let pts):
|
||||||
|
return ("forumTopics", [("flags", flags as Any), ("count", count as Any), ("topics", topics as Any), ("messages", messages as Any), ("chats", chats as Any), ("users", users as Any), ("pts", pts as Any)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_forumTopics(_ reader: BufferReader) -> ForumTopics? {
|
||||||
|
var _1: Int32?
|
||||||
|
_1 = reader.readInt32()
|
||||||
|
var _2: Int32?
|
||||||
|
_2 = reader.readInt32()
|
||||||
|
var _3: [Api.ForumTopic]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ForumTopic.self)
|
||||||
|
}
|
||||||
|
var _4: [Api.Message]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self)
|
||||||
|
}
|
||||||
|
var _5: [Api.Chat]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
|
||||||
|
}
|
||||||
|
var _6: [Api.User]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
||||||
|
}
|
||||||
|
var _7: Int32?
|
||||||
|
_7 = reader.readInt32()
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = _3 != nil
|
||||||
|
let _c4 = _4 != nil
|
||||||
|
let _c5 = _5 != nil
|
||||||
|
let _c6 = _6 != nil
|
||||||
|
let _c7 = _7 != nil
|
||||||
|
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
|
||||||
|
return Api.messages.ForumTopics.forumTopics(flags: _1!, count: _2!, topics: _3!, messages: _4!, chats: _5!, users: _6!, pts: _7!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public extension Api.messages {
|
||||||
|
enum FoundStickerSets: TypeConstructorDescription {
|
||||||
|
case foundStickerSets(hash: Int64, sets: [Api.StickerSetCovered])
|
||||||
|
case foundStickerSetsNotModified
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .foundStickerSets(let hash, let sets):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-1963942446)
|
||||||
|
}
|
||||||
|
serializeInt64(hash, buffer: buffer, boxed: false)
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(sets.count))
|
||||||
|
for item in sets {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case .foundStickerSetsNotModified:
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(223655517)
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .foundStickerSets(let hash, let sets):
|
||||||
|
return ("foundStickerSets", [("hash", hash as Any), ("sets", sets as Any)])
|
||||||
|
case .foundStickerSetsNotModified:
|
||||||
|
return ("foundStickerSetsNotModified", [])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_foundStickerSets(_ reader: BufferReader) -> FoundStickerSets? {
|
||||||
|
var _1: Int64?
|
||||||
|
_1 = reader.readInt64()
|
||||||
|
var _2: [Api.StickerSetCovered]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerSetCovered.self)
|
||||||
|
}
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
if _c1 && _c2 {
|
||||||
|
return Api.messages.FoundStickerSets.foundStickerSets(hash: _1!, sets: _2!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_foundStickerSetsNotModified(_ reader: BufferReader) -> FoundStickerSets? {
|
||||||
|
return Api.messages.FoundStickerSets.foundStickerSetsNotModified
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api.messages {
|
public extension Api.messages {
|
||||||
enum HighScores: TypeConstructorDescription {
|
enum HighScores: TypeConstructorDescription {
|
||||||
case highScores(scores: [Api.HighScore], users: [Api.User])
|
case highScores(scores: [Api.HighScore], users: [Api.User])
|
||||||
@ -1368,61 +1510,3 @@ public extension Api.messages {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public extension Api.messages {
|
|
||||||
enum Stickers: TypeConstructorDescription {
|
|
||||||
case stickers(hash: Int64, stickers: [Api.Document])
|
|
||||||
case stickersNotModified
|
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
|
||||||
switch self {
|
|
||||||
case .stickers(let hash, let stickers):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(816245886)
|
|
||||||
}
|
|
||||||
serializeInt64(hash, buffer: buffer, boxed: false)
|
|
||||||
buffer.appendInt32(481674261)
|
|
||||||
buffer.appendInt32(Int32(stickers.count))
|
|
||||||
for item in stickers {
|
|
||||||
item.serialize(buffer, true)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case .stickersNotModified:
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-244016606)
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
|
||||||
switch self {
|
|
||||||
case .stickers(let hash, let stickers):
|
|
||||||
return ("stickers", [("hash", hash as Any), ("stickers", stickers as Any)])
|
|
||||||
case .stickersNotModified:
|
|
||||||
return ("stickersNotModified", [])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func parse_stickers(_ reader: BufferReader) -> Stickers? {
|
|
||||||
var _1: Int64?
|
|
||||||
_1 = reader.readInt64()
|
|
||||||
var _2: [Api.Document]?
|
|
||||||
if let _ = reader.readInt32() {
|
|
||||||
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Document.self)
|
|
||||||
}
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
if _c1 && _c2 {
|
|
||||||
return Api.messages.Stickers.stickers(hash: _1!, stickers: _2!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_stickersNotModified(_ reader: BufferReader) -> Stickers? {
|
|
||||||
return Api.messages.Stickers.stickersNotModified
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,3 +1,61 @@
|
|||||||
|
public extension Api.messages {
|
||||||
|
enum Stickers: TypeConstructorDescription {
|
||||||
|
case stickers(hash: Int64, stickers: [Api.Document])
|
||||||
|
case stickersNotModified
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .stickers(let hash, let stickers):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(816245886)
|
||||||
|
}
|
||||||
|
serializeInt64(hash, buffer: buffer, boxed: false)
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(stickers.count))
|
||||||
|
for item in stickers {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case .stickersNotModified:
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-244016606)
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .stickers(let hash, let stickers):
|
||||||
|
return ("stickers", [("hash", hash as Any), ("stickers", stickers as Any)])
|
||||||
|
case .stickersNotModified:
|
||||||
|
return ("stickersNotModified", [])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_stickers(_ reader: BufferReader) -> Stickers? {
|
||||||
|
var _1: Int64?
|
||||||
|
_1 = reader.readInt64()
|
||||||
|
var _2: [Api.Document]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Document.self)
|
||||||
|
}
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
if _c1 && _c2 {
|
||||||
|
return Api.messages.Stickers.stickers(hash: _1!, stickers: _2!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_stickersNotModified(_ reader: BufferReader) -> Stickers? {
|
||||||
|
return Api.messages.Stickers.stickersNotModified
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api.messages {
|
public extension Api.messages {
|
||||||
enum TranscribedAudio: TypeConstructorDescription {
|
enum TranscribedAudio: TypeConstructorDescription {
|
||||||
case transcribedAudio(flags: Int32, transcriptionId: Int64, text: String)
|
case transcribedAudio(flags: Int32, transcriptionId: Int64, text: String)
|
||||||
|
@ -2911,6 +2911,111 @@ public extension Api.functions.channels {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public extension Api.functions.communities {
|
||||||
|
static func checkCommunityInvite(slug: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.community.CommunityInvite>) {
|
||||||
|
let buffer = Buffer()
|
||||||
|
buffer.appendInt32(-1753956947)
|
||||||
|
serializeString(slug, buffer: buffer, boxed: false)
|
||||||
|
return (FunctionDescription(name: "communities.checkCommunityInvite", parameters: [("slug", String(describing: slug))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.community.CommunityInvite? in
|
||||||
|
let reader = BufferReader(buffer)
|
||||||
|
var result: Api.community.CommunityInvite?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
result = Api.parse(reader, signature: signature) as? Api.community.CommunityInvite
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public extension Api.functions.communities {
|
||||||
|
static func deleteExportedInvite(community: Api.InputCommunity, slug: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
||||||
|
let buffer = Buffer()
|
||||||
|
buffer.appendInt32(-110213610)
|
||||||
|
community.serialize(buffer, true)
|
||||||
|
serializeString(slug, buffer: buffer, boxed: false)
|
||||||
|
return (FunctionDescription(name: "communities.deleteExportedInvite", parameters: [("community", String(describing: community)), ("slug", String(describing: slug))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
|
||||||
|
let reader = BufferReader(buffer)
|
||||||
|
var result: Api.Bool?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
result = Api.parse(reader, signature: signature) as? Api.Bool
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public extension Api.functions.communities {
|
||||||
|
static func editExportedInvite(flags: Int32, community: Api.InputCommunity, slug: String, title: String?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.ExportedCommunityInvite>) {
|
||||||
|
let buffer = Buffer()
|
||||||
|
buffer.appendInt32(873155725)
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
|
community.serialize(buffer, true)
|
||||||
|
serializeString(slug, buffer: buffer, boxed: false)
|
||||||
|
if Int(flags) & Int(1 << 1) != 0 {serializeString(title!, buffer: buffer, boxed: false)}
|
||||||
|
return (FunctionDescription(name: "communities.editExportedInvite", parameters: [("flags", String(describing: flags)), ("community", String(describing: community)), ("slug", String(describing: slug)), ("title", String(describing: title))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.ExportedCommunityInvite? in
|
||||||
|
let reader = BufferReader(buffer)
|
||||||
|
var result: Api.ExportedCommunityInvite?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
result = Api.parse(reader, signature: signature) as? Api.ExportedCommunityInvite
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public extension Api.functions.communities {
|
||||||
|
static func exportCommunityInvite(community: Api.InputCommunity, title: String, peers: [Api.InputPeer]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.communities.ExportedCommunityInvite>) {
|
||||||
|
let buffer = Buffer()
|
||||||
|
buffer.appendInt32(1107192281)
|
||||||
|
community.serialize(buffer, true)
|
||||||
|
serializeString(title, buffer: buffer, boxed: false)
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(peers.count))
|
||||||
|
for item in peers {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
return (FunctionDescription(name: "communities.exportCommunityInvite", parameters: [("community", String(describing: community)), ("title", String(describing: title)), ("peers", String(describing: peers))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.communities.ExportedCommunityInvite? in
|
||||||
|
let reader = BufferReader(buffer)
|
||||||
|
var result: Api.communities.ExportedCommunityInvite?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
result = Api.parse(reader, signature: signature) as? Api.communities.ExportedCommunityInvite
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public extension Api.functions.communities {
|
||||||
|
static func getExportedInvites(community: Api.InputCommunity) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.communities.ExportedInvites>) {
|
||||||
|
let buffer = Buffer()
|
||||||
|
buffer.appendInt32(1183359901)
|
||||||
|
community.serialize(buffer, true)
|
||||||
|
return (FunctionDescription(name: "communities.getExportedInvites", parameters: [("community", String(describing: community))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.communities.ExportedInvites? in
|
||||||
|
let reader = BufferReader(buffer)
|
||||||
|
var result: Api.communities.ExportedInvites?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
result = Api.parse(reader, signature: signature) as? Api.communities.ExportedInvites
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public extension Api.functions.communities {
|
||||||
|
static func joinCommunityInvite(slug: String, peers: [Api.InputPeer]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||||
|
let buffer = Buffer()
|
||||||
|
buffer.appendInt32(82835751)
|
||||||
|
serializeString(slug, buffer: buffer, boxed: false)
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(peers.count))
|
||||||
|
for item in peers {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
return (FunctionDescription(name: "communities.joinCommunityInvite", parameters: [("slug", String(describing: slug)), ("peers", String(describing: peers))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||||
|
let reader = BufferReader(buffer)
|
||||||
|
var result: Api.Updates?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
result = Api.parse(reader, signature: signature) as? Api.Updates
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api.functions.contacts {
|
public extension Api.functions.contacts {
|
||||||
static func acceptContact(id: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
static func acceptContact(id: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
|
@ -1015,6 +1015,7 @@ public extension Api {
|
|||||||
public extension Api {
|
public extension Api {
|
||||||
enum DialogFilter: TypeConstructorDescription {
|
enum DialogFilter: TypeConstructorDescription {
|
||||||
case dialogFilter(flags: Int32, id: Int32, title: String, emoticon: String?, pinnedPeers: [Api.InputPeer], includePeers: [Api.InputPeer], excludePeers: [Api.InputPeer])
|
case dialogFilter(flags: Int32, id: Int32, title: String, emoticon: String?, pinnedPeers: [Api.InputPeer], includePeers: [Api.InputPeer], excludePeers: [Api.InputPeer])
|
||||||
|
case dialogFilterCommunity(flags: Int32, id: Int32, title: String, emoticon: String?, pinnedPeers: [Api.InputPeer], includePeers: [Api.InputPeer])
|
||||||
case dialogFilterDefault
|
case dialogFilterDefault
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
@ -1043,6 +1044,25 @@ public extension Api {
|
|||||||
item.serialize(buffer, true)
|
item.serialize(buffer, true)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
case .dialogFilterCommunity(let flags, let id, let title, let emoticon, let pinnedPeers, let includePeers):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-665432009)
|
||||||
|
}
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
|
serializeInt32(id, buffer: buffer, boxed: false)
|
||||||
|
serializeString(title, buffer: buffer, boxed: false)
|
||||||
|
if Int(flags) & Int(1 << 25) != 0 {serializeString(emoticon!, buffer: buffer, boxed: false)}
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(pinnedPeers.count))
|
||||||
|
for item in pinnedPeers {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(includePeers.count))
|
||||||
|
for item in includePeers {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
break
|
||||||
case .dialogFilterDefault:
|
case .dialogFilterDefault:
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(909284270)
|
buffer.appendInt32(909284270)
|
||||||
@ -1056,6 +1076,8 @@ public extension Api {
|
|||||||
switch self {
|
switch self {
|
||||||
case .dialogFilter(let flags, let id, let title, let emoticon, let pinnedPeers, let includePeers, let excludePeers):
|
case .dialogFilter(let flags, let id, let title, let emoticon, let pinnedPeers, let includePeers, let excludePeers):
|
||||||
return ("dialogFilter", [("flags", flags as Any), ("id", id as Any), ("title", title as Any), ("emoticon", emoticon as Any), ("pinnedPeers", pinnedPeers as Any), ("includePeers", includePeers as Any), ("excludePeers", excludePeers as Any)])
|
return ("dialogFilter", [("flags", flags as Any), ("id", id as Any), ("title", title as Any), ("emoticon", emoticon as Any), ("pinnedPeers", pinnedPeers as Any), ("includePeers", includePeers as Any), ("excludePeers", excludePeers as Any)])
|
||||||
|
case .dialogFilterCommunity(let flags, let id, let title, let emoticon, let pinnedPeers, let includePeers):
|
||||||
|
return ("dialogFilterCommunity", [("flags", flags as Any), ("id", id as Any), ("title", title as Any), ("emoticon", emoticon as Any), ("pinnedPeers", pinnedPeers as Any), ("includePeers", includePeers as Any)])
|
||||||
case .dialogFilterDefault:
|
case .dialogFilterDefault:
|
||||||
return ("dialogFilterDefault", [])
|
return ("dialogFilterDefault", [])
|
||||||
}
|
}
|
||||||
@ -1096,6 +1118,36 @@ public extension Api {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public static func parse_dialogFilterCommunity(_ reader: BufferReader) -> DialogFilter? {
|
||||||
|
var _1: Int32?
|
||||||
|
_1 = reader.readInt32()
|
||||||
|
var _2: Int32?
|
||||||
|
_2 = reader.readInt32()
|
||||||
|
var _3: String?
|
||||||
|
_3 = parseString(reader)
|
||||||
|
var _4: String?
|
||||||
|
if Int(_1!) & Int(1 << 25) != 0 {_4 = parseString(reader) }
|
||||||
|
var _5: [Api.InputPeer]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.InputPeer.self)
|
||||||
|
}
|
||||||
|
var _6: [Api.InputPeer]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.InputPeer.self)
|
||||||
|
}
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = _3 != nil
|
||||||
|
let _c4 = (Int(_1!) & Int(1 << 25) == 0) || _4 != nil
|
||||||
|
let _c5 = _5 != nil
|
||||||
|
let _c6 = _6 != nil
|
||||||
|
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
|
||||||
|
return Api.DialogFilter.dialogFilterCommunity(flags: _1!, id: _2!, title: _3!, emoticon: _4, pinnedPeers: _5!, includePeers: _6!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
public static func parse_dialogFilterDefault(_ reader: BufferReader) -> DialogFilter? {
|
public static func parse_dialogFilterDefault(_ reader: BufferReader) -> DialogFilter? {
|
||||||
return Api.DialogFilter.dialogFilterDefault
|
return Api.DialogFilter.dialogFilterDefault
|
||||||
}
|
}
|
||||||
|
@ -1024,6 +1024,56 @@ public extension Api {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public extension Api {
|
||||||
|
enum ExportedCommunityInvite: TypeConstructorDescription {
|
||||||
|
case exportedCommunityInvite(title: String, url: String, peers: [Api.Peer])
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .exportedCommunityInvite(let title, let url, let peers):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-1350894801)
|
||||||
|
}
|
||||||
|
serializeString(title, buffer: buffer, boxed: false)
|
||||||
|
serializeString(url, buffer: buffer, boxed: false)
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(peers.count))
|
||||||
|
for item in peers {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .exportedCommunityInvite(let title, let url, let peers):
|
||||||
|
return ("exportedCommunityInvite", [("title", title as Any), ("url", url as Any), ("peers", peers as Any)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_exportedCommunityInvite(_ reader: BufferReader) -> ExportedCommunityInvite? {
|
||||||
|
var _1: String?
|
||||||
|
_1 = parseString(reader)
|
||||||
|
var _2: String?
|
||||||
|
_2 = parseString(reader)
|
||||||
|
var _3: [Api.Peer]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Peer.self)
|
||||||
|
}
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = _3 != nil
|
||||||
|
if _c1 && _c2 && _c3 {
|
||||||
|
return Api.ExportedCommunityInvite.exportedCommunityInvite(title: _1!, url: _2!, peers: _3!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api {
|
public extension Api {
|
||||||
enum ExportedContactToken: TypeConstructorDescription {
|
enum ExportedContactToken: TypeConstructorDescription {
|
||||||
case exportedContactToken(url: String, expires: Int32)
|
case exportedContactToken(url: String, expires: Int32)
|
||||||
@ -1064,43 +1114,3 @@ public extension Api {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public extension Api {
|
|
||||||
enum ExportedMessageLink: TypeConstructorDescription {
|
|
||||||
case exportedMessageLink(link: String, html: String)
|
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
|
||||||
switch self {
|
|
||||||
case .exportedMessageLink(let link, let html):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(1571494644)
|
|
||||||
}
|
|
||||||
serializeString(link, buffer: buffer, boxed: false)
|
|
||||||
serializeString(html, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
|
||||||
switch self {
|
|
||||||
case .exportedMessageLink(let link, let html):
|
|
||||||
return ("exportedMessageLink", [("link", link as Any), ("html", html as Any)])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func parse_exportedMessageLink(_ reader: BufferReader) -> ExportedMessageLink? {
|
|
||||||
var _1: String?
|
|
||||||
_1 = parseString(reader)
|
|
||||||
var _2: String?
|
|
||||||
_2 = parseString(reader)
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
if _c1 && _c2 {
|
|
||||||
return Api.ExportedMessageLink.exportedMessageLink(link: _1!, html: _2!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,3 +1,43 @@
|
|||||||
|
public extension Api {
|
||||||
|
enum ExportedMessageLink: TypeConstructorDescription {
|
||||||
|
case exportedMessageLink(link: String, html: String)
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .exportedMessageLink(let link, let html):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(1571494644)
|
||||||
|
}
|
||||||
|
serializeString(link, buffer: buffer, boxed: false)
|
||||||
|
serializeString(html, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .exportedMessageLink(let link, let html):
|
||||||
|
return ("exportedMessageLink", [("link", link as Any), ("html", html as Any)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_exportedMessageLink(_ reader: BufferReader) -> ExportedMessageLink? {
|
||||||
|
var _1: String?
|
||||||
|
_1 = parseString(reader)
|
||||||
|
var _2: String?
|
||||||
|
_2 = parseString(reader)
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
if _c1 && _c2 {
|
||||||
|
return Api.ExportedMessageLink.exportedMessageLink(link: _1!, html: _2!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api {
|
public extension Api {
|
||||||
enum FileHash: TypeConstructorDescription {
|
enum FileHash: TypeConstructorDescription {
|
||||||
case fileHash(offset: Int64, limit: Int32, hash: Buffer)
|
case fileHash(offset: Int64, limit: Int32, hash: Buffer)
|
||||||
|
@ -532,6 +532,42 @@ public extension Api {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public extension Api {
|
||||||
|
enum InputCommunity: TypeConstructorDescription {
|
||||||
|
case inputCommunityDialogFilter(filterId: Int32)
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .inputCommunityDialogFilter(let filterId):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(450955169)
|
||||||
|
}
|
||||||
|
serializeInt32(filterId, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .inputCommunityDialogFilter(let filterId):
|
||||||
|
return ("inputCommunityDialogFilter", [("filterId", filterId as Any)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_inputCommunityDialogFilter(_ reader: BufferReader) -> InputCommunity? {
|
||||||
|
var _1: Int32?
|
||||||
|
_1 = reader.readInt32()
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
if _c1 {
|
||||||
|
return Api.InputCommunity.inputCommunityDialogFilter(filterId: _1!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api {
|
public extension Api {
|
||||||
enum InputContact: TypeConstructorDescription {
|
enum InputContact: TypeConstructorDescription {
|
||||||
case inputPhoneContact(clientId: Int64, phone: String, firstName: String, lastName: String)
|
case inputPhoneContact(clientId: Int64, phone: String, firstName: String, lastName: String)
|
||||||
|
@ -210,7 +210,7 @@ public class BoxedMessage: NSObject {
|
|||||||
|
|
||||||
public class Serialization: NSObject, MTSerialization {
|
public class Serialization: NSObject, MTSerialization {
|
||||||
public func currentLayer() -> UInt {
|
public func currentLayer() -> UInt {
|
||||||
return 156
|
return 158
|
||||||
}
|
}
|
||||||
|
|
||||||
public func parseMessage(_ data: Data!) -> Any! {
|
public func parseMessage(_ data: Data!) -> Any! {
|
||||||
|
@ -174,6 +174,7 @@ extension ChatListFilterIncludePeers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public struct ChatListFilterData: Equatable, Hashable {
|
public struct ChatListFilterData: Equatable, Hashable {
|
||||||
|
public var isShared: Bool
|
||||||
public var categories: ChatListFilterPeerCategories
|
public var categories: ChatListFilterPeerCategories
|
||||||
public var excludeMuted: Bool
|
public var excludeMuted: Bool
|
||||||
public var excludeRead: Bool
|
public var excludeRead: Bool
|
||||||
@ -182,6 +183,7 @@ public struct ChatListFilterData: Equatable, Hashable {
|
|||||||
public var excludePeers: [PeerId]
|
public var excludePeers: [PeerId]
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
|
isShared: Bool,
|
||||||
categories: ChatListFilterPeerCategories,
|
categories: ChatListFilterPeerCategories,
|
||||||
excludeMuted: Bool,
|
excludeMuted: Bool,
|
||||||
excludeRead: Bool,
|
excludeRead: Bool,
|
||||||
@ -189,6 +191,7 @@ public struct ChatListFilterData: Equatable, Hashable {
|
|||||||
includePeers: ChatListFilterIncludePeers,
|
includePeers: ChatListFilterIncludePeers,
|
||||||
excludePeers: [PeerId]
|
excludePeers: [PeerId]
|
||||||
) {
|
) {
|
||||||
|
self.isShared = isShared
|
||||||
self.categories = categories
|
self.categories = categories
|
||||||
self.excludeMuted = excludeMuted
|
self.excludeMuted = excludeMuted
|
||||||
self.excludeRead = excludeRead
|
self.excludeRead = excludeRead
|
||||||
@ -246,6 +249,7 @@ public enum ChatListFilter: Codable, Equatable {
|
|||||||
let emoticon = try container.decodeIfPresent(String.self, forKey: "emoticon")
|
let emoticon = try container.decodeIfPresent(String.self, forKey: "emoticon")
|
||||||
|
|
||||||
let data = ChatListFilterData(
|
let data = ChatListFilterData(
|
||||||
|
isShared: try container.decodeIfPresent(Bool.self, forKey: "isShared") ?? false,
|
||||||
categories: ChatListFilterPeerCategories(rawValue: try container.decode(Int32.self, forKey: "categories")),
|
categories: ChatListFilterPeerCategories(rawValue: try container.decode(Int32.self, forKey: "categories")),
|
||||||
excludeMuted: (try container.decode(Int32.self, forKey: "excludeMuted")) != 0,
|
excludeMuted: (try container.decode(Int32.self, forKey: "excludeMuted")) != 0,
|
||||||
excludeRead: (try container.decode(Int32.self, forKey: "excludeRead")) != 0,
|
excludeRead: (try container.decode(Int32.self, forKey: "excludeRead")) != 0,
|
||||||
@ -275,6 +279,7 @@ public enum ChatListFilter: Codable, Equatable {
|
|||||||
try container.encode(title, forKey: "title")
|
try container.encode(title, forKey: "title")
|
||||||
try container.encodeIfPresent(emoticon, forKey: "emoticon")
|
try container.encodeIfPresent(emoticon, forKey: "emoticon")
|
||||||
|
|
||||||
|
try container.encode(data.isShared, forKey: "isShared")
|
||||||
try container.encode(data.categories.rawValue, forKey: "categories")
|
try container.encode(data.categories.rawValue, forKey: "categories")
|
||||||
try container.encode((data.excludeMuted ? 1 : 0) as Int32, forKey: "excludeMuted")
|
try container.encode((data.excludeMuted ? 1 : 0) as Int32, forKey: "excludeMuted")
|
||||||
try container.encode((data.excludeRead ? 1 : 0) as Int32, forKey: "excludeRead")
|
try container.encode((data.excludeRead ? 1 : 0) as Int32, forKey: "excludeRead")
|
||||||
@ -297,6 +302,7 @@ extension ChatListFilter {
|
|||||||
title: title,
|
title: title,
|
||||||
emoticon: emoticon,
|
emoticon: emoticon,
|
||||||
data: ChatListFilterData(
|
data: ChatListFilterData(
|
||||||
|
isShared: false,
|
||||||
categories: ChatListFilterPeerCategories(apiFlags: flags),
|
categories: ChatListFilterPeerCategories(apiFlags: flags),
|
||||||
excludeMuted: (flags & (1 << 11)) != 0,
|
excludeMuted: (flags & (1 << 11)) != 0,
|
||||||
excludeRead: (flags & (1 << 12)) != 0,
|
excludeRead: (flags & (1 << 12)) != 0,
|
||||||
@ -338,6 +344,43 @@ extension ChatListFilter {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
case let .dialogFilterCommunity(_, id, title, emoticon, pinnedPeers, includePeers):
|
||||||
|
self = .filter(
|
||||||
|
id: id,
|
||||||
|
title: title,
|
||||||
|
emoticon: emoticon,
|
||||||
|
data: ChatListFilterData(
|
||||||
|
isShared: true,
|
||||||
|
categories: [],
|
||||||
|
excludeMuted: false,
|
||||||
|
excludeRead: false,
|
||||||
|
excludeArchived: false,
|
||||||
|
includePeers: ChatListFilterIncludePeers(rawPeers: includePeers.compactMap { peer -> PeerId? in
|
||||||
|
switch peer {
|
||||||
|
case let .inputPeerUser(userId, _):
|
||||||
|
return PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
|
||||||
|
case let .inputPeerChat(chatId):
|
||||||
|
return PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(chatId))
|
||||||
|
case let .inputPeerChannel(channelId, _):
|
||||||
|
return PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId))
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}, rawPinnedPeers: pinnedPeers.compactMap { peer -> PeerId? in
|
||||||
|
switch peer {
|
||||||
|
case let .inputPeerUser(userId, _):
|
||||||
|
return PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
|
||||||
|
case let .inputPeerChat(chatId):
|
||||||
|
return PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(chatId))
|
||||||
|
case let .inputPeerChannel(channelId, _):
|
||||||
|
return PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId))
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
excludePeers: []
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -455,6 +498,46 @@ private func requestChatListFilters(accountPeerId: PeerId, postbox: Postbox, net
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for peer in pinnedPeers {
|
||||||
|
var peerId: PeerId?
|
||||||
|
switch peer {
|
||||||
|
case let .inputPeerUser(userId, _):
|
||||||
|
peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
|
||||||
|
case let .inputPeerChat(chatId):
|
||||||
|
peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(chatId))
|
||||||
|
case let .inputPeerChannel(channelId, _):
|
||||||
|
peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId))
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if let peerId = peerId, !missingChatIds.contains(peerId) {
|
||||||
|
if transaction.getPeerChatListIndex(peerId) == nil {
|
||||||
|
missingChatIds.insert(peerId)
|
||||||
|
missingChats.append(peer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case let .dialogFilterCommunity(_, _, _, _, pinnedPeers, includePeers):
|
||||||
|
for peer in pinnedPeers + includePeers {
|
||||||
|
var peerId: PeerId?
|
||||||
|
switch peer {
|
||||||
|
case let .inputPeerUser(userId, _):
|
||||||
|
peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
|
||||||
|
case let .inputPeerChat(chatId):
|
||||||
|
peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(chatId))
|
||||||
|
case let .inputPeerChannel(channelId, _):
|
||||||
|
peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId))
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if let peerId = peerId {
|
||||||
|
if transaction.getPeer(peerId) == nil && !missingPeerIds.contains(peerId) {
|
||||||
|
missingPeerIds.insert(peerId)
|
||||||
|
missingPeers.append(peer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for peer in pinnedPeers {
|
for peer in pinnedPeers {
|
||||||
var peerId: PeerId?
|
var peerId: PeerId?
|
||||||
switch peer {
|
switch peer {
|
||||||
@ -931,6 +1014,7 @@ public struct ChatListFeaturedFilter: Codable, Equatable {
|
|||||||
self.title = try container.decode(String.self, forKey: "title")
|
self.title = try container.decode(String.self, forKey: "title")
|
||||||
self.description = try container.decode(String.self, forKey: "description")
|
self.description = try container.decode(String.self, forKey: "description")
|
||||||
self.data = ChatListFilterData(
|
self.data = ChatListFilterData(
|
||||||
|
isShared: try container.decodeIfPresent(Bool.self, forKey: "isShared") ?? false,
|
||||||
categories: ChatListFilterPeerCategories(rawValue: try container.decode(Int32.self, forKey: "categories")),
|
categories: ChatListFilterPeerCategories(rawValue: try container.decode(Int32.self, forKey: "categories")),
|
||||||
excludeMuted: (try container.decode(Int32.self, forKey: "excludeMuted")) != 0,
|
excludeMuted: (try container.decode(Int32.self, forKey: "excludeMuted")) != 0,
|
||||||
excludeRead: (try container.decode(Int32.self, forKey: "excludeRead")) != 0,
|
excludeRead: (try container.decode(Int32.self, forKey: "excludeRead")) != 0,
|
||||||
|
@ -0,0 +1,117 @@
|
|||||||
|
import Foundation
|
||||||
|
import SwiftSignalKit
|
||||||
|
import Postbox
|
||||||
|
import TelegramApi
|
||||||
|
|
||||||
|
//communities.exportCommunityInvite#41fe69d9 community:InputCommunity title:string peers:Vector<InputPeer> = communities.ExportedCommunityInvite;
|
||||||
|
//communities.exportedCommunityInvite#6b97a8ea filter:DialogFilter invite:ExportedCommunityInvite = communities.ExportedCommunityInvite;
|
||||||
|
//exportedCommunityInvite#af7afb2f title:string url:string peers:Vector<Peer> = ExportedCommunityInvite;
|
||||||
|
|
||||||
|
public enum ExportChatFolderError {
|
||||||
|
case generic
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct ExportedChatFolderLink: Equatable {
|
||||||
|
public var title: String
|
||||||
|
public var link: String
|
||||||
|
public var peerIds: [EnginePeer.Id]
|
||||||
|
|
||||||
|
public init(
|
||||||
|
title: String,
|
||||||
|
link: String,
|
||||||
|
peerIds: [EnginePeer.Id]
|
||||||
|
) {
|
||||||
|
self.title = title
|
||||||
|
self.link = link
|
||||||
|
self.peerIds = peerIds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func _internal_exportChatFolder(account: Account, filterId: Int32, title: String, peerIds: [PeerId]) -> Signal<ExportedChatFolderLink, ExportChatFolderError> {
|
||||||
|
return account.postbox.transaction { transaction -> [Api.InputPeer] in
|
||||||
|
return peerIds.compactMap(transaction.getPeer).compactMap(apiInputPeer)
|
||||||
|
}
|
||||||
|
|> castError(ExportChatFolderError.self)
|
||||||
|
|> mapToSignal { inputPeers -> Signal<ExportedChatFolderLink, ExportChatFolderError> in
|
||||||
|
return account.network.request(Api.functions.communities.exportCommunityInvite(community: .inputCommunityDialogFilter(filterId: filterId), title: title, peers: inputPeers))
|
||||||
|
|> mapError { _ -> ExportChatFolderError in
|
||||||
|
return .generic
|
||||||
|
}
|
||||||
|
|> mapToSignal { result -> Signal<ExportedChatFolderLink, ExportChatFolderError> in
|
||||||
|
return account.postbox.transaction { transaction -> Signal<ExportedChatFolderLink, ExportChatFolderError> in
|
||||||
|
switch result {
|
||||||
|
case let .exportedCommunityInvite(filter, invite):
|
||||||
|
let parsedFilter = ChatListFilter(apiFilter: filter)
|
||||||
|
|
||||||
|
let _ = updateChatListFiltersState(transaction: transaction, { state in
|
||||||
|
var state = state
|
||||||
|
if let index = state.filters.firstIndex(where: { $0.id == filterId }) {
|
||||||
|
state.filters[index] = parsedFilter
|
||||||
|
} else {
|
||||||
|
state.filters.append(parsedFilter)
|
||||||
|
}
|
||||||
|
state.remoteFilters = state.filters
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
|
||||||
|
switch invite {
|
||||||
|
case let .exportedCommunityInvite(title, url, peers):
|
||||||
|
return .single(ExportedChatFolderLink(
|
||||||
|
title: title,
|
||||||
|
link: url,
|
||||||
|
peerIds: peers.map(\.peerId)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> castError(ExportChatFolderError.self)
|
||||||
|
|> switchToLatest
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func _internal_getExportedChatLinks(account: Account, id: Int32) -> Signal<[ExportedChatFolderLink], NoError> {
|
||||||
|
return account.network.request(Api.functions.communities.getExportedInvites(community: .inputCommunityDialogFilter(filterId: id)))
|
||||||
|
|> map(Optional.init)
|
||||||
|
|> `catch` { _ -> Signal<Api.communities.ExportedInvites?, NoError> in
|
||||||
|
return .single(nil)
|
||||||
|
}
|
||||||
|
|> mapToSignal { result -> Signal<[ExportedChatFolderLink], NoError> in
|
||||||
|
guard let result = result else {
|
||||||
|
return .single([])
|
||||||
|
}
|
||||||
|
return account.postbox.transaction { transaction -> [ExportedChatFolderLink] in
|
||||||
|
switch result {
|
||||||
|
case let .exportedInvites(invites, chats, users):
|
||||||
|
var peers: [Peer] = []
|
||||||
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
|
|
||||||
|
for user in users {
|
||||||
|
let telegramUser = TelegramUser(user: user)
|
||||||
|
peers.append(telegramUser)
|
||||||
|
peerPresences[telegramUser.id] = user
|
||||||
|
}
|
||||||
|
for chat in chats {
|
||||||
|
if let peer = parseTelegramGroupOrChannel(chat: chat) {
|
||||||
|
peers.append(peer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in
|
||||||
|
return updated
|
||||||
|
})
|
||||||
|
updatePeerPresences(transaction: transaction, accountPeerId: account.peerId, peerPresences: peerPresences)
|
||||||
|
|
||||||
|
var result: [ExportedChatFolderLink] = []
|
||||||
|
for invite in invites {
|
||||||
|
switch invite {
|
||||||
|
case let .exportedCommunityInvite(title, url, peers):
|
||||||
|
result.append(ExportedChatFolderLink(title: title, link: url, peerIds: peers.map(\.peerId)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1025,6 +1025,14 @@ public extension TelegramEngine {
|
|||||||
|> ignoreValues
|
|> ignoreValues
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func exportChatFolder(filterId: Int32, title: String, peerIds: [PeerId]) -> Signal<ExportedChatFolderLink, ExportChatFolderError> {
|
||||||
|
return _internal_exportChatFolder(account: self.account, filterId: filterId, title: title, peerIds: peerIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func getExportedChatLinks(id: Int32) -> Signal<[ExportedChatFolderLink], NoError> {
|
||||||
|
return _internal_getExportedChatLinks(account: self.account, id: id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user