Channel reaction improvements

This commit is contained in:
Isaac 2023-11-25 23:07:15 +04:00
parent afdc11b171
commit 48a2a72a6a
11 changed files with 311 additions and 187 deletions

View File

@ -2246,6 +2246,7 @@ public final class ContextController: ViewController, StandalonePresentableContr
public var reactionItems: [ReactionContextItem] public var reactionItems: [ReactionContextItem]
public var selectedReactionItems: Set<MessageReaction.Reaction> public var selectedReactionItems: Set<MessageReaction.Reaction>
public var animationCache: AnimationCache? public var animationCache: AnimationCache?
public var alwaysAllowPremiumReactions: Bool
public var getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)? public var getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)?
public var disablePositionLock: Bool public var disablePositionLock: Bool
public var tip: Tip? public var tip: Tip?
@ -2259,6 +2260,7 @@ public final class ContextController: ViewController, StandalonePresentableContr
reactionItems: [ReactionContextItem] = [], reactionItems: [ReactionContextItem] = [],
selectedReactionItems: Set<MessageReaction.Reaction> = Set(), selectedReactionItems: Set<MessageReaction.Reaction> = Set(),
animationCache: AnimationCache? = nil, animationCache: AnimationCache? = nil,
alwaysAllowPremiumReactions: Bool = false,
getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)? = nil, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)? = nil,
disablePositionLock: Bool = false, disablePositionLock: Bool = false,
tip: Tip? = nil, tip: Tip? = nil,
@ -2271,6 +2273,7 @@ public final class ContextController: ViewController, StandalonePresentableContr
self.animationCache = animationCache self.animationCache = animationCache
self.reactionItems = reactionItems self.reactionItems = reactionItems
self.selectedReactionItems = selectedReactionItems self.selectedReactionItems = selectedReactionItems
self.alwaysAllowPremiumReactions = alwaysAllowPremiumReactions
self.getEmojiContent = getEmojiContent self.getEmojiContent = getEmojiContent
self.disablePositionLock = disablePositionLock self.disablePositionLock = disablePositionLock
self.tip = tip self.tip = tip
@ -2284,6 +2287,7 @@ public final class ContextController: ViewController, StandalonePresentableContr
self.context = nil self.context = nil
self.reactionItems = [] self.reactionItems = []
self.selectedReactionItems = Set() self.selectedReactionItems = Set()
self.alwaysAllowPremiumReactions = false
self.getEmojiContent = nil self.getEmojiContent = nil
self.disablePositionLock = false self.disablePositionLock = false
self.tip = nil self.tip = nil

View File

@ -46,7 +46,7 @@ public protocol ContextControllerActionsStackItem: AnyObject {
var id: AnyHashable? { get } var id: AnyHashable? { get }
var tip: ContextController.Tip? { get } var tip: ContextController.Tip? { get }
var tipSignal: Signal<ContextController.Tip?, NoError>? { get } var tipSignal: Signal<ContextController.Tip?, NoError>? { get }
var reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set<MessageReaction.Reaction>, animationCache: AnimationCache, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)?)? { get } var reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set<MessageReaction.Reaction>, animationCache: AnimationCache, alwaysAllowPremiumReactions: Bool, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)?)? { get }
var dismissed: (() -> Void)? { get } var dismissed: (() -> Void)? { get }
} }
@ -906,7 +906,7 @@ final class ContextControllerActionsListStackItem: ContextControllerActionsStack
let id: AnyHashable? let id: AnyHashable?
let items: [ContextMenuItem] let items: [ContextMenuItem]
let reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set<MessageReaction.Reaction>, animationCache: AnimationCache, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)?)? let reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set<MessageReaction.Reaction>, animationCache: AnimationCache, alwaysAllowPremiumReactions: Bool, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)?)?
let tip: ContextController.Tip? let tip: ContextController.Tip?
let tipSignal: Signal<ContextController.Tip?, NoError>? let tipSignal: Signal<ContextController.Tip?, NoError>?
let dismissed: (() -> Void)? let dismissed: (() -> Void)?
@ -914,7 +914,7 @@ final class ContextControllerActionsListStackItem: ContextControllerActionsStack
init( init(
id: AnyHashable?, id: AnyHashable?,
items: [ContextMenuItem], items: [ContextMenuItem],
reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set<MessageReaction.Reaction>, animationCache: AnimationCache, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)?)?, reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set<MessageReaction.Reaction>, animationCache: AnimationCache, alwaysAllowPremiumReactions: Bool, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)?)?,
tip: ContextController.Tip?, tip: ContextController.Tip?,
tipSignal: Signal<ContextController.Tip?, NoError>?, tipSignal: Signal<ContextController.Tip?, NoError>?,
dismissed: (() -> Void)? dismissed: (() -> Void)?
@ -1004,7 +1004,7 @@ final class ContextControllerActionsCustomStackItem: ContextControllerActionsSta
let id: AnyHashable? let id: AnyHashable?
private let content: ContextControllerItemsContent private let content: ContextControllerItemsContent
let reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set<MessageReaction.Reaction>, animationCache: AnimationCache, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)?)? let reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set<MessageReaction.Reaction>, animationCache: AnimationCache, alwaysAllowPremiumReactions: Bool, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)?)?
let tip: ContextController.Tip? let tip: ContextController.Tip?
let tipSignal: Signal<ContextController.Tip?, NoError>? let tipSignal: Signal<ContextController.Tip?, NoError>?
let dismissed: (() -> Void)? let dismissed: (() -> Void)?
@ -1012,7 +1012,7 @@ final class ContextControllerActionsCustomStackItem: ContextControllerActionsSta
init( init(
id: AnyHashable?, id: AnyHashable?,
content: ContextControllerItemsContent, content: ContextControllerItemsContent,
reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set<MessageReaction.Reaction>, animationCache: AnimationCache, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)?)?, reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set<MessageReaction.Reaction>, animationCache: AnimationCache, alwaysAllowPremiumReactions: Bool, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)?)?,
tip: ContextController.Tip?, tip: ContextController.Tip?,
tipSignal: Signal<ContextController.Tip?, NoError>?, tipSignal: Signal<ContextController.Tip?, NoError>?,
dismissed: (() -> Void)? dismissed: (() -> Void)?
@ -1041,9 +1041,9 @@ final class ContextControllerActionsCustomStackItem: ContextControllerActionsSta
} }
func makeContextControllerActionsStackItem(items: ContextController.Items) -> [ContextControllerActionsStackItem] { func makeContextControllerActionsStackItem(items: ContextController.Items) -> [ContextControllerActionsStackItem] {
var reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set<MessageReaction.Reaction>, animationCache: AnimationCache, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)?)? var reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set<MessageReaction.Reaction>, animationCache: AnimationCache, alwaysAllowPremiumReactions: Bool, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)?)?
if let context = items.context, let animationCache = items.animationCache, !items.reactionItems.isEmpty { 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 { switch items.content {
case let .list(listItems): case let .list(listItems):
@ -1167,7 +1167,7 @@ final class ContextControllerActionsStackNode: ASDisplayNode {
var tip: ContextController.Tip? var tip: ContextController.Tip?
let tipSignal: Signal<ContextController.Tip?, NoError>? let tipSignal: Signal<ContextController.Tip?, NoError>?
var tipNode: InnerTextSelectionTipContainerNode? var tipNode: InnerTextSelectionTipContainerNode?
let reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set<MessageReaction.Reaction>, animationCache: AnimationCache, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)?)? let reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set<MessageReaction.Reaction>, animationCache: AnimationCache, alwaysAllowPremiumReactions: Bool, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)?)?
let itemDismissed: (() -> Void)? let itemDismissed: (() -> Void)?
var storedScrollingState: CGFloat? var storedScrollingState: CGFloat?
let positionLock: CGFloat? let positionLock: CGFloat?
@ -1182,7 +1182,7 @@ final class ContextControllerActionsStackNode: ASDisplayNode {
item: ContextControllerActionsStackItem, item: ContextControllerActionsStackItem,
tip: ContextController.Tip?, tip: ContextController.Tip?,
tipSignal: Signal<ContextController.Tip?, NoError>?, tipSignal: Signal<ContextController.Tip?, NoError>?,
reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set<MessageReaction.Reaction>, animationCache: AnimationCache, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)?)?, reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set<MessageReaction.Reaction>, animationCache: AnimationCache, alwaysAllowPremiumReactions: Bool, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)?)?,
itemDismissed: (() -> Void)?, itemDismissed: (() -> Void)?,
positionLock: CGFloat? positionLock: CGFloat?
) { ) {
@ -1333,7 +1333,7 @@ final class ContextControllerActionsStackNode: ASDisplayNode {
private var selectionPanGesture: UIPanGestureRecognizer? private var selectionPanGesture: UIPanGestureRecognizer?
var topReactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set<MessageReaction.Reaction>, animationCache: AnimationCache, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)?)? { var topReactionItems: (context: AccountContext, reactionItems: [ReactionContextItem], selectedReactionItems: Set<MessageReaction.Reaction>, animationCache: AnimationCache, alwaysAllowPremiumReactions: Bool, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)?)? {
return self.itemContainers.last?.reactionItems return self.itemContainers.last?.reactionItems
} }

View File

@ -639,6 +639,7 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
presentationData: presentationData, presentationData: presentationData,
items: reactionItems.reactionItems, items: reactionItems.reactionItems,
selectedItems: reactionItems.selectedReactionItems, selectedItems: reactionItems.selectedReactionItems,
alwaysAllowPremiumReactions: reactionItems.alwaysAllowPremiumReactions,
getEmojiContent: reactionItems.getEmojiContent, getEmojiContent: reactionItems.getEmojiContent,
isExpandedUpdated: { [weak self] transition in isExpandedUpdated: { [weak self] transition in
guard let strongSelf = self else { 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) 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)
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) self.proposedReactionsPositionLock = contentRect.minY - 18.0 - reactionContextNode.contentHeight - (46.0 + 54.0 - 4.0)
}
} else { } else {
self.proposedReactionsPositionLock = nil self.proposedReactionsPositionLock = nil
} }

View File

@ -136,6 +136,7 @@ public class DrawingReactionEntityView: DrawingStickerEntityView {
items: reactionItems.map(ReactionContextItem.reaction), items: reactionItems.map(ReactionContextItem.reaction),
selectedItems: Set(), selectedItems: Set(),
title: nil, title: nil,
alwaysAllowPremiumReactions: false,
getEmojiContent: { [weak self] animationCache, animationRenderer in getEmojiContent: { [weak self] animationCache, animationRenderer in
guard let self else { guard let self else {
preconditionFailure() preconditionFailure()
@ -150,7 +151,7 @@ public class DrawingReactionEntityView: DrawingStickerEntityView {
animationCache: animationCache, animationCache: animationCache,
animationRenderer: animationRenderer, animationRenderer: animationRenderer,
isStandalone: false, isStandalone: false,
subject: .reaction, subject: .reaction(onlyTop: false),
hasTrending: false, hasTrending: false,
topReactionItems: mappedReactionItems, topReactionItems: mappedReactionItems,
areUnicodeEmojiEnabled: false, areUnicodeEmojiEnabled: false,

View File

@ -1192,10 +1192,10 @@ private final class LimitSheetContent: CombinedComponent {
case .nameColors: case .nameColors:
titleText = strings.ChannelBoost_EnableColors titleText = strings.ChannelBoost_EnableColors
string = strings.ChannelBoost_EnableColorsLevelText("\(premiumConfiguration.minChannelNameColorLevel)").string string = strings.ChannelBoost_EnableColorsLevelText("\(premiumConfiguration.minChannelNameColorLevel)").string
case .channelReactions: case let .channelReactions(reactionCount):
//TODO:localize //TODO:localize
titleText = "Custom Reactions" 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 { } else {
let storiesString = strings.ChannelBoost_StoriesPerDay(level) let storiesString = strings.ChannelBoost_StoriesPerDay(level)
@ -1777,10 +1777,10 @@ public class PremiumLimitScreen: ViewControllerComponentContainer {
case storiesWeekly case storiesWeekly
case storiesMonthly case storiesMonthly
public enum BoostSubject { public enum BoostSubject: Equatable {
case stories case stories
case nameColors 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) case storiesChannelBoost(peer: EnginePeer, boostSubject: BoostSubject, isCurrent: Bool, level: Int32, currentLevelBoosts: Int32, nextLevelBoosts: Int32?, link: String?, myBoostCount: Int32, canBoostAgain: Bool)

View File

@ -296,6 +296,8 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
private var extensionDistance: CGFloat = 0.0 private var extensionDistance: CGFloat = 0.0
public private(set) var visibleExtensionDistance: 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 emojiContentLayout: EmojiPagerContentComponent.CustomLayout?
private var emojiContent: EmojiPagerContentComponent? private var emojiContent: EmojiPagerContentComponent?
private var scheduledEmojiContentAnimationHint: EmojiPagerContentComponent.ContentAnimation? private var scheduledEmojiContentAnimationHint: EmojiPagerContentComponent.ContentAnimation?
@ -322,6 +324,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
private var availableReactions: AvailableReactions? private var availableReactions: AvailableReactions?
private var availableReactionsDisposable: Disposable? private var availableReactionsDisposable: Disposable?
public let alwaysAllowPremiumReactions: Bool
private var hasPremium: Bool? private var hasPremium: Bool?
private var hasPremiumDisposable: Disposable? 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<MessageReaction.Reaction>, title: String? = nil, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)?, isExpandedUpdated: @escaping (ContainedViewLayoutTransition) -> Void, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void, requestUpdateOverlayWantsToBeBelowKeyboard: @escaping (ContainedViewLayoutTransition) -> Void) { public init(context: AccountContext, animationCache: AnimationCache, presentationData: PresentationData, items: [ReactionContextItem], selectedItems: Set<MessageReaction.Reaction>, title: String? = nil, alwaysAllowPremiumReactions: Bool, getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)?, isExpandedUpdated: @escaping (ContainedViewLayoutTransition) -> Void, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void, requestUpdateOverlayWantsToBeBelowKeyboard: @escaping (ContainedViewLayoutTransition) -> Void) {
self.context = context self.context = context
self.presentationData = presentationData self.presentationData = presentationData
self.items = items self.items = items
@ -468,6 +471,8 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
self.contentTopInset = 24.0 self.contentTopInset = 24.0
} }
self.alwaysAllowPremiumReactions = alwaysAllowPremiumReactions
super.init() super.init()
self.addSubnode(self.backgroundNode) self.addSubnode(self.backgroundNode)
@ -486,6 +491,9 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
strongSelf.availableReactions = availableReactions strongSelf.availableReactions = availableReactions
}) })
if alwaysAllowPremiumReactions {
self.hasPremium = true
} else {
self.hasPremiumDisposable = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId)) self.hasPremiumDisposable = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|> deliverOnMainQueue).start(next: { [weak self] peer in |> deliverOnMainQueue).start(next: { [weak self] peer in
guard let strongSelf = self else { guard let strongSelf = self else {
@ -493,6 +501,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
} }
strongSelf.hasPremium = peer?.isPremium ?? false strongSelf.hasPremium = peer?.isPremium ?? false
}) })
}
if let getEmojiContent = getEmojiContent { if let getEmojiContent = getEmojiContent {
let viewKey = PostboxViewKey.orderedItemList(id: Namespaces.OrderedItemList.CloudFeaturedEmojiPacks) 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) 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( let _ = reactionSelectionComponentHost.update(
transition: emojiTransition, transition: emojiTransition,
component: AnyComponent(EmojiStatusSelectionComponent( component: AnyComponent(EmojiStatusSelectionComponent(
@ -575,7 +591,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
emojiContent: emojiContent, emojiContent: emojiContent,
backgroundColor: .clear, backgroundColor: .clear,
separatorColor: strongSelf.presentationData.theme.list.itemPlainSeparatorColor.withMultipliedAlpha(0.5), separatorColor: strongSelf.presentationData.theme.list.itemPlainSeparatorColor.withMultipliedAlpha(0.5),
hideTopPanel: strongSelf.isReactionSearchActive, hideTopPanel: hideTopPanel,
hideTopPanelUpdated: { hideTopPanel, transition in hideTopPanelUpdated: { hideTopPanel, transition in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
@ -585,7 +601,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
} }
)), )),
environment: {}, 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 expandItemSize = 30.0
expandTintOffset = 0.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, frame: baseNextFrame)
transition.updateFrame(view: expandItemView.tintView, frame: baseNextFrame.offsetBy(dx: 0.0, dy: expandTintOffset)) 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 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) scrollFrame.origin.y += floorToScreenPixels(self.extensionDistance / 2.0)
transition.updatePosition(node: self.contentContainer, position: visualBackgroundFrame.center, beginWithCurrentState: true) 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.updateScrolling(transition: transition)
self.emojiContentLayout = EmojiPagerContentComponent.CustomLayout( self.emojiContentLayout = EmojiPagerContentComponent.CustomLayout(
topPanelAlwaysHidden: self.alwaysAllowPremiumReactions,
itemsPerRow: itemCount, itemsPerRow: itemCount,
itemSize: itemSize, itemSize: itemSize,
sideInset: sideInset, sideInset: sideInset,
@ -1168,6 +1200,13 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
componentTransition = Transition(animation: .curve(duration: 0.4, curve: .spring)).withUserData(contentAnimation) 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( let _ = reactionSelectionComponentHost.update(
transition: componentTransition, transition: componentTransition,
component: AnyComponent(EmojiStatusSelectionComponent( component: AnyComponent(EmojiStatusSelectionComponent(
@ -1177,7 +1216,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
emojiContent: emojiContent, emojiContent: emojiContent,
backgroundColor: .clear, backgroundColor: .clear,
separatorColor: self.presentationData.theme.list.itemPlainSeparatorColor.withMultipliedAlpha(0.5), separatorColor: self.presentationData.theme.list.itemPlainSeparatorColor.withMultipliedAlpha(0.5),
hideTopPanel: self.isReactionSearchActive, hideTopPanel: hideTopPanel,
hideTopPanelUpdated: { [weak self] hideTopPanel, transition in hideTopPanelUpdated: { [weak self] hideTopPanel, transition in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
@ -1187,7 +1226,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
} }
)), )),
environment: {}, environment: {},
containerSize: CGSize(width: actualBackgroundFrame.width, height: 300.0) containerSize: CGSize(width: actualBackgroundFrame.width, height: self.emojiContentHeight)
) )
if let componentView = reactionSelectionComponentHost.view { if let componentView = reactionSelectionComponentHost.view {
var animateIn = false var animateIn = false
@ -1229,7 +1268,15 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
if let mirrorContentClippingView = emojiView.mirrorContentClippingView { if let mirrorContentClippingView = emojiView.mirrorContentClippingView {
mirrorContentClippingView.clipsToBounds = false 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 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))) componentTransition.setFrame(view: componentView, frame: CGRect(origin: componentFrame.origin, size: CGSize(width: componentFrame.width, height: componentFrame.height)))
if animateIn { 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 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( emojiContent.inputInteractionHolder.inputInteraction = EmojiPagerContentComponent.InputInteraction(
performItemAction: { [weak self] groupId, item, sourceView, sourceRect, sourceLayer, isLongPress in performItemAction: { [weak self] groupId, item, sourceView, sourceRect, sourceLayer, isLongPress in
guard let strongSelf = self, let availableReactions = strongSelf.availableReactions, let itemFile = item.itemFile else { 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)) { if let expandItemView = self.expandItemView, expandItemView.bounds.contains(self.view.convert(point, to: self.expandItemView)) {
self.animateFromExtensionDistance = self.contentTopInset * 2.0 + self.extensionDistance self.animateFromExtensionDistance = self.contentTopInset * 2.0 + self.extensionDistance
self.contentTopInset = 0.0 self.contentTopInset = 0.0
self.currentContentHeight = 300.0 self.currentContentHeight = self.emojiContentHeight
self.isExpanded = true self.isExpanded = true
self.longPressRecognizer?.isEnabled = false self.longPressRecognizer?.isEnabled = false
self.isExpandedUpdated(.animated(duration: 0.4, curve: .spring)) self.isExpandedUpdated(.animated(duration: 0.4, curve: .spring))
@ -2388,7 +2453,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
self.extensionDistance = 0.0 self.extensionDistance = 0.0
self.visibleExtensionDistance = 0.0 self.visibleExtensionDistance = 0.0
self.contentTopInset = 0.0 self.contentTopInset = 0.0
self.currentContentHeight = 300.0 self.currentContentHeight = self.emojiContentHeight
self.isExpanded = true self.isExpanded = true
self.isExpandedUpdated(.animated(duration: 0.4, curve: .spring)) self.isExpandedUpdated(.animated(duration: 0.4, curve: .spring))
} }

View File

@ -2298,17 +2298,20 @@ public final class EmojiPagerContentComponent: Component {
} }
public struct CustomLayout: Equatable { public struct CustomLayout: Equatable {
public var topPanelAlwaysHidden: Bool
public var itemsPerRow: Int public var itemsPerRow: Int
public var itemSize: CGFloat public var itemSize: CGFloat
public var sideInset: CGFloat public var sideInset: CGFloat
public var itemSpacing: CGFloat public var itemSpacing: CGFloat
public init( public init(
topPanelAlwaysHidden: Bool,
itemsPerRow: Int, itemsPerRow: Int,
itemSize: CGFloat, itemSize: CGFloat,
sideInset: CGFloat, sideInset: CGFloat,
itemSpacing: CGFloat itemSpacing: CGFloat
) { ) {
self.topPanelAlwaysHidden = topPanelAlwaysHidden
self.itemsPerRow = itemsPerRow self.itemsPerRow = itemsPerRow
self.itemSize = itemSize self.itemSize = itemSize
self.sideInset = sideInset self.sideInset = sideInset
@ -3052,7 +3055,8 @@ public final class EmojiPagerContentComponent: Component {
var verticalGroupOrigin: CGFloat = self.itemInsets.top var verticalGroupOrigin: CGFloat = self.itemInsets.top
self.itemGroupLayouts = [] self.itemGroupLayouts = []
for itemGroup in itemGroups { for i in 0 ..< itemGroups.count {
let itemGroup = itemGroups[i]
var itemsPerRow = self.itemsPerRow var itemsPerRow = self.itemsPerRow
var nativeItemSize = self.nativeItemSize var nativeItemSize = self.nativeItemSize
var visibleItemSize = self.visibleItemSize var visibleItemSize = self.visibleItemSize
@ -3145,7 +3149,10 @@ public final class EmojiPagerContentComponent: Component {
collapsedItemIndex: collapsedItemIndex, collapsedItemIndex: collapsedItemIndex,
collapsedItemText: collapsedItemText collapsedItemText: collapsedItemText
)) ))
verticalGroupOrigin += groupContentSize.height + groupSpacing verticalGroupOrigin += groupContentSize.height
if i != itemGroups.count - 1 {
verticalGroupOrigin += groupSpacing
}
} }
verticalGroupOrigin += itemInsets.bottom verticalGroupOrigin += itemInsets.bottom
self.contentSize = CGSize(width: width, height: verticalGroupOrigin) self.contentSize = CGSize(width: width, height: verticalGroupOrigin)
@ -6791,6 +6798,9 @@ public final class EmojiPagerContentComponent: Component {
self.scrollView.contentSize = effectiveContentSize self.scrollView.contentSize = effectiveContentSize
} }
var scrollIndicatorInsets = pagerEnvironment.containerInsets var scrollIndicatorInsets = pagerEnvironment.containerInsets
if let inputInteraction = component.inputInteractionHolder.inputInteraction, let customLayout = inputInteraction.customLayout, customLayout.topPanelAlwaysHidden {
scrollIndicatorInsets.top += 20.0
}
if self.warpView != nil { if self.warpView != nil {
scrollIndicatorInsets.bottom += 20.0 scrollIndicatorInsets.bottom += 20.0
} }
@ -7175,10 +7185,10 @@ public final class EmojiPagerContentComponent: Component {
return hasPremium return hasPremium
} }
public enum Subject { public enum Subject: Equatable {
case generic case generic
case status case status
case reaction case reaction(onlyTop: Bool)
case emoji case emoji
case topicIcon case topicIcon
case quickReaction case quickReaction
@ -7216,7 +7226,12 @@ public final class EmojiPagerContentComponent: Component {
var orderedItemListCollectionIds: [Int32] = [] var orderedItemListCollectionIds: [Int32] = []
switch subject {
case .backgroundIcon, .reactionList:
break
default:
orderedItemListCollectionIds.append(Namespaces.OrderedItemList.LocalRecentEmoji) orderedItemListCollectionIds.append(Namespaces.OrderedItemList.LocalRecentEmoji)
}
var iconStatusEmoji: Signal<[TelegramMediaFile], NoError> = .single([]) var iconStatusEmoji: Signal<[TelegramMediaFile], NoError> = .single([])
@ -7234,7 +7249,7 @@ public final class EmojiPagerContentComponent: Component {
} }
} }
|> take(1) |> 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.CloudTopReactions)
orderedItemListCollectionIds.append(Namespaces.OrderedItemList.CloudRecentReactions) orderedItemListCollectionIds.append(Namespaces.OrderedItemList.CloudRecentReactions)
} else if case .topicIcon = subject { } else if case .topicIcon = subject {
@ -7257,14 +7272,14 @@ public final class EmojiPagerContentComponent: Component {
} }
let availableReactions: Signal<AvailableReactions?, NoError> let availableReactions: Signal<AvailableReactions?, NoError>
if [.reaction, .quickReaction, .reactionList].contains(subject) { if [.reaction(onlyTop: false), .quickReaction, .reactionList].contains(subject) {
availableReactions = context.engine.stickers.availableReactions() availableReactions = context.engine.stickers.availableReactions()
} else { } else {
availableReactions = .single(nil) availableReactions = .single(nil)
} }
let searchCategories: Signal<EmojiSearchCategories?, NoError> let searchCategories: Signal<EmojiSearchCategories?, NoError>
if [.emoji, .reaction, .reactionList].contains(subject) { if [.emoji, .reaction(onlyTop: false), .reactionList].contains(subject) {
searchCategories = context.engine.stickers.emojiSearchCategories(kind: .emoji) searchCategories = context.engine.stickers.emojiSearchCategories(kind: .emoji)
} else if case .status = subject { } else if case .status = subject {
searchCategories = context.engine.stickers.emojiSearchCategories(kind: .status) 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<MessageReaction.Reaction>() var existingIds = Set<MessageReaction.Reaction>()
var topReactionItems = topReactionItems var topReactionItems = topReactionItems
@ -7720,7 +7735,9 @@ public final class EmojiPagerContentComponent: Component {
} }
let maxTopLineCount: Int let maxTopLineCount: Int
if hasPremium { if case .reaction(onlyTop: true) = subject {
maxTopLineCount = 1000
} else if hasPremium {
maxTopLineCount = 2 maxTopLineCount = 2
} else { } else {
maxTopLineCount = 6 maxTopLineCount = 6
@ -7733,7 +7750,9 @@ public final class EmojiPagerContentComponent: Component {
existingIds.insert(reactionItem.reaction) existingIds.insert(reactionItem.reaction)
let icon: EmojiPagerContentComponent.Item.Icon 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 icon = .locked
} else { } else {
icon = .none icon = .none
@ -7768,6 +7787,7 @@ public final class EmojiPagerContentComponent: Component {
} }
} }
if case .reaction(onlyTop: false) = subject {
var hasRecent = false var hasRecent = false
if let recentReactions = recentReactions, !recentReactions.items.isEmpty { if let recentReactions = recentReactions, !recentReactions.items.isEmpty {
hasRecent = true hasRecent = true
@ -7909,6 +7929,7 @@ public final class EmojiPagerContentComponent: Component {
} }
} }
} }
}
} else if [.profilePhoto, .groupPhoto].contains(subject) { } else if [.profilePhoto, .groupPhoto].contains(subject) {
var existingIds = Set<MediaId>() var existingIds = Set<MediaId>()
@ -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 { if let recentEmoji = recentEmoji, hasRecentEmoji {
for item in recentEmoji.items { for item in recentEmoji.items {
@ -8108,7 +8129,7 @@ public final class EmojiPagerContentComponent: Component {
} }
var icon: EmojiPagerContentComponent.Item.Icon = .none var icon: EmojiPagerContentComponent.Item.Icon = .none
if [.reaction, .quickReaction].contains(subject), !hasPremium { if [.reaction(onlyTop: false), .quickReaction].contains(subject), !hasPremium {
icon = .locked icon = .locked
} }
@ -8285,7 +8306,7 @@ public final class EmojiPagerContentComponent: Component {
var displaySearchWithPlaceholder: String? var displaySearchWithPlaceholder: String?
let searchInitiallyHidden = true let searchInitiallyHidden = true
if hasSearch { if hasSearch {
if [.reaction, .quickReaction].contains(subject) { if [.reaction(onlyTop: false), .quickReaction].contains(subject) {
displaySearchWithPlaceholder = strings.EmojiSearch_SearchReactionsPlaceholder displaySearchWithPlaceholder = strings.EmojiSearch_SearchReactionsPlaceholder
} else if case .status = subject { } else if case .status = subject {
displaySearchWithPlaceholder = strings.EmojiSearch_SearchStatusesPlaceholder displaySearchWithPlaceholder = strings.EmojiSearch_SearchStatusesPlaceholder
@ -8340,8 +8361,8 @@ public final class EmojiPagerContentComponent: Component {
) )
} }
let warpContentsOnEdges = [.reaction, .quickReaction, .status, .profilePhoto, .groupPhoto, .backgroundIcon].contains(subject) let warpContentsOnEdges = [.reaction(onlyTop: true), .reaction(onlyTop: false), .quickReaction, .status, .profilePhoto, .groupPhoto, .backgroundIcon].contains(subject)
let enableLongPress = [.reaction, .status].contains(subject) let enableLongPress = [.reaction(onlyTop: true), .reaction(onlyTop: false), .status].contains(subject)
return EmojiPagerContentComponent( return EmojiPagerContentComponent(
id: "emoji", id: "emoji",

View File

@ -225,7 +225,7 @@ public final class EmojiSelectionComponent: Component {
component: AnyComponent(EntityKeyboardComponent( component: AnyComponent(EntityKeyboardComponent(
theme: component.theme, theme: component.theme,
strings: component.strings, strings: component.strings,
isContentInFocus: false, isContentInFocus: true,
containerInsets: UIEdgeInsets(top: topPanelHeight - 34.0, left: component.sideInset, bottom: component.bottomInset + 16.0, right: component.sideInset), 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), topPanelInsets: UIEdgeInsets(top: 0.0, left: 4.0, bottom: 0.0, right: 4.0),
emojiContent: component.emojiContent.withCustomTintColor(component.theme.list.itemPrimaryTextColor), emojiContent: component.emojiContent.withCustomTintColor(component.theme.list.itemPrimaryTextColor),

View File

@ -274,7 +274,7 @@ final class PeerAllowedReactionsScreenComponent: Component {
}) })
if let boostStatus = self.boostStatus, !customReactions.isEmpty, customReactions.count > boostStatus.level { if let boostStatus = self.boostStatus, !customReactions.isEmpty, customReactions.count > boostStatus.level {
self.displayPremiumScreen() self.displayPremiumScreen(reactionCount: customReactions.count)
return return
} }
@ -306,7 +306,7 @@ final class PeerAllowedReactionsScreenComponent: Component {
if !standalone { if !standalone {
switch error { switch error {
case .boostRequired: case .boostRequired:
self.displayPremiumScreen() self.displayPremiumScreen(reactionCount: customReactions.count)
case .generic: case .generic:
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 } let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
//TODO:localize //TODO:localize
@ -330,7 +330,7 @@ final class PeerAllowedReactionsScreenComponent: Component {
} }
} }
private func displayPremiumScreen() { private func displayPremiumScreen(reactionCount: Int) {
guard let component = self.component else { guard let component = self.component else {
return return
} }
@ -344,7 +344,7 @@ final class PeerAllowedReactionsScreenComponent: Component {
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: component.context.currentAppConfiguration.with { $0 }) let premiumConfiguration = PremiumConfiguration.with(appConfiguration: component.context.currentAppConfiguration.with { $0 })
let link = status.url 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 { guard let self, let component = self.component else {
return true return true
} }

View File

@ -4271,6 +4271,7 @@ public final class StoryItemSetContainerComponent: Component {
items: reactionItems.map(ReactionContextItem.reaction), items: reactionItems.map(ReactionContextItem.reaction),
selectedItems: component.slice.item.storyItem.myReaction.flatMap { Set([$0]) } ?? Set(), selectedItems: component.slice.item.storyItem.myReaction.flatMap { Set([$0]) } ?? Set(),
title: self.displayLikeReactions ? nil : component.strings.Story_SendReactionAsMessage, title: self.displayLikeReactions ? nil : component.strings.Story_SendReactionAsMessage,
alwaysAllowPremiumReactions: false,
getEmojiContent: { [weak self] animationCache, animationRenderer in getEmojiContent: { [weak self] animationCache, animationRenderer in
guard let self, let component = self.component else { guard let self, let component = self.component else {
preconditionFailure() preconditionFailure()
@ -4285,7 +4286,7 @@ public final class StoryItemSetContainerComponent: Component {
animationCache: animationCache, animationCache: animationCache,
animationRenderer: animationRenderer, animationRenderer: animationRenderer,
isStandalone: false, isStandalone: false,
subject: .reaction, subject: .reaction(onlyTop: false),
hasTrending: false, hasTrending: false,
topReactionItems: mappedReactionItems, topReactionItems: mappedReactionItems,
areUnicodeEmojiEnabled: false, areUnicodeEmojiEnabled: false,

View File

@ -112,6 +112,10 @@ extension ChatControllerImpl {
actions.reactionItems = topReactions.map(ReactionContextItem.reaction) actions.reactionItems = topReactions.map(ReactionContextItem.reaction)
actions.selectedReactionItems = selectedReactions.reactions actions.selectedReactionItems = selectedReactions.reactions
if let channel = self.presentationInterfaceState.renderedPeer?.peer as? TelegramChannel, case .broadcast = channel.info {
actions.alwaysAllowPremiumReactions = true
}
if !actions.reactionItems.isEmpty { if !actions.reactionItems.isEmpty {
let reactionItems: [EmojiComponentReactionItem] = actions.reactionItems.compactMap { item -> EmojiComponentReactionItem? in let reactionItems: [EmojiComponentReactionItem] = actions.reactionItems.compactMap { item -> EmojiComponentReactionItem? in
switch item { switch item {
@ -150,7 +154,7 @@ extension ChatControllerImpl {
animationCache: animationCache, animationCache: animationCache,
animationRenderer: animationRenderer, animationRenderer: animationRenderer,
isStandalone: false, isStandalone: false,
subject: .reaction, subject: .reaction(onlyTop: false),
hasTrending: false, hasTrending: false,
topReactionItems: reactionItems, topReactionItems: reactionItems,
areUnicodeEmojiEnabled: false, areUnicodeEmojiEnabled: false,
@ -159,6 +163,26 @@ extension ChatControllerImpl {
selectedItems: selectedReactions.files 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,11 +356,14 @@ extension ChatControllerImpl {
}*/ }*/
if removedReaction == nil, case .custom = chosenReaction { if removedReaction == nil, case .custom = chosenReaction {
if let peer = self.presentationInterfaceState.renderedPeer?.peer as? TelegramChannel, case .broadcast = peer.info {
} else {
if !self.presentationInterfaceState.isPremium { if !self.presentationInterfaceState.isPremium {
controller?.premiumReactionsSelected?() controller?.premiumReactionsSelected?()
return return
} }
} }
}
self.chatDisplayNode.historyNode.forEachItemNode { itemNode in self.chatDisplayNode.historyNode.forEachItemNode { itemNode in
if let itemNode = itemNode as? ChatMessageItemView, let item = itemNode.item { if let itemNode = itemNode as? ChatMessageItemView, let item = itemNode.item {