mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Folder improvements
This commit is contained in:
parent
195b4a0159
commit
dfe8e80232
@ -1547,7 +1547,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
for filter in filters {
|
||||
if filter.id == filterId, case let .filter(_, title, _, data) = filter {
|
||||
if !data.includePeers.peers.isEmpty && data.categories.isEmpty && !data.excludeRead && !data.excludeMuted && !data.excludeArchived && data.excludePeers.isEmpty {
|
||||
items.append(.action(ContextMenuActionItem(text: "Share", textColor: .primary, badge: ContextMenuActionBadge(value: "NEW", color: .accent, style: .label), icon: { theme in
|
||||
items.append(.action(ContextMenuActionItem(text: "Share", textColor: .primary, badge: data.hasSharedLinks ? nil : ContextMenuActionBadge(value: "NEW", color: .accent, style: .label), icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Link"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
|
@ -1044,7 +1044,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
var includePeers = ChatListFilterIncludePeers()
|
||||
includePeers.setPeers(state.additionallyIncludePeers)
|
||||
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 filter: ChatListFilter = .filter(id: currentPreset?.id ?? -1, title: state.name, emoticon: currentPreset?.emoticon, data: ChatListFilterData(isShared: currentPreset?.data?.isShared ?? false, hasSharedLinks: currentPreset?.data?.hasSharedLinks ?? false, categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: includePeers, excludePeers: state.additionallyExcludePeers))
|
||||
if let data = filter.data {
|
||||
switch chatListFilterType(data) {
|
||||
case .generic:
|
||||
@ -1189,7 +1189,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
||||
let state = stateValue.with { $0 }
|
||||
var includePeers = ChatListFilterIncludePeers()
|
||||
includePeers.setPeers(state.additionallyIncludePeers)
|
||||
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 filter: ChatListFilter = .filter(id: currentPreset?.id ?? -1, title: state.name, emoticon: currentPreset?.emoticon, data: ChatListFilterData(isShared: currentPreset?.data?.isShared ?? false, hasSharedLinks: currentPreset?.data?.hasSharedLinks ?? false, categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: includePeers, excludePeers: state.additionallyExcludePeers))
|
||||
|
||||
let _ = (context.engine.peers.currentChatListFilters()
|
||||
|> deliverOnMainQueue).start(next: { filters in
|
||||
@ -1211,7 +1211,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
||||
let state = stateValue.with { $0 }
|
||||
var includePeers = ChatListFilterIncludePeers()
|
||||
includePeers.setPeers(state.additionallyIncludePeers)
|
||||
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 filter: ChatListFilter = .filter(id: currentPreset?.id ?? -1, title: state.name, emoticon: currentPreset?.emoticon, data: ChatListFilterData(isShared: currentPreset?.data?.isShared ?? false, hasSharedLinks: currentPreset?.data?.hasSharedLinks ?? false, categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: includePeers, excludePeers: state.additionallyExcludePeers))
|
||||
|
||||
let _ = (context.engine.peers.currentChatListFilters()
|
||||
|> deliverOnMainQueue).start(next: { filters in
|
||||
@ -1328,9 +1328,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
||||
previousLink = updatedLink
|
||||
|
||||
let _ = (sharedLinks.get() |> take(1) |> deliverOnMainQueue).start(next: { links in
|
||||
guard var links else {
|
||||
return
|
||||
}
|
||||
var links = links ?? []
|
||||
|
||||
if let updatedLink {
|
||||
if let index = links.firstIndex(where: { $0.link == updatedLink.link }) {
|
||||
@ -1356,9 +1354,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
||||
pushControllerImpl?(folderInviteLinkListController(context: context, filterId: currentPreset.id, title: currentPreset.title, allPeerIds: state.additionallyIncludePeers, currentInvitation: link, linkUpdated: { updatedLink in
|
||||
if updatedLink != link {
|
||||
let _ = (sharedLinks.get() |> take(1) |> deliverOnMainQueue).start(next: { links in
|
||||
guard var links else {
|
||||
return
|
||||
}
|
||||
var links = links ?? []
|
||||
|
||||
if let updatedLink {
|
||||
if let index = links.firstIndex(where: { $0.link == link.link }) {
|
||||
@ -1381,9 +1377,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
||||
removeLink: { link in
|
||||
if let currentPreset {
|
||||
let _ = (sharedLinks.get() |> take(1) |> deliverOnMainQueue).start(next: { links in
|
||||
guard var links else {
|
||||
return
|
||||
}
|
||||
var links = links ?? []
|
||||
|
||||
if let index = links.firstIndex(where: { $0.link == link.link }) {
|
||||
links.remove(at: index)
|
||||
@ -1407,7 +1401,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
||||
if currentPreset == nil {
|
||||
filterId = context.engine.peers.generateNewChatListFilterId(filters: filters)
|
||||
}
|
||||
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 updatedFilter: ChatListFilter = .filter(id: filterId, title: state.name, emoticon: currentPreset?.emoticon, data: ChatListFilterData(isShared: currentPreset?.data?.isShared ?? false, hasSharedLinks: currentPreset?.data?.hasSharedLinks ?? false, categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: includePeers, excludePeers: state.additionallyExcludePeers))
|
||||
|
||||
var filters = filters
|
||||
if let _ = currentPreset {
|
||||
@ -1554,7 +1548,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
||||
|
||||
var includePeers = ChatListFilterIncludePeers()
|
||||
includePeers.setPeers(state.additionallyIncludePeers)
|
||||
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))
|
||||
let filter: ChatListFilter = .filter(id: currentPreset.id, title: state.name, emoticon: currentPreset.emoticon, data: ChatListFilterData(isShared: currentPreset.data?.isShared ?? false, hasSharedLinks: currentPreset.data?.hasSharedLinks ?? false, categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: includePeers, excludePeers: state.additionallyExcludePeers))
|
||||
if currentPresetWithoutPinnedPeers != filter {
|
||||
displaySaveAlert()
|
||||
return false
|
||||
|
@ -30,7 +30,7 @@ private final class FolderInviteLinkListControllerArguments {
|
||||
let copyLink: (String) -> Void
|
||||
let mainLinkContextAction: (ExportedChatFolderLink?, ASDisplayNode, ContextGesture?) -> Void
|
||||
let peerAction: (EnginePeer, Bool) -> Void
|
||||
let generateLink: () -> Void
|
||||
let toggleAllSelected: () -> Void
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
@ -39,7 +39,7 @@ private final class FolderInviteLinkListControllerArguments {
|
||||
copyLink: @escaping (String) -> Void,
|
||||
mainLinkContextAction: @escaping (ExportedChatFolderLink?, ASDisplayNode, ContextGesture?) -> Void,
|
||||
peerAction: @escaping (EnginePeer, Bool) -> Void,
|
||||
generateLink: @escaping () -> Void
|
||||
toggleAllSelected: @escaping () -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.shareMainLink = shareMainLink
|
||||
@ -47,7 +47,7 @@ private final class FolderInviteLinkListControllerArguments {
|
||||
self.copyLink = copyLink
|
||||
self.mainLinkContextAction = mainLinkContextAction
|
||||
self.peerAction = peerAction
|
||||
self.generateLink = generateLink
|
||||
self.toggleAllSelected = toggleAllSelected
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,7 +68,7 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
|
||||
case mainLinkHeader(String)
|
||||
case mainLink(link: ExportedChatFolderLink?, isGenerating: Bool)
|
||||
|
||||
case peersHeader(String)
|
||||
case peersHeader(String, String?)
|
||||
case peer(index: Int, peer: EnginePeer, isSelected: Bool, disabledReasonText: String?)
|
||||
case peersInfo(String)
|
||||
|
||||
@ -137,8 +137,8 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .peersHeader(text):
|
||||
if case .peersHeader(text) = rhs {
|
||||
case let .peersHeader(text, action):
|
||||
if case .peersHeader(text, action) = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -177,8 +177,6 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
|
||||
}, shareAction: {
|
||||
if let link {
|
||||
arguments.copyLink(link.link)
|
||||
} else {
|
||||
arguments.generateLink()
|
||||
}
|
||||
}, secondaryAction: {
|
||||
if let link {
|
||||
@ -191,8 +189,10 @@ private enum InviteLinksListEntry: ItemListNodeEntry {
|
||||
arguments.openMainLink(link.link)
|
||||
}
|
||||
})
|
||||
case let .peersHeader(text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .peersHeader(text, action):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, actionText: action, action: action == nil ? nil : {
|
||||
arguments.toggleAllSelected()
|
||||
}, sectionId: self.section)
|
||||
case let .peersInfo(text):
|
||||
return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section)
|
||||
case let .peer(_, peer, isSelected, disabledReasonText):
|
||||
@ -239,6 +239,9 @@ private func folderInviteLinkListControllerEntries(
|
||||
let peersHeaderString: String
|
||||
|
||||
let canShareChats = !allPeers.allSatisfy({ !canShareLinkToPeer(peer: $0) })
|
||||
let allSelected = allPeers.filter({ canShareLinkToPeer(peer: $0) }).allSatisfy({ state.selectedPeerIds.contains($0.id) })
|
||||
|
||||
var selectAllString: String?
|
||||
|
||||
if !canShareChats {
|
||||
infoString = "You can only share groups and channels in which you are allowed to create invite links."
|
||||
@ -247,12 +250,21 @@ private func folderInviteLinkListControllerEntries(
|
||||
} else if state.selectedPeerIds.isEmpty {
|
||||
chatCountString = "Anyone with this link can add **\(title)** folder and the chats selected below."
|
||||
peersHeaderString = "CHATS"
|
||||
if allPeers.count > 1 {
|
||||
selectAllString = allSelected ? "DESELECT ALL" : "SELECT ALL"
|
||||
}
|
||||
} else if state.selectedPeerIds.count == 1 {
|
||||
chatCountString = "Anyone with this link can add **\(title)** folder and the 1 chat selected below."
|
||||
peersHeaderString = "1 CHAT SELECTED"
|
||||
if allPeers.count > 1 {
|
||||
selectAllString = allSelected ? "DESELECT ALL" : "SELECT ALL"
|
||||
}
|
||||
} else {
|
||||
chatCountString = "Anyone with this link can add **\(title)** folder and the \(state.selectedPeerIds.count) chats selected below."
|
||||
peersHeaderString = "\(state.selectedPeerIds.count) CHATS SELECTED"
|
||||
if allPeers.count > 1 {
|
||||
selectAllString = allSelected ? "DESELECT ALL" : "SELECT ALL"
|
||||
}
|
||||
}
|
||||
entries.append(.header(chatCountString))
|
||||
|
||||
@ -263,7 +275,7 @@ private func folderInviteLinkListControllerEntries(
|
||||
entries.append(.mainLink(link: state.currentLink, isGenerating: state.generatingLink))
|
||||
}
|
||||
|
||||
entries.append(.peersHeader(peersHeaderString))
|
||||
entries.append(.peersHeader(peersHeaderString, selectAllString))
|
||||
|
||||
var sortedPeers: [EnginePeer] = []
|
||||
for peer in allPeers.filter({ canShareLinkToPeer(peer: $0) }) {
|
||||
@ -338,6 +350,20 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese
|
||||
|
||||
var didDisplayAddPeerNotice: Bool = false
|
||||
|
||||
var combinedPeerIds: [EnginePeer.Id] = []
|
||||
if let currentInvitation {
|
||||
for peerId in currentInvitation.peerIds {
|
||||
if !combinedPeerIds.contains(peerId) {
|
||||
combinedPeerIds.append(peerId)
|
||||
}
|
||||
}
|
||||
}
|
||||
for peerId in allPeerIds {
|
||||
if !combinedPeerIds.contains(peerId) {
|
||||
combinedPeerIds.append(peerId)
|
||||
}
|
||||
}
|
||||
|
||||
let arguments = FolderInviteLinkListControllerArguments(context: context, shareMainLink: { inviteLink in
|
||||
let shareController = ShareController(context: context, subject: .url(inviteLink), updatedPresentationData: updatedPresentationData)
|
||||
shareController.completed = { peerIds in
|
||||
@ -500,47 +526,33 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese
|
||||
dismissTooltipsImpl?()
|
||||
displayTooltipImpl?(.peers(context: context, peers: [peer], title: nil, text: text, customUndoText: nil))
|
||||
}
|
||||
}, generateLink: {
|
||||
let currentState = stateValue.with({ $0 })
|
||||
if !currentState.generatingLink {
|
||||
updateState { state in
|
||||
var state = state
|
||||
}, toggleAllSelected: {
|
||||
let _ = (context.engine.data.get(
|
||||
EngineDataList(combinedPeerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:)))
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { allPeers in
|
||||
let allPeers = allPeers.compactMap({ $0 })
|
||||
|
||||
state.generatingLink = true
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
actionsDisposable.add((context.engine.peers.exportChatFolder(filterId: filterId, title: "", peerIds: Array(currentState.selectedPeerIds))
|
||||
|> deliverOnMainQueue).start(next: { result in
|
||||
linkUpdated(result)
|
||||
let selectablePeers = allPeers.filter({ canShareLinkToPeer(peer: $0) })
|
||||
let state = stateValue.with({ $0 })
|
||||
let allSelected = selectablePeers.allSatisfy({ state.selectedPeerIds.contains($0.id) })
|
||||
|
||||
updateState { state in
|
||||
var state = state
|
||||
|
||||
state.generatingLink = false
|
||||
state.currentLink = result
|
||||
if allSelected {
|
||||
state.selectedPeerIds.removeAll()
|
||||
} else {
|
||||
state.selectedPeerIds.removeAll()
|
||||
for peer in selectablePeers {
|
||||
state.selectedPeerIds.insert(peer.id)
|
||||
}
|
||||
}
|
||||
|
||||
return state
|
||||
}
|
||||
}, error: { _ in
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
var combinedPeerIds: [EnginePeer.Id] = []
|
||||
if let currentInvitation {
|
||||
for peerId in currentInvitation.peerIds {
|
||||
if !combinedPeerIds.contains(peerId) {
|
||||
combinedPeerIds.append(peerId)
|
||||
}
|
||||
}
|
||||
}
|
||||
for peerId in allPeerIds {
|
||||
if !combinedPeerIds.contains(peerId) {
|
||||
combinedPeerIds.append(peerId)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
let allPeers = context.engine.data.subscribe(
|
||||
EngineDataList(combinedPeerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:)))
|
||||
|
@ -45,17 +45,21 @@ public class ItemListSectionHeaderItem: ListViewItem, ItemListItem {
|
||||
let multiline: Bool
|
||||
let activityIndicator: ItemListSectionHeaderActivityIndicator
|
||||
let accessoryText: ItemListSectionHeaderAccessoryText?
|
||||
let actionText: String?
|
||||
let action: (() -> Void)?
|
||||
public let sectionId: ItemListSectionId
|
||||
|
||||
public let isAlwaysPlain: Bool = true
|
||||
|
||||
public init(presentationData: ItemListPresentationData, text: String, badge: String? = nil, multiline: Bool = false, activityIndicator: ItemListSectionHeaderActivityIndicator = .none, accessoryText: ItemListSectionHeaderAccessoryText? = nil, sectionId: ItemListSectionId) {
|
||||
public init(presentationData: ItemListPresentationData, text: String, badge: String? = nil, multiline: Bool = false, activityIndicator: ItemListSectionHeaderActivityIndicator = .none, accessoryText: ItemListSectionHeaderAccessoryText? = nil, actionText: String? = nil, action: (() -> Void)? = nil, sectionId: ItemListSectionId) {
|
||||
self.presentationData = presentationData
|
||||
self.text = text
|
||||
self.badge = badge
|
||||
self.multiline = multiline
|
||||
self.activityIndicator = activityIndicator
|
||||
self.accessoryText = accessoryText
|
||||
self.actionText = actionText
|
||||
self.action = action
|
||||
self.sectionId = sectionId
|
||||
}
|
||||
|
||||
@ -104,6 +108,8 @@ public class ItemListSectionHeaderItemNode: ListViewItemNode {
|
||||
private let accessoryTextNode: TextNode
|
||||
private var accessoryImageNode: ASImageNode?
|
||||
private var activityIndicator: ActivityIndicator?
|
||||
private var actionNode: TextNode?
|
||||
private var actionButtonNode: HighlightableButtonNode?
|
||||
|
||||
private let activateArea: AccessibilityAreaNode
|
||||
|
||||
@ -130,6 +136,7 @@ public class ItemListSectionHeaderItemNode: ListViewItemNode {
|
||||
|
||||
public func asyncLayout() -> (_ item: ItemListSectionHeaderItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
||||
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
||||
let makeActionLayout = TextNode.asyncLayout(self.actionNode)
|
||||
let makeBadgeTextLayout = TextNode.asyncLayout(self.badgeTextNode)
|
||||
let makeAccessoryTextLayout = TextNode.asyncLayout(self.accessoryTextNode)
|
||||
|
||||
@ -152,6 +159,13 @@ public class ItemListSectionHeaderItemNode: ListViewItemNode {
|
||||
textRightInset += badgeLayoutAndApply.0.size.width + badgeSpacing
|
||||
}
|
||||
|
||||
var actionLayoutAndApply: (TextNodeLayout, () -> TextNode)?
|
||||
if let actionText = item.actionText {
|
||||
let actionLayoutAndApplyValue = makeActionLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: actionText, font: titleFont, textColor: item.presentationData.theme.list.itemAccentColor), backgroundColor: nil, maximumNumberOfLines: item.multiline ? 0 : 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - textRightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
actionLayoutAndApply = actionLayoutAndApplyValue
|
||||
textRightInset += actionLayoutAndApplyValue.0.size.width + 2.0
|
||||
}
|
||||
|
||||
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.text, font: titleFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: item.multiline ? 0 : 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - textRightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
var accessoryTextString: NSAttributedString?
|
||||
var accessoryIcon: UIImage?
|
||||
@ -195,6 +209,39 @@ public class ItemListSectionHeaderItemNode: ListViewItemNode {
|
||||
|
||||
strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: leftInset, y: 7.0), size: titleLayout.size)
|
||||
|
||||
if let (actionLayout, actionApply) = actionLayoutAndApply {
|
||||
let actionButtonNode: HighlightableButtonNode
|
||||
if let current = strongSelf.actionButtonNode {
|
||||
actionButtonNode = current
|
||||
} else {
|
||||
actionButtonNode = HighlightableButtonNode()
|
||||
strongSelf.actionButtonNode = actionButtonNode
|
||||
actionButtonNode.hitTestSlop = UIEdgeInsets(top: -4.0, left: -4.0, bottom: -4.0, right: -4.0)
|
||||
strongSelf.addSubnode(actionButtonNode)
|
||||
actionButtonNode.addTarget(strongSelf, action: #selector(strongSelf.actionButtonPressed), forControlEvents: .touchUpInside)
|
||||
}
|
||||
|
||||
let actionNode = actionApply()
|
||||
if strongSelf.actionNode !== actionNode {
|
||||
strongSelf.actionNode?.removeFromSupernode()
|
||||
strongSelf.actionNode = actionNode
|
||||
actionButtonNode.addSubnode(actionNode)
|
||||
}
|
||||
|
||||
actionButtonNode.frame = CGRect(origin: CGPoint(x: params.width - leftInset - actionLayout.size.width, y: 7.0), size: actionLayout.size)
|
||||
|
||||
actionNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: actionLayout.size)
|
||||
} else {
|
||||
if let actionNode = strongSelf.actionNode {
|
||||
strongSelf.actionNode = nil
|
||||
actionNode.removeFromSupernode()
|
||||
}
|
||||
if let actionButtonNode = strongSelf.actionButtonNode {
|
||||
strongSelf.actionButtonNode = nil
|
||||
actionButtonNode.removeFromSupernode()
|
||||
}
|
||||
}
|
||||
|
||||
if let badgeLayoutAndApply {
|
||||
let badgeTextNode = badgeLayoutAndApply.1()
|
||||
let badgeSideInset: CGFloat = 4.0
|
||||
@ -296,6 +343,10 @@ public class ItemListSectionHeaderItemNode: ListViewItemNode {
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func actionButtonPressed() {
|
||||
self.item?.action?()
|
||||
}
|
||||
|
||||
override public func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
||||
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
||||
}
|
||||
|
@ -175,6 +175,7 @@ extension ChatListFilterIncludePeers {
|
||||
|
||||
public struct ChatListFilterData: Equatable, Hashable {
|
||||
public var isShared: Bool
|
||||
public var hasSharedLinks: Bool
|
||||
public var categories: ChatListFilterPeerCategories
|
||||
public var excludeMuted: Bool
|
||||
public var excludeRead: Bool
|
||||
@ -184,6 +185,7 @@ public struct ChatListFilterData: Equatable, Hashable {
|
||||
|
||||
public init(
|
||||
isShared: Bool,
|
||||
hasSharedLinks: Bool,
|
||||
categories: ChatListFilterPeerCategories,
|
||||
excludeMuted: Bool,
|
||||
excludeRead: Bool,
|
||||
@ -192,6 +194,7 @@ public struct ChatListFilterData: Equatable, Hashable {
|
||||
excludePeers: [PeerId]
|
||||
) {
|
||||
self.isShared = isShared
|
||||
self.hasSharedLinks = hasSharedLinks
|
||||
self.categories = categories
|
||||
self.excludeMuted = excludeMuted
|
||||
self.excludeRead = excludeRead
|
||||
@ -250,6 +253,7 @@ public enum ChatListFilter: Codable, Equatable {
|
||||
|
||||
let data = ChatListFilterData(
|
||||
isShared: try container.decodeIfPresent(Bool.self, forKey: "isShared") ?? false,
|
||||
hasSharedLinks: try container.decodeIfPresent(Bool.self, forKey: "hasSharedLinks") ?? false,
|
||||
categories: ChatListFilterPeerCategories(rawValue: try container.decode(Int32.self, forKey: "categories")),
|
||||
excludeMuted: (try container.decode(Int32.self, forKey: "excludeMuted")) != 0,
|
||||
excludeRead: (try container.decode(Int32.self, forKey: "excludeRead")) != 0,
|
||||
@ -280,6 +284,7 @@ public enum ChatListFilter: Codable, Equatable {
|
||||
try container.encodeIfPresent(emoticon, forKey: "emoticon")
|
||||
|
||||
try container.encode(data.isShared, forKey: "isShared")
|
||||
try container.encode(data.hasSharedLinks, forKey: "hasSharedLinks")
|
||||
try container.encode(data.categories.rawValue, forKey: "categories")
|
||||
try container.encode((data.excludeMuted ? 1 : 0) as Int32, forKey: "excludeMuted")
|
||||
try container.encode((data.excludeRead ? 1 : 0) as Int32, forKey: "excludeRead")
|
||||
@ -303,6 +308,7 @@ extension ChatListFilter {
|
||||
emoticon: emoticon,
|
||||
data: ChatListFilterData(
|
||||
isShared: false,
|
||||
hasSharedLinks: false,
|
||||
categories: ChatListFilterPeerCategories(apiFlags: flags),
|
||||
excludeMuted: (flags & (1 << 11)) != 0,
|
||||
excludeRead: (flags & (1 << 12)) != 0,
|
||||
@ -344,13 +350,14 @@ extension ChatListFilter {
|
||||
}
|
||||
)
|
||||
)
|
||||
case let .dialogFilterCommunity(_, id, title, emoticon, pinnedPeers, includePeers):
|
||||
case let .dialogFilterCommunity(flags, id, title, emoticon, pinnedPeers, includePeers):
|
||||
self = .filter(
|
||||
id: id,
|
||||
title: title,
|
||||
emoticon: emoticon,
|
||||
data: ChatListFilterData(
|
||||
isShared: true,
|
||||
hasSharedLinks: (flags & (1 << 26)) != 0,
|
||||
categories: [],
|
||||
excludeMuted: false,
|
||||
excludeRead: false,
|
||||
@ -1078,7 +1085,8 @@ public struct ChatListFeaturedFilter: Codable, Equatable {
|
||||
self.title = try container.decode(String.self, forKey: "title")
|
||||
self.description = try container.decode(String.self, forKey: "description")
|
||||
self.data = ChatListFilterData(
|
||||
isShared: try container.decodeIfPresent(Bool.self, forKey: "isShared") ?? false,
|
||||
isShared: false,
|
||||
hasSharedLinks: false,
|
||||
categories: ChatListFilterPeerCategories(rawValue: try container.decode(Int32.self, forKey: "categories")),
|
||||
excludeMuted: (try container.decode(Int32.self, forKey: "excludeMuted")) != 0,
|
||||
excludeRead: (try container.decode(Int32.self, forKey: "excludeRead")) != 0,
|
||||
|
@ -539,24 +539,29 @@ private struct FirstTimeFolderUpdatesKey: Hashable {
|
||||
private var firstTimeFolderUpdates = Set<FirstTimeFolderUpdatesKey>()
|
||||
|
||||
func _internal_pollChatFolderUpdatesOnce(account: Account, folderId: Int32) -> Signal<Never, NoError> {
|
||||
return account.postbox.transaction { transaction -> ChatListFiltersState in
|
||||
return _internal_currentChatListFiltersState(transaction: transaction)
|
||||
return account.postbox.transaction { transaction -> (ChatListFiltersState, AppConfiguration) in
|
||||
return (_internal_currentChatListFiltersState(transaction: transaction), currentAppConfiguration(transaction: transaction))
|
||||
}
|
||||
|> mapToSignal { state -> Signal<Never, NoError> in
|
||||
|> mapToSignal { state, appConfig -> Signal<Never, NoError> in
|
||||
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||
let key = FirstTimeFolderUpdatesKey(accountId: account.id, folderId: folderId)
|
||||
|
||||
if firstTimeFolderUpdates.contains(key) {
|
||||
if let current = state.updates.first(where: { $0.folderId == folderId }) {
|
||||
let updateInterval: Int32
|
||||
var updateInterval: Int32 = 3600
|
||||
|
||||
if let data = appConfig.data {
|
||||
if let value = data["community_update_period"] as? Double {
|
||||
updateInterval = Int32(value)
|
||||
}
|
||||
}
|
||||
#if DEBUG
|
||||
if "".isEmpty {
|
||||
updateInterval = 5
|
||||
#else
|
||||
updateInterval = 60 * 60
|
||||
}
|
||||
#endif
|
||||
|
||||
if current.timestamp + updateInterval >= timestamp {
|
||||
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user