diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift index a97e9441b4..b545d74054 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift @@ -927,10 +927,15 @@ private final class ProfileGiftsContextImpl { private var sorting: ProfileGiftsContext.Sorting = .date private var filter: ProfileGiftsContext.Filters = ProfileGiftsContext.Filters.All + private var gifts: [ProfileGiftsContext.State.StarGift] = [] - private var filteredGifts: [ProfileGiftsContext.State.StarGift] = [] private var count: Int32? private var dataState: ProfileGiftsContext.State.DataState = .ready(canLoadMore: true, nextOffset: nil) + + private var filteredGifts: [ProfileGiftsContext.State.StarGift] = [] + private var filteredCount: Int32? + private var filteredDataState: ProfileGiftsContext.State.DataState = .ready(canLoadMore: true, nextOffset: nil) + private var notificationsEnabled: Bool? var _state: ProfileGiftsContext.State? @@ -958,9 +963,15 @@ private final class ProfileGiftsContextImpl { let accountPeerId = self.account.peerId let network = self.account.network let postbox = self.account.postbox + let filter = self.filter + let sorting = self.sorting - if case let .ready(true, initialNextOffset) = self.dataState { - if self.gifts.isEmpty, initialNextOffset == nil { + let isFiltered = self.filter != .All || self.sorting != .date + + let dataState = isFiltered ? self.filteredDataState : self.dataState + + if case let .ready(true, initialNextOffset) = dataState { + if !isFiltered, self.gifts.isEmpty, initialNextOffset == nil { self.cacheDisposable.set((self.account.postbox.transaction { transaction -> CachedProfileGifts? in let cachedGifts = transaction.retrieveItemCacheEntry(id: entryId(peerId: peerId))?.get(CachedProfileGifts.self) cachedGifts?.render(transaction: transaction) @@ -978,7 +989,11 @@ private final class ProfileGiftsContextImpl { })) } - self.dataState = .loading + if isFiltered { + self.filteredDataState = .loading + } else { + self.dataState = .loading + } self.pushState() let signal: Signal<([ProfileGiftsContext.State.StarGift], Int32, String?, Bool?), NoError> = self.account.postbox.transaction { transaction -> Api.InputPeer? in @@ -988,7 +1003,25 @@ private final class ProfileGiftsContextImpl { guard let inputPeer else { return .single(([], 0, nil, nil)) } - let flags: Int32 = 0 + var flags: Int32 = 0 + if case .value = sorting { + flags |= (1 << 5) + } + if !filter.contains(.hidden) { + flags |= (1 << 0) + } + if !filter.contains(.displayed) { + flags |= (1 << 1) + } + if !filter.contains(.unlimited) { + flags |= (1 << 2) + } + if !filter.contains(.limited) { + flags |= (1 << 3) + } + if !filter.contains(.unique) { + flags |= (1 << 4) + } return network.request(Api.functions.payments.getSavedStarGifts(flags: flags, peer: inputPeer, offset: initialNextOffset ?? "", limit: 32)) |> map(Optional.init) |> `catch` { _ -> Signal in @@ -1022,28 +1055,42 @@ private final class ProfileGiftsContextImpl { self.disposable.set((signal |> deliverOn(self.queue)).start(next: { [weak self] (gifts, count, nextOffset, notificationsEnabled) in - guard let strongSelf = self else { + guard let self else { return } - if initialNextOffset == nil { - strongSelf.gifts = gifts - - strongSelf.cacheDisposable.set(strongSelf.account.postbox.transaction { transaction in - if let entry = CodableEntry(CachedProfileGifts(gifts: gifts, count: count, notificationsEnabled: notificationsEnabled)) { - transaction.putItemCacheEntry(id: entryId(peerId: peerId), entry: entry) + if isFiltered { + if initialNextOffset == nil { + self.filteredGifts = gifts + } else { + for gift in gifts { + self.filteredGifts.append(gift) } - }.start()) - } else { - for gift in gifts { - strongSelf.gifts.append(gift) } + + let updatedCount = max(Int32(self.filteredGifts.count), count) + self.filteredCount = updatedCount + self.filteredDataState = .ready(canLoadMore: count != 0 && updatedCount > self.filteredGifts.count && nextOffset != nil, nextOffset: nextOffset) + } else { + if initialNextOffset == nil { + self.gifts = gifts + self.cacheDisposable.set(self.account.postbox.transaction { transaction in + if let entry = CodableEntry(CachedProfileGifts(gifts: gifts, count: count, notificationsEnabled: notificationsEnabled)) { + transaction.putItemCacheEntry(id: entryId(peerId: peerId), entry: entry) + } + }.start()) + } else { + for gift in gifts { + self.gifts.append(gift) + } + } + + let updatedCount = max(Int32(self.gifts.count), count) + self.count = updatedCount + self.dataState = .ready(canLoadMore: count != 0 && updatedCount > self.gifts.count && nextOffset != nil, nextOffset: nextOffset) } - let updatedCount = max(Int32(strongSelf.gifts.count), count) - strongSelf.count = updatedCount - strongSelf.dataState = .ready(canLoadMore: count != 0 && updatedCount > strongSelf.gifts.count && nextOffset != nil, nextOffset: nextOffset) - strongSelf.notificationsEnabled = notificationsEnabled - strongSelf.pushState() + self.notificationsEnabled = notificationsEnabled + self.pushState() })) } } @@ -1116,16 +1163,36 @@ private final class ProfileGiftsContextImpl { func updateFilter(_ filter: ProfileGiftsContext.Filters) { self.filter = filter + self.filteredDataState = .ready(canLoadMore: true, nextOffset: nil) self.pushState() + + self.loadMore() } func updateSorting(_ sorting: ProfileGiftsContext.Sorting) { self.sorting = sorting + self.filteredDataState = .ready(canLoadMore: true, nextOffset: nil) self.pushState() + + self.loadMore() } private func pushState() { - let state = ProfileGiftsContext.State(filter: self.filter, sorting: self.sorting, gifts: self.gifts, count: self.count, dataState: self.dataState, notificationsEnabled: self.notificationsEnabled) + let useMainData = (self.filter == .All && self.sorting == .date) || self.filteredCount == nil + + let effectiveGifts = useMainData ? self.gifts : self.filteredGifts + let effectiveCount = useMainData ? self.count : self.filteredCount + let effectiveDataState = useMainData ? self.dataState : self.filteredDataState + + let state = ProfileGiftsContext.State( + filter: self.filter, + sorting: self.sorting, + gifts: self.gifts, + filteredGifts: effectiveGifts, + count: effectiveCount, + dataState: effectiveDataState, + notificationsEnabled: self.notificationsEnabled + ) self._state = state self.stateValue.set(.single(state)) } @@ -1314,6 +1381,7 @@ public final class ProfileGiftsContext { public var filter: Filters public var sorting: Sorting public var gifts: [ProfileGiftsContext.State.StarGift] + public var filteredGifts: [ProfileGiftsContext.State.StarGift] public var count: Int32? public var dataState: ProfileGiftsContext.State.DataState public var notificationsEnabled: Bool? diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index e987e40834..0336afd47c 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -10946,28 +10946,32 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro } else { updatedFilter.insert(value) } + if !updatedFilter.contains(.unlimited) && !updatedFilter.contains(.limited) && !updatedFilter.contains(.unique) { + updatedFilter.insert(.unlimited) + } + if !updatedFilter.contains(.displayed) && !updatedFilter.contains(.hidden) { + if value == .displayed { + updatedFilter.insert(.hidden) + } else { + updatedFilter.insert(.displayed) + } + } giftsContext?.updateFilter(updatedFilter) } items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Unlimited, icon: { theme in return filter.contains(.unlimited) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil }, action: { _, f in - f(.default) - toggleFilter(.unlimited) }))) items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Limited, icon: { theme in return filter.contains(.limited) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil }, action: { _, f in - f(.default) - toggleFilter(.limited) }))) items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Unique, icon: { theme in return filter.contains(.unique) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil }, action: { _, f in - f(.default) - toggleFilter(.unique) }))) @@ -10976,15 +10980,11 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Displayed, icon: { theme in return filter.contains(.displayed) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil }, action: { _, f in - f(.default) - toggleFilter(.displayed) }))) items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Hidden, icon: { theme in return filter.contains(.hidden) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil }, action: { _, f in - f(.default) - toggleFilter(.hidden) }))) diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift index 7875288158..694f25da70 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift @@ -47,7 +47,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr private var panelButton: SolidRoundedButtonNode? private var panelCheck: ComponentView? - private var currentParams: (size: CGSize, sideInset: CGFloat, bottomInset: CGFloat, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, presentationData: PresentationData)? + private var currentParams: (size: CGSize, sideInset: CGFloat, bottomInset: CGFloat, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, expandProgress: CGFloat, presentationData: PresentationData)? private var theme: PresentationTheme? private let presentationDataPromise = Promise() @@ -96,7 +96,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr let isFirstTime = starsProducts == nil let presentationData = self.context.sharedContext.currentPresentationData.with { $0 } self.statusPromise.set(.single(PeerInfoStatusData(text: presentationData.strings.SharedMedia_GiftCount(state.count ?? 0), isActivity: true, key: .gifts))) - self.starsProducts = state.gifts + self.starsProducts = state.filteredGifts if !self.didSetReady { self.didSetReady = true @@ -313,7 +313,6 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr var bottomScrollInset: CGFloat = 0.0 var contentHeight = ceil(CGFloat(starsProducts.count) / 3.0) * (starsOptionSize.height + optionSpacing) - optionSpacing + topInset + 16.0 - let transition = ComponentTransition.immediate let size = params.size @@ -328,6 +327,8 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr let panelSeparator: ASDisplayNode let panelButton: SolidRoundedButtonNode + let panelAlpha = params.expandProgress + if let current = self.panelBackground { panelBackground = current } else { @@ -382,6 +383,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr } transition.setFrame(view: panelButton.view, frame: CGRect(origin: CGPoint(x: buttonSideInset, y: size.height - bottomInset - buttonSize.height - scrollOffset), size: buttonSize)) + transition.setAlpha(view: panelButton.view, alpha: panelAlpha) let _ = panelButton.updateLayout(width: buttonSize.width, transition: .immediate) if self.canManage { @@ -452,13 +454,16 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr self.view.addSubview(panelCheckView) } panelCheckView.frame = CGRect(origin: CGPoint(x: floor((size.width - panelCheckSize.width) / 2.0), y: size.height - bottomInset - panelCheckSize.height - 11.0 - scrollOffset), size: panelCheckSize) + transition.setAlpha(view: panelCheckView, alpha: panelAlpha) } panelButton.isHidden = true } transition.setFrame(view: panelBackground.view, frame: CGRect(x: 0.0, y: size.height - bottomPanelHeight - scrollOffset, width: size.width, height: bottomPanelHeight)) + transition.setAlpha(view: panelBackground.view, alpha: panelAlpha) panelBackground.update(size: CGSize(width: size.width, height: bottomPanelHeight), transition: transition.containedViewLayoutTransition) transition.setFrame(view: panelSeparator.view, frame: CGRect(x: 0.0, y: size.height - bottomPanelHeight - scrollOffset, width: size.width, height: UIScreenPixel)) + transition.setAlpha(view: panelSeparator.view, alpha: panelAlpha) if self.peerId == self.context.account.peerId { let footerText: ComponentView @@ -529,7 +534,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr } public func update(size: CGSize, topInset: CGFloat, sideInset: CGFloat, bottomInset: CGFloat, deviceMetrics: DeviceMetrics, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, expandProgress: CGFloat, navigationHeight: CGFloat, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) { - self.currentParams = (size, sideInset, bottomInset, visibleHeight, isScrollingLockedAtTop, presentationData) + self.currentParams = (size, sideInset, bottomInset, visibleHeight, isScrollingLockedAtTop, expandProgress, presentationData) self.presentationDataPromise.set(.single(presentationData)) self.backgroundNode.backgroundColor = presentationData.theme.list.blocksBackgroundColor