diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 610a38efa6..5fa2cb54b5 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -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: { diff --git a/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift b/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift index 8adde8655c..5148efe60d 100644 --- a/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift +++ b/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift @@ -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 diff --git a/submodules/InviteLinksUI/Sources/FolderInviteLinkListController.swift b/submodules/InviteLinksUI/Sources/FolderInviteLinkListController.swift index d3a21e4360..75a048e55f 100644 --- a/submodules/InviteLinksUI/Sources/FolderInviteLinkListController.swift +++ b/submodules/InviteLinksUI/Sources/FolderInviteLinkListController.swift @@ -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,48 +526,34 @@ 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 { + }, 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 }) + + 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 = true + if allSelected { + state.selectedPeerIds.removeAll() + } else { + state.selectedPeerIds.removeAll() + for peer in selectablePeers { + state.selectedPeerIds.insert(peer.id) + } + } return state } - - actionsDisposable.add((context.engine.peers.exportChatFolder(filterId: filterId, title: "", peerIds: Array(currentState.selectedPeerIds)) - |> deliverOnMainQueue).start(next: { result in - linkUpdated(result) - - updateState { state in - var state = state - - state.generatingLink = false - state.currentLink = result - - 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:))) ) diff --git a/submodules/ItemListUI/Sources/Items/ItemListSectionHeaderItem.swift b/submodules/ItemListUI/Sources/Items/ItemListSectionHeaderItem.swift index 2289a35072..af59c31803 100644 --- a/submodules/ItemListUI/Sources/Items/ItemListSectionHeaderItem.swift +++ b/submodules/ItemListUI/Sources/Items/ItemListSectionHeaderItem.swift @@ -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) } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChatListFiltering.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChatListFiltering.swift index cff9b3cc86..2a862cb933 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChatListFiltering.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChatListFiltering.swift @@ -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, diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/Communities.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/Communities.swift index 2ba2c7b7dd..3846486ddb 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/Communities.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/Communities.swift @@ -539,24 +539,29 @@ private struct FirstTimeFolderUpdatesKey: Hashable { private var firstTimeFolderUpdates = Set() func _internal_pollChatFolderUpdatesOnce(account: Account, folderId: Int32) -> Signal { - 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 in + |> mapToSignal { state, appConfig -> Signal 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 - updateInterval = 5 -#else - updateInterval = 60 * 60 + if "".isEmpty { + updateInterval = 5 + } #endif if current.timestamp + updateInterval >= timestamp { - return .complete() } }