diff --git a/submodules/ContextUI/Sources/ContextController.swift b/submodules/ContextUI/Sources/ContextController.swift index 96f7c72a87..13679a82fd 100644 --- a/submodules/ContextUI/Sources/ContextController.swift +++ b/submodules/ContextUI/Sources/ContextController.swift @@ -2246,6 +2246,7 @@ public final class ContextController: ViewController, StandalonePresentableContr public var reactionItems: [ReactionContextItem] public var selectedReactionItems: Set public var animationCache: AnimationCache? + public var alwaysAllowPremiumReactions: Bool public var getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal)? public var disablePositionLock: Bool public var tip: Tip? @@ -2259,6 +2260,7 @@ public final class ContextController: ViewController, StandalonePresentableContr reactionItems: [ReactionContextItem] = [], selectedReactionItems: Set = Set(), animationCache: AnimationCache? = nil, + alwaysAllowPremiumReactions: Bool = false, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal)? = nil, disablePositionLock: Bool = false, tip: Tip? = nil, @@ -2271,6 +2273,7 @@ public final class ContextController: ViewController, StandalonePresentableContr self.animationCache = animationCache self.reactionItems = reactionItems self.selectedReactionItems = selectedReactionItems + self.alwaysAllowPremiumReactions = alwaysAllowPremiumReactions self.getEmojiContent = getEmojiContent self.disablePositionLock = disablePositionLock self.tip = tip @@ -2284,6 +2287,7 @@ public final class ContextController: ViewController, StandalonePresentableContr self.context = nil self.reactionItems = [] self.selectedReactionItems = Set() + self.alwaysAllowPremiumReactions = false self.getEmojiContent = nil self.disablePositionLock = false self.tip = nil diff --git a/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift b/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift index 207d4f1b0c..39b3dc725a 100644 --- a/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift +++ b/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift @@ -46,7 +46,7 @@ public protocol ContextControllerActionsStackItem: AnyObject { var id: AnyHashable? { get } var tip: ContextController.Tip? { get } var tipSignal: Signal? { get } - var reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set, animationCache: AnimationCache, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal)?)? { get } + var reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set, animationCache: AnimationCache, alwaysAllowPremiumReactions: Bool, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal)?)? { get } var dismissed: (() -> Void)? { get } } @@ -906,7 +906,7 @@ final class ContextControllerActionsListStackItem: ContextControllerActionsStack let id: AnyHashable? let items: [ContextMenuItem] - let reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set, animationCache: AnimationCache, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal)?)? + let reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set, animationCache: AnimationCache, alwaysAllowPremiumReactions: Bool, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal)?)? let tip: ContextController.Tip? let tipSignal: Signal? let dismissed: (() -> Void)? @@ -914,7 +914,7 @@ final class ContextControllerActionsListStackItem: ContextControllerActionsStack init( id: AnyHashable?, items: [ContextMenuItem], - reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set, animationCache: AnimationCache, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal)?)?, + reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set, animationCache: AnimationCache, alwaysAllowPremiumReactions: Bool, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal)?)?, tip: ContextController.Tip?, tipSignal: Signal?, dismissed: (() -> Void)? @@ -1004,7 +1004,7 @@ final class ContextControllerActionsCustomStackItem: ContextControllerActionsSta let id: AnyHashable? private let content: ContextControllerItemsContent - let reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set, animationCache: AnimationCache, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal)?)? + let reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set, animationCache: AnimationCache, alwaysAllowPremiumReactions: Bool, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal)?)? let tip: ContextController.Tip? let tipSignal: Signal? let dismissed: (() -> Void)? @@ -1012,7 +1012,7 @@ final class ContextControllerActionsCustomStackItem: ContextControllerActionsSta init( id: AnyHashable?, content: ContextControllerItemsContent, - reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set, animationCache: AnimationCache, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal)?)?, + reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set, animationCache: AnimationCache, alwaysAllowPremiumReactions: Bool, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal)?)?, tip: ContextController.Tip?, tipSignal: Signal?, dismissed: (() -> Void)? @@ -1041,9 +1041,9 @@ final class ContextControllerActionsCustomStackItem: ContextControllerActionsSta } func makeContextControllerActionsStackItem(items: ContextController.Items) -> [ContextControllerActionsStackItem] { - var reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set, animationCache: AnimationCache, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal)?)? + var reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set, animationCache: AnimationCache, alwaysAllowPremiumReactions: Bool, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal)?)? if let context = items.context, let animationCache = items.animationCache, !items.reactionItems.isEmpty { - reactionItems = (context, items.reactionItems, items.selectedReactionItems, animationCache, items.getEmojiContent) + reactionItems = (context, items.reactionItems, items.selectedReactionItems, animationCache, alwaysAllowPremiumReactions: items.alwaysAllowPremiumReactions, items.getEmojiContent) } switch items.content { case let .list(listItems): @@ -1167,7 +1167,7 @@ final class ContextControllerActionsStackNode: ASDisplayNode { var tip: ContextController.Tip? let tipSignal: Signal? var tipNode: InnerTextSelectionTipContainerNode? - let reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set, animationCache: AnimationCache, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal)?)? + let reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set, animationCache: AnimationCache, alwaysAllowPremiumReactions: Bool, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal)?)? let itemDismissed: (() -> Void)? var storedScrollingState: CGFloat? let positionLock: CGFloat? @@ -1182,7 +1182,7 @@ final class ContextControllerActionsStackNode: ASDisplayNode { item: ContextControllerActionsStackItem, tip: ContextController.Tip?, tipSignal: Signal?, - reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set, animationCache: AnimationCache, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal)?)?, + reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set, animationCache: AnimationCache, alwaysAllowPremiumReactions: Bool, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal)?)?, itemDismissed: (() -> Void)?, positionLock: CGFloat? ) { @@ -1333,7 +1333,7 @@ final class ContextControllerActionsStackNode: ASDisplayNode { private var selectionPanGesture: UIPanGestureRecognizer? - var topReactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set, animationCache: AnimationCache, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal)?)? { + var topReactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set, animationCache: AnimationCache, alwaysAllowPremiumReactions: Bool, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal)?)? { return self.itemContainers.last?.reactionItems } diff --git a/submodules/ContextUI/Sources/ContextControllerExtractedPresentationNode.swift b/submodules/ContextUI/Sources/ContextControllerExtractedPresentationNode.swift index dd554d8402..0218be517a 100644 --- a/submodules/ContextUI/Sources/ContextControllerExtractedPresentationNode.swift +++ b/submodules/ContextUI/Sources/ContextControllerExtractedPresentationNode.swift @@ -639,6 +639,7 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo presentationData: presentationData, items: reactionItems.reactionItems, selectedItems: reactionItems.selectedReactionItems, + alwaysAllowPremiumReactions: reactionItems.alwaysAllowPremiumReactions, getEmojiContent: reactionItems.getEmojiContent, isExpandedUpdated: { [weak self] transition in guard let strongSelf = self else { @@ -916,7 +917,11 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo reactionContextNode.updateLayout(size: layout.size, insets: UIEdgeInsets(top: topInset, left: layout.safeInsets.left, bottom: 0.0, right: layout.safeInsets.right), anchorRect: reactionAnchorRect, isCoveredByInput: isCoveredByInput, isAnimatingOut: isAnimatingOut, transition: reactionContextNodeTransition) - self.proposedReactionsPositionLock = contentRect.minY - 18.0 - reactionContextNode.contentHeight - (46.0 + 54.0 - 4.0) + if reactionContextNode.alwaysAllowPremiumReactions { + self.proposedReactionsPositionLock = contentRect.minY - 18.0 - reactionContextNode.contentHeight + } else { + self.proposedReactionsPositionLock = contentRect.minY - 18.0 - reactionContextNode.contentHeight - (46.0 + 54.0 - 4.0) + } } else { self.proposedReactionsPositionLock = nil } diff --git a/submodules/DrawingUI/Sources/DrawingReactionView.swift b/submodules/DrawingUI/Sources/DrawingReactionView.swift index 375f941e81..816f7b3ec1 100644 --- a/submodules/DrawingUI/Sources/DrawingReactionView.swift +++ b/submodules/DrawingUI/Sources/DrawingReactionView.swift @@ -136,6 +136,7 @@ public class DrawingReactionEntityView: DrawingStickerEntityView { items: reactionItems.map(ReactionContextItem.reaction), selectedItems: Set(), title: nil, + alwaysAllowPremiumReactions: false, getEmojiContent: { [weak self] animationCache, animationRenderer in guard let self else { preconditionFailure() @@ -150,7 +151,7 @@ public class DrawingReactionEntityView: DrawingStickerEntityView { animationCache: animationCache, animationRenderer: animationRenderer, isStandalone: false, - subject: .reaction, + subject: .reaction(onlyTop: false), hasTrending: false, topReactionItems: mappedReactionItems, areUnicodeEmojiEnabled: false, diff --git a/submodules/PremiumUI/Sources/PremiumLimitScreen.swift b/submodules/PremiumUI/Sources/PremiumLimitScreen.swift index c398798a4c..a2d0c263ea 100644 --- a/submodules/PremiumUI/Sources/PremiumLimitScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumLimitScreen.swift @@ -1192,10 +1192,10 @@ private final class LimitSheetContent: CombinedComponent { case .nameColors: titleText = strings.ChannelBoost_EnableColors string = strings.ChannelBoost_EnableColorsLevelText("\(premiumConfiguration.minChannelNameColorLevel)").string - case .channelReactions: + case let .channelReactions(reactionCount): //TODO:localize titleText = "Custom Reactions" - string = "Your channel needs \(valueString) to add custom emoji as reactions.\n\nAsk your **Premium** subscribers to boost your channel with this link:" + string = "Your channel needs to reach **Level \(reactionCount)** to add **\(reactionCount)** custom emoji as reactions.\n\nAsk your **Premium** subscribers to boost your channel with this link:" } } else { let storiesString = strings.ChannelBoost_StoriesPerDay(level) @@ -1777,10 +1777,10 @@ public class PremiumLimitScreen: ViewControllerComponentContainer { case storiesWeekly case storiesMonthly - public enum BoostSubject { + public enum BoostSubject: Equatable { case stories case nameColors - case channelReactions + case channelReactions(reactionCount: Int) } case storiesChannelBoost(peer: EnginePeer, boostSubject: BoostSubject, isCurrent: Bool, level: Int32, currentLevelBoosts: Int32, nextLevelBoosts: Int32?, link: String?, myBoostCount: Int32, canBoostAgain: Bool) diff --git a/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift b/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift index 884b6f73e6..d82188f008 100644 --- a/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift +++ b/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift @@ -296,6 +296,8 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { private var extensionDistance: CGFloat = 0.0 public private(set) var visibleExtensionDistance: CGFloat = 0.0 + private var emojiContentHeight: CGFloat = 300.0 + private var didInitializeEmojiContentHeight: Bool = false private var emojiContentLayout: EmojiPagerContentComponent.CustomLayout? private var emojiContent: EmojiPagerContentComponent? private var scheduledEmojiContentAnimationHint: EmojiPagerContentComponent.ContentAnimation? @@ -322,6 +324,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { private var availableReactions: AvailableReactions? private var availableReactionsDisposable: Disposable? + public let alwaysAllowPremiumReactions: Bool private var hasPremium: Bool? private var hasPremiumDisposable: Disposable? @@ -368,7 +371,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { } } - public init(context: AccountContext, animationCache: AnimationCache, presentationData: PresentationData, items: [ReactionContextItem], selectedItems: Set, title: String? = nil, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal)?, isExpandedUpdated: @escaping (ContainedViewLayoutTransition) -> Void, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void, requestUpdateOverlayWantsToBeBelowKeyboard: @escaping (ContainedViewLayoutTransition) -> Void) { + public init(context: AccountContext, animationCache: AnimationCache, presentationData: PresentationData, items: [ReactionContextItem], selectedItems: Set, title: String? = nil, alwaysAllowPremiumReactions: Bool, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal)?, isExpandedUpdated: @escaping (ContainedViewLayoutTransition) -> Void, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void, requestUpdateOverlayWantsToBeBelowKeyboard: @escaping (ContainedViewLayoutTransition) -> Void) { self.context = context self.presentationData = presentationData self.items = items @@ -468,6 +471,8 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { self.contentTopInset = 24.0 } + self.alwaysAllowPremiumReactions = alwaysAllowPremiumReactions + super.init() self.addSubnode(self.backgroundNode) @@ -486,13 +491,17 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { strongSelf.availableReactions = availableReactions }) - self.hasPremiumDisposable = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId)) - |> deliverOnMainQueue).start(next: { [weak self] peer in - guard let strongSelf = self else { - return - } - strongSelf.hasPremium = peer?.isPremium ?? false - }) + if alwaysAllowPremiumReactions { + self.hasPremium = true + } else { + self.hasPremiumDisposable = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId)) + |> deliverOnMainQueue).start(next: { [weak self] peer in + guard let strongSelf = self else { + return + } + strongSelf.hasPremium = peer?.isPremium ?? false + }) + } if let getEmojiContent = getEmojiContent { let viewKey = PostboxViewKey.orderedItemList(id: Namespaces.OrderedItemList.CloudFeaturedEmojiPacks) @@ -566,6 +575,13 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { emojiTransition = Transition(animation: .curve(duration: 0.4, curve: .spring)).withUserData(contentAnimation) } + var hideTopPanel = false + if strongSelf.isReactionSearchActive { + hideTopPanel = true + } else if strongSelf.alwaysAllowPremiumReactions { + hideTopPanel = true + } + let _ = reactionSelectionComponentHost.update( transition: emojiTransition, component: AnyComponent(EmojiStatusSelectionComponent( @@ -575,7 +591,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { emojiContent: emojiContent, backgroundColor: .clear, separatorColor: strongSelf.presentationData.theme.list.itemPlainSeparatorColor.withMultipliedAlpha(0.5), - hideTopPanel: strongSelf.isReactionSearchActive, + hideTopPanel: hideTopPanel, hideTopPanelUpdated: { hideTopPanel, transition in guard let strongSelf = self else { return @@ -585,7 +601,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { } )), environment: {}, - containerSize: CGSize(width: componentView.bounds.width, height: 300.0) + containerSize: CGSize(width: componentView.bounds.width, height: strongSelf.emojiContentHeight) ) } }) @@ -1023,7 +1039,13 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { expandItemSize = 30.0 expandTintOffset = 0.0 } - let baseNextFrame = CGRect(origin: CGPoint(x: self.scrollNode.view.bounds.width - expandItemSize - 9.0, y: self.contentTopInset + containerHeight - contentHeight + floor((contentHeight - expandItemSize) / 2.0) + (self.isExpanded ? (46.0 + 54.0 - 4.0) : 0.0)), size: CGSize(width: expandItemSize, height: expandItemSize + self.extensionDistance)) + var baseNextFrame = CGRect(origin: CGPoint(x: self.scrollNode.view.bounds.width - expandItemSize - 9.0, y: self.contentTopInset + containerHeight - contentHeight + floor((contentHeight - expandItemSize) / 2.0)), size: CGSize(width: expandItemSize, height: expandItemSize + self.extensionDistance)) + if self.isExpanded { + if self.alwaysAllowPremiumReactions { + } else { + baseNextFrame.origin.y += 46.0 + 54.0 - 4.0 + } + } transition.updateFrame(view: expandItemView, frame: baseNextFrame) transition.updateFrame(view: expandItemView.tintView, frame: baseNextFrame.offsetBy(dx: 0.0, dy: expandTintOffset)) @@ -1124,7 +1146,16 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { visibleItemCount: itemCount ) - var scrollFrame = CGRect(origin: CGPoint(x: 0.0, y: self.isExpanded ? (46.0 + 54.0 - 4.0) : self.contentTopInset), size: actualBackgroundFrame.size) + var scrollFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: actualBackgroundFrame.size) + if self.isExpanded { + if self.alwaysAllowPremiumReactions { + scrollFrame.origin.y += 0.0 + } else { + scrollFrame.origin.y += 46.0 + 54.0 - 4.0 + } + } else { + scrollFrame.origin.y += self.contentTopInset + } scrollFrame.origin.y += floorToScreenPixels(self.extensionDistance / 2.0) transition.updatePosition(node: self.contentContainer, position: visualBackgroundFrame.center, beginWithCurrentState: true) @@ -1142,6 +1173,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { self.updateScrolling(transition: transition) self.emojiContentLayout = EmojiPagerContentComponent.CustomLayout( + topPanelAlwaysHidden: self.alwaysAllowPremiumReactions, itemsPerRow: itemCount, itemSize: itemSize, sideInset: sideInset, @@ -1168,6 +1200,13 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { componentTransition = Transition(animation: .curve(duration: 0.4, curve: .spring)).withUserData(contentAnimation) } + var hideTopPanel = false + if self.isReactionSearchActive { + hideTopPanel = true + } else if self.alwaysAllowPremiumReactions { + hideTopPanel = true + } + let _ = reactionSelectionComponentHost.update( transition: componentTransition, component: AnyComponent(EmojiStatusSelectionComponent( @@ -1177,7 +1216,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { emojiContent: emojiContent, backgroundColor: .clear, separatorColor: self.presentationData.theme.list.itemPlainSeparatorColor.withMultipliedAlpha(0.5), - hideTopPanel: self.isReactionSearchActive, + hideTopPanel: hideTopPanel, hideTopPanelUpdated: { [weak self] hideTopPanel, transition in guard let strongSelf = self else { return @@ -1187,7 +1226,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { } )), environment: {}, - containerSize: CGSize(width: actualBackgroundFrame.width, height: 300.0) + containerSize: CGSize(width: actualBackgroundFrame.width, height: self.emojiContentHeight) ) if let componentView = reactionSelectionComponentHost.view { var animateIn = false @@ -1229,7 +1268,15 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { if let mirrorContentClippingView = emojiView.mirrorContentClippingView { mirrorContentClippingView.clipsToBounds = false - Transition(transition).animateBoundsOrigin(view: mirrorContentClippingView, from: CGPoint(x: 0.0, y: 46.0 + 54.0 - 4.0), to: CGPoint(), additive: true, completion: { [weak mirrorContentClippingView] _ in + + var animationOffsetY: CGFloat = 0.0 + if self.alwaysAllowPremiumReactions { + animationOffsetY += -4.0 + } else { + animationOffsetY += 46.0 + 54.0 - 4.0 + } + + Transition(transition).animateBoundsOrigin(view: mirrorContentClippingView, from: CGPoint(x: 0.0, y: animationOffsetY), to: CGPoint(), additive: true, completion: { [weak mirrorContentClippingView] _ in mirrorContentClippingView?.clipsToBounds = true }) } @@ -1260,7 +1307,14 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { componentTransition.setFrame(view: componentView, frame: CGRect(origin: componentFrame.origin, size: CGSize(width: componentFrame.width, height: componentFrame.height))) if animateIn { - transition.animatePositionAdditive(layer: componentView.layer, offset: CGPoint(x: 0.0, y: -(46.0 + 54.0 - 4.0) + floorToScreenPixels(self.animateFromExtensionDistance / 2.0))) + var animationOffsetY: CGFloat = 0.0 + if self.alwaysAllowPremiumReactions { + animationOffsetY += 4.0 + } else { + animationOffsetY += 46.0 + 54.0 - 4.0 + } + + transition.animatePositionAdditive(layer: componentView.layer, offset: CGPoint(x: 0.0, y: -animationOffsetY + floorToScreenPixels(self.animateFromExtensionDistance / 2.0))) } } } @@ -1317,6 +1371,17 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { return } + if !self.didInitializeEmojiContentHeight { + self.didInitializeEmojiContentHeight = true + + if emojiContent.contentItemGroups.count == 1 { + let itemCount = emojiContent.contentItemGroups[0].items.count + let numRows = (itemCount + (emojiContentLayout.itemsPerRow - 1)) / emojiContentLayout.itemsPerRow + let proposedHeight: CGFloat = CGFloat(numRows) * emojiContentLayout.itemSize + CGFloat(numRows - 1) * emojiContentLayout.itemSpacing + emojiContentLayout.itemSpacing * 2.0 + 5.0 + self.emojiContentHeight = min(300.0, proposedHeight) + } + } + emojiContent.inputInteractionHolder.inputInteraction = EmojiPagerContentComponent.InputInteraction( performItemAction: { [weak self] groupId, item, sourceView, sourceRect, sourceLayer, isLongPress in guard let strongSelf = self, let availableReactions = strongSelf.availableReactions, let itemFile = item.itemFile else { @@ -2347,7 +2412,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { if let expandItemView = self.expandItemView, expandItemView.bounds.contains(self.view.convert(point, to: self.expandItemView)) { self.animateFromExtensionDistance = self.contentTopInset * 2.0 + self.extensionDistance self.contentTopInset = 0.0 - self.currentContentHeight = 300.0 + self.currentContentHeight = self.emojiContentHeight self.isExpanded = true self.longPressRecognizer?.isEnabled = false self.isExpandedUpdated(.animated(duration: 0.4, curve: .spring)) @@ -2388,7 +2453,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { self.extensionDistance = 0.0 self.visibleExtensionDistance = 0.0 self.contentTopInset = 0.0 - self.currentContentHeight = 300.0 + self.currentContentHeight = self.emojiContentHeight self.isExpanded = true self.isExpandedUpdated(.animated(duration: 0.4, curve: .spring)) } diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift index f05f506e9d..e661064f2b 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift +++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift @@ -2298,17 +2298,20 @@ public final class EmojiPagerContentComponent: Component { } public struct CustomLayout: Equatable { + public var topPanelAlwaysHidden: Bool public var itemsPerRow: Int public var itemSize: CGFloat public var sideInset: CGFloat public var itemSpacing: CGFloat public init( + topPanelAlwaysHidden: Bool, itemsPerRow: Int, itemSize: CGFloat, sideInset: CGFloat, itemSpacing: CGFloat ) { + self.topPanelAlwaysHidden = topPanelAlwaysHidden self.itemsPerRow = itemsPerRow self.itemSize = itemSize self.sideInset = sideInset @@ -3052,7 +3055,8 @@ public final class EmojiPagerContentComponent: Component { var verticalGroupOrigin: CGFloat = self.itemInsets.top self.itemGroupLayouts = [] - for itemGroup in itemGroups { + for i in 0 ..< itemGroups.count { + let itemGroup = itemGroups[i] var itemsPerRow = self.itemsPerRow var nativeItemSize = self.nativeItemSize var visibleItemSize = self.visibleItemSize @@ -3145,7 +3149,10 @@ public final class EmojiPagerContentComponent: Component { collapsedItemIndex: collapsedItemIndex, collapsedItemText: collapsedItemText )) - verticalGroupOrigin += groupContentSize.height + groupSpacing + verticalGroupOrigin += groupContentSize.height + if i != itemGroups.count - 1 { + verticalGroupOrigin += groupSpacing + } } verticalGroupOrigin += itemInsets.bottom self.contentSize = CGSize(width: width, height: verticalGroupOrigin) @@ -6791,6 +6798,9 @@ public final class EmojiPagerContentComponent: Component { self.scrollView.contentSize = effectiveContentSize } var scrollIndicatorInsets = pagerEnvironment.containerInsets + if let inputInteraction = component.inputInteractionHolder.inputInteraction, let customLayout = inputInteraction.customLayout, customLayout.topPanelAlwaysHidden { + scrollIndicatorInsets.top += 20.0 + } if self.warpView != nil { scrollIndicatorInsets.bottom += 20.0 } @@ -7175,10 +7185,10 @@ public final class EmojiPagerContentComponent: Component { return hasPremium } - public enum Subject { + public enum Subject: Equatable { case generic case status - case reaction + case reaction(onlyTop: Bool) case emoji case topicIcon case quickReaction @@ -7216,7 +7226,12 @@ public final class EmojiPagerContentComponent: Component { var orderedItemListCollectionIds: [Int32] = [] - orderedItemListCollectionIds.append(Namespaces.OrderedItemList.LocalRecentEmoji) + switch subject { + case .backgroundIcon, .reactionList: + break + default: + orderedItemListCollectionIds.append(Namespaces.OrderedItemList.LocalRecentEmoji) + } var iconStatusEmoji: Signal<[TelegramMediaFile], NoError> = .single([]) @@ -7234,7 +7249,7 @@ public final class EmojiPagerContentComponent: Component { } } |> take(1) - } else if [.reaction, .quickReaction].contains(subject) { + } else if [.reaction(onlyTop: false), .quickReaction].contains(subject) { orderedItemListCollectionIds.append(Namespaces.OrderedItemList.CloudTopReactions) orderedItemListCollectionIds.append(Namespaces.OrderedItemList.CloudRecentReactions) } else if case .topicIcon = subject { @@ -7257,14 +7272,14 @@ public final class EmojiPagerContentComponent: Component { } let availableReactions: Signal - if [.reaction, .quickReaction, .reactionList].contains(subject) { + if [.reaction(onlyTop: false), .quickReaction, .reactionList].contains(subject) { availableReactions = context.engine.stickers.availableReactions() } else { availableReactions = .single(nil) } let searchCategories: Signal - if [.emoji, .reaction, .reactionList].contains(subject) { + if [.emoji, .reaction(onlyTop: false), .reactionList].contains(subject) { searchCategories = context.engine.stickers.emojiSearchCategories(kind: .emoji) } else if case .status = subject { searchCategories = context.engine.stickers.emojiSearchCategories(kind: .status) @@ -7694,7 +7709,7 @@ public final class EmojiPagerContentComponent: Component { } } } - } else if [.reaction, .quickReaction].contains(subject) { + } else if [.reaction(onlyTop: true), .reaction(onlyTop: false), .quickReaction].contains(subject) { var existingIds = Set() var topReactionItems = topReactionItems @@ -7720,7 +7735,9 @@ public final class EmojiPagerContentComponent: Component { } let maxTopLineCount: Int - if hasPremium { + if case .reaction(onlyTop: true) = subject { + maxTopLineCount = 1000 + } else if hasPremium { maxTopLineCount = 2 } else { maxTopLineCount = 6 @@ -7733,7 +7750,9 @@ public final class EmojiPagerContentComponent: Component { existingIds.insert(reactionItem.reaction) let icon: EmojiPagerContentComponent.Item.Icon - if !hasPremium, case .custom = reactionItem.reaction { + if case .reaction(onlyTop: true) = subject { + icon = .none + } else if !hasPremium, case .custom = reactionItem.reaction { icon = .locked } else { icon = .none @@ -7768,144 +7787,146 @@ public final class EmojiPagerContentComponent: Component { } } - var hasRecent = false - if let recentReactions = recentReactions, !recentReactions.items.isEmpty { - hasRecent = true - } - - let maxRecentLineCount: Int - if hasPremium { - maxRecentLineCount = 10 - } else { - maxRecentLineCount = 10 - } - - let popularTitle = hasRecent ? strings.Chat_ReactionSection_Recent : strings.Chat_ReactionSection_Popular - - if let availableReactions = availableReactions { - for reactionItem in availableReactions.reactions { - if !reactionItem.isEnabled { - continue - } - if existingIds.contains(reactionItem.value) { - continue - } - existingIds.insert(reactionItem.value) - - let icon: EmojiPagerContentComponent.Item.Icon - if !hasPremium, case .custom = reactionItem.value { - icon = .locked - } else { - icon = .none - } - - var tintMode: Item.TintMode = .none - if reactionItem.selectAnimation.isCustomTemplateEmoji { - tintMode = .primary - } - - let animationFile = reactionItem.selectAnimation - let animationData = EntityKeyboardAnimationData(file: animationFile, isReaction: true) - let resultItem = EmojiPagerContentComponent.Item( - animationData: animationData, - content: .animation(animationData), - itemFile: animationFile, - subgroupId: nil, - icon: icon, - tintMode: tintMode - ) - - if hasPremium { - let groupId = "popular" - if let groupIndex = itemGroupIndexById[groupId] { - itemGroups[groupIndex].items.append(resultItem) - } else { - itemGroupIndexById[groupId] = itemGroups.count - itemGroups.append(ItemGroup(supergroupId: groupId, id: groupId, title: popularTitle, subtitle: nil, isPremiumLocked: false, isFeatured: false, collapsedLineCount: nil, isClearable: hasRecent && subject != .quickReaction, headerItem: nil, items: [resultItem])) - } - } else { - let groupId = "recent" - if let groupIndex = itemGroupIndexById[groupId] { - itemGroups[groupIndex].items.append(resultItem) - - if itemGroups[groupIndex].items.count >= maxRecentLineCount * 8 { - break - } - } else { - itemGroupIndexById[groupId] = itemGroups.count - itemGroups.append(ItemGroup(supergroupId: groupId, id: groupId, title: nil, subtitle: nil, isPremiumLocked: false, isFeatured: false, collapsedLineCount: nil, isClearable: false, headerItem: nil, items: [resultItem])) - } - } + if case .reaction(onlyTop: false) = subject { + var hasRecent = false + if let recentReactions = recentReactions, !recentReactions.items.isEmpty { + hasRecent = true } - } - - if let recentReactions = recentReactions { - var popularInsertIndex = 0 - for item in recentReactions.items { - guard let item = item.contents.get(RecentReactionItem.self) else { - continue - } - - let animationFile: TelegramMediaFile - let icon: EmojiPagerContentComponent.Item.Icon - - switch item.content { - case let .builtin(value): - if existingIds.contains(.builtin(value)) { + + let maxRecentLineCount: Int + if hasPremium { + maxRecentLineCount = 10 + } else { + maxRecentLineCount = 10 + } + + let popularTitle = hasRecent ? strings.Chat_ReactionSection_Recent : strings.Chat_ReactionSection_Popular + + if let availableReactions = availableReactions { + for reactionItem in availableReactions.reactions { + if !reactionItem.isEnabled { continue } - existingIds.insert(.builtin(value)) - if let availableReactions = availableReactions, let availableReaction = availableReactions.reactions.first(where: { $0.value == .builtin(value) }) { - if let centerAnimation = availableReaction.centerAnimation { - animationFile = centerAnimation - } else { - continue - } - } else { + if existingIds.contains(reactionItem.value) { continue } + existingIds.insert(reactionItem.value) - icon = .none - case let .custom(file): - if existingIds.contains(.custom(file.fileId.id)) { - continue - } - existingIds.insert(.custom(file.fileId.id)) - animationFile = file - - if !hasPremium { + let icon: EmojiPagerContentComponent.Item.Icon + if !hasPremium, case .custom = reactionItem.value { icon = .locked } else { icon = .none } - } - - var tintMode: Item.TintMode = .none - if animationFile.isCustomTemplateEmoji { - tintMode = .primary - } - - let animationData = EntityKeyboardAnimationData(file: animationFile, isReaction: true) - let resultItem = EmojiPagerContentComponent.Item( - animationData: animationData, - content: .animation(animationData), - itemFile: animationFile, - subgroupId: nil, - icon: icon, - tintMode: tintMode - ) - - let groupId = "popular" - if let groupIndex = itemGroupIndexById[groupId] { - if itemGroups[groupIndex].items.count + 1 >= maxRecentLineCount * 8 { - break + + var tintMode: Item.TintMode = .none + if reactionItem.selectAnimation.isCustomTemplateEmoji { + tintMode = .primary } - itemGroups[groupIndex].items.insert(resultItem, at: popularInsertIndex) - popularInsertIndex += 1 - } else { - itemGroupIndexById[groupId] = itemGroups.count - itemGroups.append(ItemGroup(supergroupId: groupId, id: groupId, title: popularTitle, subtitle: nil, isPremiumLocked: false, isFeatured: false, collapsedLineCount: nil, isClearable: hasRecent && subject != .quickReaction, headerItem: nil, items: [resultItem])) + let animationFile = reactionItem.selectAnimation + let animationData = EntityKeyboardAnimationData(file: animationFile, isReaction: true) + let resultItem = EmojiPagerContentComponent.Item( + animationData: animationData, + content: .animation(animationData), + itemFile: animationFile, + subgroupId: nil, + icon: icon, + tintMode: tintMode + ) + + if hasPremium { + let groupId = "popular" + if let groupIndex = itemGroupIndexById[groupId] { + itemGroups[groupIndex].items.append(resultItem) + } else { + itemGroupIndexById[groupId] = itemGroups.count + itemGroups.append(ItemGroup(supergroupId: groupId, id: groupId, title: popularTitle, subtitle: nil, isPremiumLocked: false, isFeatured: false, collapsedLineCount: nil, isClearable: hasRecent && subject != .quickReaction, headerItem: nil, items: [resultItem])) + } + } else { + let groupId = "recent" + if let groupIndex = itemGroupIndexById[groupId] { + itemGroups[groupIndex].items.append(resultItem) + + if itemGroups[groupIndex].items.count >= maxRecentLineCount * 8 { + break + } + } else { + itemGroupIndexById[groupId] = itemGroups.count + itemGroups.append(ItemGroup(supergroupId: groupId, id: groupId, title: nil, subtitle: nil, isPremiumLocked: false, isFeatured: false, collapsedLineCount: nil, isClearable: false, headerItem: nil, items: [resultItem])) + } + } + } + } + + if let recentReactions = recentReactions { + var popularInsertIndex = 0 + for item in recentReactions.items { + guard let item = item.contents.get(RecentReactionItem.self) else { + continue + } + + let animationFile: TelegramMediaFile + let icon: EmojiPagerContentComponent.Item.Icon + + switch item.content { + case let .builtin(value): + if existingIds.contains(.builtin(value)) { + continue + } + existingIds.insert(.builtin(value)) + if let availableReactions = availableReactions, let availableReaction = availableReactions.reactions.first(where: { $0.value == .builtin(value) }) { + if let centerAnimation = availableReaction.centerAnimation { + animationFile = centerAnimation + } else { + continue + } + } else { + continue + } + + icon = .none + case let .custom(file): + if existingIds.contains(.custom(file.fileId.id)) { + continue + } + existingIds.insert(.custom(file.fileId.id)) + animationFile = file + + if !hasPremium { + icon = .locked + } else { + icon = .none + } + } + + var tintMode: Item.TintMode = .none + if animationFile.isCustomTemplateEmoji { + tintMode = .primary + } + + let animationData = EntityKeyboardAnimationData(file: animationFile, isReaction: true) + let resultItem = EmojiPagerContentComponent.Item( + animationData: animationData, + content: .animation(animationData), + itemFile: animationFile, + subgroupId: nil, + icon: icon, + tintMode: tintMode + ) + + let groupId = "popular" + if let groupIndex = itemGroupIndexById[groupId] { + if itemGroups[groupIndex].items.count + 1 >= maxRecentLineCount * 8 { + break + } + + itemGroups[groupIndex].items.insert(resultItem, at: popularInsertIndex) + popularInsertIndex += 1 + } else { + itemGroupIndexById[groupId] = itemGroups.count + itemGroups.append(ItemGroup(supergroupId: groupId, id: groupId, title: popularTitle, subtitle: nil, isPremiumLocked: false, isFeatured: false, collapsedLineCount: nil, isClearable: hasRecent && subject != .quickReaction, headerItem: nil, items: [resultItem])) + } } } } @@ -7966,7 +7987,7 @@ public final class EmojiPagerContentComponent: Component { } } } - } else if case .backgroundIcon = subject { + } else if case .backgroundIcon = subject { var existingIds = Set() let resultItem = EmojiPagerContentComponent.Item( @@ -8042,7 +8063,7 @@ public final class EmojiPagerContentComponent: Component { } } - let hasRecentEmoji = ![.reaction, .quickReaction, .status, .profilePhoto, .groupPhoto, .topicIcon, .backgroundIcon].contains(subject) + let hasRecentEmoji = ![.reaction(onlyTop: true), .reaction(onlyTop: false), .quickReaction, .status, .profilePhoto, .groupPhoto, .topicIcon, .backgroundIcon, .reactionList].contains(subject) if let recentEmoji = recentEmoji, hasRecentEmoji { for item in recentEmoji.items { @@ -8108,7 +8129,7 @@ public final class EmojiPagerContentComponent: Component { } var icon: EmojiPagerContentComponent.Item.Icon = .none - if [.reaction, .quickReaction].contains(subject), !hasPremium { + if [.reaction(onlyTop: false), .quickReaction].contains(subject), !hasPremium { icon = .locked } @@ -8285,7 +8306,7 @@ public final class EmojiPagerContentComponent: Component { var displaySearchWithPlaceholder: String? let searchInitiallyHidden = true if hasSearch { - if [.reaction, .quickReaction].contains(subject) { + if [.reaction(onlyTop: false), .quickReaction].contains(subject) { displaySearchWithPlaceholder = strings.EmojiSearch_SearchReactionsPlaceholder } else if case .status = subject { displaySearchWithPlaceholder = strings.EmojiSearch_SearchStatusesPlaceholder @@ -8340,8 +8361,8 @@ public final class EmojiPagerContentComponent: Component { ) } - let warpContentsOnEdges = [.reaction, .quickReaction, .status, .profilePhoto, .groupPhoto, .backgroundIcon].contains(subject) - let enableLongPress = [.reaction, .status].contains(subject) + let warpContentsOnEdges = [.reaction(onlyTop: true), .reaction(onlyTop: false), .quickReaction, .status, .profilePhoto, .groupPhoto, .backgroundIcon].contains(subject) + let enableLongPress = [.reaction(onlyTop: true), .reaction(onlyTop: false), .status].contains(subject) return EmojiPagerContentComponent( id: "emoji", diff --git a/submodules/TelegramUI/Components/PeerAllowedReactionsScreen/Sources/EmojiSelectionComponent.swift b/submodules/TelegramUI/Components/PeerAllowedReactionsScreen/Sources/EmojiSelectionComponent.swift index 429aaf0521..44f8bb7dbe 100644 --- a/submodules/TelegramUI/Components/PeerAllowedReactionsScreen/Sources/EmojiSelectionComponent.swift +++ b/submodules/TelegramUI/Components/PeerAllowedReactionsScreen/Sources/EmojiSelectionComponent.swift @@ -225,7 +225,7 @@ public final class EmojiSelectionComponent: Component { component: AnyComponent(EntityKeyboardComponent( theme: component.theme, strings: component.strings, - isContentInFocus: false, + isContentInFocus: true, containerInsets: UIEdgeInsets(top: topPanelHeight - 34.0, left: component.sideInset, bottom: component.bottomInset + 16.0, right: component.sideInset), topPanelInsets: UIEdgeInsets(top: 0.0, left: 4.0, bottom: 0.0, right: 4.0), emojiContent: component.emojiContent.withCustomTintColor(component.theme.list.itemPrimaryTextColor), diff --git a/submodules/TelegramUI/Components/PeerAllowedReactionsScreen/Sources/PeerAllowedReactionsScreen.swift b/submodules/TelegramUI/Components/PeerAllowedReactionsScreen/Sources/PeerAllowedReactionsScreen.swift index 5b468c1b0b..faec2799cc 100644 --- a/submodules/TelegramUI/Components/PeerAllowedReactionsScreen/Sources/PeerAllowedReactionsScreen.swift +++ b/submodules/TelegramUI/Components/PeerAllowedReactionsScreen/Sources/PeerAllowedReactionsScreen.swift @@ -274,7 +274,7 @@ final class PeerAllowedReactionsScreenComponent: Component { }) if let boostStatus = self.boostStatus, !customReactions.isEmpty, customReactions.count > boostStatus.level { - self.displayPremiumScreen() + self.displayPremiumScreen(reactionCount: customReactions.count) return } @@ -306,7 +306,7 @@ final class PeerAllowedReactionsScreenComponent: Component { if !standalone { switch error { case .boostRequired: - self.displayPremiumScreen() + self.displayPremiumScreen(reactionCount: customReactions.count) case .generic: let presentationData = component.context.sharedContext.currentPresentationData.with { $0 } //TODO:localize @@ -330,7 +330,7 @@ final class PeerAllowedReactionsScreenComponent: Component { } } - private func displayPremiumScreen() { + private func displayPremiumScreen(reactionCount: Int) { guard let component = self.component else { return } @@ -344,7 +344,7 @@ final class PeerAllowedReactionsScreenComponent: Component { let premiumConfiguration = PremiumConfiguration.with(appConfiguration: component.context.currentAppConfiguration.with { $0 }) let link = status.url - let controller = PremiumLimitScreen(context: component.context, subject: .storiesChannelBoost(peer: peer, boostSubject: .channelReactions, isCurrent: true, level: Int32(status.level), currentLevelBoosts: Int32(status.currentLevelBoosts), nextLevelBoosts: status.nextLevelBoosts.flatMap(Int32.init), link: link, myBoostCount: 0, canBoostAgain: false), count: Int32(status.boosts), action: { [weak self] in + let controller = PremiumLimitScreen(context: component.context, subject: .storiesChannelBoost(peer: peer, boostSubject: .channelReactions(reactionCount: reactionCount), isCurrent: true, level: Int32(status.level), currentLevelBoosts: Int32(status.currentLevelBoosts), nextLevelBoosts: status.nextLevelBoosts.flatMap(Int32.init), link: link, myBoostCount: 0, canBoostAgain: false), count: Int32(status.boosts), action: { [weak self] in guard let self, let component = self.component else { return true } diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift index 021e119546..b8087b98eb 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift @@ -4271,6 +4271,7 @@ public final class StoryItemSetContainerComponent: Component { items: reactionItems.map(ReactionContextItem.reaction), selectedItems: component.slice.item.storyItem.myReaction.flatMap { Set([$0]) } ?? Set(), title: self.displayLikeReactions ? nil : component.strings.Story_SendReactionAsMessage, + alwaysAllowPremiumReactions: false, getEmojiContent: { [weak self] animationCache, animationRenderer in guard let self, let component = self.component else { preconditionFailure() @@ -4285,7 +4286,7 @@ public final class StoryItemSetContainerComponent: Component { animationCache: animationCache, animationRenderer: animationRenderer, isStandalone: false, - subject: .reaction, + subject: .reaction(onlyTop: false), hasTrending: false, topReactionItems: mappedReactionItems, areUnicodeEmojiEnabled: false, diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerOpenMessageContextMenu.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerOpenMessageContextMenu.swift index 0c3692581c..ce7208eaa4 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerOpenMessageContextMenu.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerOpenMessageContextMenu.swift @@ -112,6 +112,10 @@ extension ChatControllerImpl { actions.reactionItems = topReactions.map(ReactionContextItem.reaction) actions.selectedReactionItems = selectedReactions.reactions + if let channel = self.presentationInterfaceState.renderedPeer?.peer as? TelegramChannel, case .broadcast = channel.info { + actions.alwaysAllowPremiumReactions = true + } + if !actions.reactionItems.isEmpty { let reactionItems: [EmojiComponentReactionItem] = actions.reactionItems.compactMap { item -> EmojiComponentReactionItem? in switch item { @@ -150,7 +154,7 @@ extension ChatControllerImpl { animationCache: animationCache, animationRenderer: animationRenderer, isStandalone: false, - subject: .reaction, + subject: .reaction(onlyTop: false), hasTrending: false, topReactionItems: reactionItems, areUnicodeEmojiEnabled: false, @@ -159,6 +163,26 @@ extension ChatControllerImpl { selectedItems: selectedReactions.files ) } + } else if reactionItems.count > 10 { + actions.getEmojiContent = { [weak self] animationCache, animationRenderer in + guard let self else { + preconditionFailure() + } + + return EmojiPagerContentComponent.emojiInputData( + context: self.context, + animationCache: animationCache, + animationRenderer: animationRenderer, + isStandalone: false, + subject: .reaction(onlyTop: true), + hasTrending: false, + topReactionItems: reactionItems, + areUnicodeEmojiEnabled: false, + areCustomEmojiEnabled: false, + chatPeerId: self.chatLocation.peerId, + selectedItems: selectedReactions.files + ) + } } } } @@ -332,9 +356,12 @@ extension ChatControllerImpl { }*/ if removedReaction == nil, case .custom = chosenReaction { - if !self.presentationInterfaceState.isPremium { - controller?.premiumReactionsSelected?() - return + if let peer = self.presentationInterfaceState.renderedPeer?.peer as? TelegramChannel, case .broadcast = peer.info { + } else { + if !self.presentationInterfaceState.isPremium { + controller?.premiumReactionsSelected?() + return + } } }