diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 72b05a7180..33c098db5c 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -1394,29 +1394,32 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController } let context = strongSelf.context - let filterPeersAreMuted: Signal = strongSelf.context.engine.peers.currentChatListFilters() + let filterPeersAreMuted: Signal<(areMuted: Bool, peerIds: [EnginePeer.Id])?, NoError> = strongSelf.context.engine.peers.currentChatListFilters() |> take(1) - |> mapToSignal { filters -> Signal in + |> mapToSignal { filters -> Signal<(areMuted: Bool, peerIds: [EnginePeer.Id])?, NoError> in guard let filter = filters.first(where: { $0.id == id }) else { - return .single(false) + return .single(nil) } guard case let .filter(_, _, _, data) = filter else { - return .single(false) + return .single(nil) } - return context.engine.data.get( - EngineDataMap(data.includePeers.peers.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:))), - EngineDataMap(data.includePeers.peers.map(TelegramEngine.EngineData.Item.Peer.NotificationSettings.init(id:))), - TelegramEngine.EngineData.Item.NotificationSettings.Global() - ) - |> map { peers, list, globalSettings -> Bool in - for peerId in data.includePeers.peers { - switch list[peerId]?.muteState { - case .unmuted: - return false - case .default: - if let peer = peers[peerId], let peerValue = peer { + + let filterPredicate: ChatListFilterPredicate = chatListFilterPredicate(filter: data) + return context.engine.peers.getChatListPeers(filterPredicate: filterPredicate) + |> mapToSignal { peers -> Signal<(areMuted: Bool, peerIds: [EnginePeer.Id])?, NoError> in + let peerIds = peers.map(\.id) + return context.engine.data.get( + EngineDataMap(peerIds.map(TelegramEngine.EngineData.Item.Peer.NotificationSettings.init(id:))), + TelegramEngine.EngineData.Item.NotificationSettings.Global() + ) + |> map { list, globalSettings -> (areMuted: Bool, peerIds: [EnginePeer.Id])? in + for peer in peers { + switch list[peer.id]?.muteState { + case .unmuted: + return (false, peerIds) + case .default: let globalValue: EngineGlobalNotificationSettings.CategorySettings - switch peerValue { + switch peer { case .user, .secretChat: globalValue = globalSettings.privateChats case .legacyGroup: @@ -1429,14 +1432,14 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController } } if globalValue.enabled { - return false + return (false, peerIds) } + default: + break } - default: - break } + return (true, peerIds) } - return true } } @@ -1600,9 +1603,9 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController for filter in filters { if filter.id == filterId, case let .filter(_, title, _, data) = filter { - if data.categories.isEmpty && !data.excludeRead && !data.excludeMuted && !data.excludeArchived && data.excludePeers.isEmpty && !data.includePeers.peers.isEmpty { - items.append(.action(ContextMenuActionItem(text: filterPeersAreMuted ? "Unmute All" : "Mute All", textColor: .primary, badge: nil, icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: filterPeersAreMuted ? "Chat/Context Menu/Unmute" : "Chat/Context Menu/Muted"), color: theme.contextMenu.primaryColor) + if let filterPeersAreMuted { + items.append(.action(ContextMenuActionItem(text: filterPeersAreMuted.areMuted ? "Unmute All" : "Mute All", textColor: .primary, badge: nil, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: filterPeersAreMuted.areMuted ? "Chat/Context Menu/Unmute" : "Chat/Context Menu/Muted"), color: theme.contextMenu.primaryColor) }, action: { c, f in c.dismiss(completion: { }) @@ -1611,7 +1614,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController return } - let _ = (strongSelf.context.engine.peers.updateMultiplePeerMuteSettings(peerIds: data.includePeers.peers, muted: !filterPeersAreMuted) + let _ = (strongSelf.context.engine.peers.updateMultiplePeerMuteSettings(peerIds: filterPeersAreMuted.peerIds, muted: !filterPeersAreMuted.areMuted) |> deliverOnMainQueue).start(completed: { guard let strongSelf = self else { return @@ -1619,7 +1622,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController let iconColor: UIColor = .white let overlayController: UndoOverlayController - if !filterPeersAreMuted { + if !filterPeersAreMuted.areMuted { overlayController = UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_profilemute", scale: 0.075, colors: [ "Middle.Group 1.Fill 1": iconColor, "Top.Group 1.Fill 1": iconColor, @@ -2827,6 +2830,8 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController self?.push(c) }, presentController: { [weak self] c in self?.present(c, in: .window(.root)) + }, pushPremiumController: { [weak self] c in + self?.push(c) }, completed: { }, linkUpdated: { _ in }) diff --git a/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift b/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift index 88b754bb42..db327fd667 100644 --- a/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift +++ b/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift @@ -1155,6 +1155,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset initi var applyImpl: ((Bool, @escaping () -> Void) -> Void)? var getControllerImpl: (() -> ViewController?)? var presentInGlobalOverlayImpl: ((ViewController) -> Void)? + var pushPremiumController: ((ViewController) -> Void)? let sharedLinks = Promise<[ExportedChatFolderLink]?>(nil) if let initialPreset { @@ -1385,7 +1386,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset initi let state = stateValue.with({ $0 }) if state.additionallyIncludePeers.isEmpty { //TODO:localize - let text = "Please add chats to this folder to share it." + let text = "You can’t share folders which have chat types or excluded chats." presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) return @@ -1424,6 +1425,8 @@ func chatListFilterPresetController(context: AccountContext, currentPreset initi pushControllerImpl?(c) }, presentController: { c in presentControllerImpl?(c, nil) + }, pushPremiumController: { c in + pushPremiumController?(c) }, completed: { statusController?.dismiss() statusController = nil @@ -1769,6 +1772,11 @@ func chatListFilterPresetController(context: AccountContext, currentPreset initi controller.presentInGlobalOverlay(c) } } + pushPremiumController = { [weak controller] c in + if let controller = controller { + controller.replace(with: c) + } + } attemptNavigationImpl = { f in let _ = (updatedCurrentPreset |> take(1) |> deliverOnMainQueue).start(next: { currentPreset in let state = stateValue.with { $0 } @@ -1803,7 +1811,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset initi return controller } -func openCreateChatListFolderLink(context: AccountContext, folderId: Int32, checkIfExists: Bool, title: String, peerIds: [EnginePeer.Id], pushController: @escaping (ViewController) -> Void, presentController: @escaping (ViewController) -> Void, completed: @escaping () -> Void, linkUpdated: @escaping (ExportedChatFolderLink?) -> Void) { +func openCreateChatListFolderLink(context: AccountContext, folderId: Int32, checkIfExists: Bool, title: String, peerIds: [EnginePeer.Id], pushController: @escaping (ViewController) -> Void, presentController: @escaping (ViewController) -> Void, pushPremiumController: @escaping (ViewController) -> Void, completed: @escaping () -> Void, linkUpdated: @escaping (ExportedChatFolderLink?) -> Void) { if peerIds.isEmpty { completed() return @@ -1898,24 +1906,28 @@ func openCreateChatListFolderLink(context: AccountContext, folderId: Int32, chec text = "An error occurred" case let .sharedFolderLimitExceeded(limit, _): let limitController = context.sharedContext.makePremiumLimitController(context: context, subject: .membershipInSharedFolders, count: limit, action: { + pushPremiumController(PremiumIntroScreen(context: context, source: .membershipInSharedFolders)) }) pushController(limitController) return case let .limitExceeded(limit, _): let limitController = context.sharedContext.makePremiumLimitController(context: context, subject: .linksPerSharedFolder, count: limit, action: { + pushPremiumController(PremiumIntroScreen(context: context, source: .linksPerSharedFolder)) }) pushController(limitController) return case let .tooManyChannels(limit, _): let limitController = context.sharedContext.makePremiumLimitController(context: context, subject: .linksPerSharedFolder, count: limit, action: { + pushPremiumController(PremiumIntroScreen(context: context, source: .groupsAndChannels)) }) pushController(limitController) return case let .tooManyChannelsInAccount(limit, _): let limitController = context.sharedContext.makePremiumLimitController(context: context, subject: .channels, count: limit, action: { + pushPremiumController(PremiumIntroScreen(context: context, source: .groupsAndChannels)) }) pushController(limitController) diff --git a/submodules/Postbox/Sources/ChatListTable.swift b/submodules/Postbox/Sources/ChatListTable.swift index 3d2d766506..cfd1cc4a5f 100644 --- a/submodules/Postbox/Sources/ChatListTable.swift +++ b/submodules/Postbox/Sources/ChatListTable.swift @@ -265,6 +265,50 @@ final class ChatListTable: Table { } } + func getChatListPeers(postbox: PostboxImpl, currentTransaction: Transaction, groupId: PeerGroupId, filterPredicate: ChatListFilterPredicate?, additionalFilter: ((Peer) -> Bool)?) -> [Peer] { + let globalNotificationSettings = postbox.getGlobalNotificationSettings(transaction: currentTransaction) + + var result: [Peer] = [] + self.valueBox.range(self.table, start: self.upperBound(groupId: groupId), end: self.lowerBound(groupId: groupId), keys: { key in + let (_, _, messageIndex, _) = extractKey(key) + if let peer = postbox.peerTable.get(messageIndex.id.peerId) { + //let state = postbox.readStateTable.getCombinedState(messageIndex.id.peerId), state.isUnread + + var passFilter: Bool + if let filterPredicate = filterPredicate { + let isUnread = postbox.readStateTable.getCombinedState(messageIndex.id.peerId)?.isUnread ?? false + let isContact = postbox.contactsTable.isContact(peerId: messageIndex.id.peerId) + + let isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettings, peer: peer, peerSettings: postbox.peerNotificationSettingsTable.getEffective(messageIndex.id.peerId)) + + let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peer.id, threadId: nil, calculation: filterPredicate.messageTagSummary) + + if filterPredicate.pinnedPeerIds.contains(peer.id) { + passFilter = true + } else if filterPredicate.includes(peer: peer, groupId: groupId, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: isContact, messageTagSummaryResult: messageTagSummaryResult) { + passFilter = true + } else { + passFilter = false + } + } else { + passFilter = true + } + + if passFilter, let additionalFilter = additionalFilter { + if !additionalFilter(peer) { + passFilter = false + } + } + + if passFilter { + result.append(peer) + } + } + return true + }, limit: 0) + return result + } + func getUnreadChatListPeerIds(postbox: PostboxImpl, currentTransaction: Transaction, groupId: PeerGroupId, filterPredicate: ChatListFilterPredicate?, additionalFilter: ((Peer) -> Bool)?, stopOnFirstMatch: Bool) -> [PeerId] { let globalNotificationSettings = postbox.getGlobalNotificationSettings(transaction: currentTransaction) diff --git a/submodules/Postbox/Sources/Postbox.swift b/submodules/Postbox/Sources/Postbox.swift index 2d35853aaa..1f765a4334 100644 --- a/submodules/Postbox/Sources/Postbox.swift +++ b/submodules/Postbox/Sources/Postbox.swift @@ -389,6 +389,15 @@ public final class Transaction { return self.postbox?.chatListTable.getPeerChatListIndex(peerId: peerId) } + public func getChatListPeers(groupId: PeerGroupId, filterPredicate: ChatListFilterPredicate?, additionalFilter: ((Peer) -> Bool)?) -> [Peer] { + assert(!self.disposed) + if let postbox = self.postbox { + return postbox.chatListTable.getChatListPeers(postbox: postbox, currentTransaction: self, groupId: groupId, filterPredicate: filterPredicate, additionalFilter: additionalFilter) + } else { + return [] + } + } + public func getUnreadChatListPeerIds(groupId: PeerGroupId, filterPredicate: ChatListFilterPredicate?, additionalFilter: ((Peer) -> Bool)?, stopOnFirstMatch: Bool) -> [PeerId] { assert(!self.disposed) if let postbox = self.postbox { diff --git a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift index 511563eefc..b2b16fb876 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift @@ -3405,6 +3405,22 @@ func replayFinalState( for (space, _) in holesAtHistoryStart { transaction.removeHole(peerId: chatPeerId, threadId: nil, namespace: Namespaces.Message.Cloud, space: space, range: 1 ... id.id) } + case let .setChatWallpaper(wallpaper): + if chatPeerId == accountPeerId { + transaction.updatePeerCachedData(peerIds: [message.id.peerId], update: { peerId, current in + var current = current + if current == nil { + if peerId.namespace == Namespaces.Peer.CloudUser { + current = CachedUserData() + } + } + if let cachedData = current as? CachedUserData { + return cachedData.withUpdatedWallpaper(wallpaper) + } else { + return current + } + }) + } default: break } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift index 2ece79bff4..c51b687b89 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift @@ -649,6 +649,12 @@ public extension TelegramEngine { public func updateBotAbout(peerId: PeerId, about: String) -> Signal { return _internal_updateBotAbout(account: self.account, peerId: peerId, about: about) } + + public func getChatListPeers(filterPredicate: ChatListFilterPredicate) -> Signal<[EnginePeer], NoError> { + return self.account.postbox.transaction { transaction -> [EnginePeer] in + return transaction.getChatListPeers(groupId: .root, filterPredicate: filterPredicate, additionalFilter: nil).map(EnginePeer.init) + } + } public func getNextUnreadChannel(peerId: PeerId, chatListFilterId: Int32?, getFilterPredicate: @escaping (ChatListFilterData) -> ChatListFilterPredicate) -> Signal<(peer: EnginePeer, unreadCount: Int, location: NextUnreadChannelLocation)?, NoError> { return self.account.postbox.transaction { transaction -> (peer: EnginePeer, unreadCount: Int, location: NextUnreadChannelLocation)? in