mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Channel reaction improvements
This commit is contained in:
parent
afdc11b171
commit
48a2a72a6a
@ -2246,6 +2246,7 @@ public final class ContextController: ViewController, StandalonePresentableContr
|
||||
public var reactionItems: [ReactionContextItem]
|
||||
public var selectedReactionItems: Set<MessageReaction.Reaction>
|
||||
public var animationCache: AnimationCache?
|
||||
public var alwaysAllowPremiumReactions: Bool
|
||||
public var getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)?
|
||||
public var disablePositionLock: Bool
|
||||
public var tip: Tip?
|
||||
@ -2259,6 +2260,7 @@ public final class ContextController: ViewController, StandalonePresentableContr
|
||||
reactionItems: [ReactionContextItem] = [],
|
||||
selectedReactionItems: Set<MessageReaction.Reaction> = Set(),
|
||||
animationCache: AnimationCache? = nil,
|
||||
alwaysAllowPremiumReactions: Bool = false,
|
||||
getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError>)? = 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
|
||||
|
@ -46,7 +46,7 @@ public protocol ContextControllerActionsStackItem: AnyObject {
|
||||
var id: AnyHashable? { get }
|
||||
var tip: ContextController.Tip? { 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 }
|
||||
}
|
||||
|
||||
@ -906,7 +906,7 @@ final class ContextControllerActionsListStackItem: ContextControllerActionsStack
|
||||
|
||||
let id: AnyHashable?
|
||||
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 tipSignal: Signal<ContextController.Tip?, NoError>?
|
||||
let dismissed: (() -> Void)?
|
||||
@ -914,7 +914,7 @@ final class ContextControllerActionsListStackItem: ContextControllerActionsStack
|
||||
init(
|
||||
id: AnyHashable?,
|
||||
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?,
|
||||
tipSignal: Signal<ContextController.Tip?, NoError>?,
|
||||
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<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 tipSignal: Signal<ContextController.Tip?, NoError>?
|
||||
let dismissed: (() -> Void)?
|
||||
@ -1012,7 +1012,7 @@ final class ContextControllerActionsCustomStackItem: ContextControllerActionsSta
|
||||
init(
|
||||
id: AnyHashable?,
|
||||
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?,
|
||||
tipSignal: Signal<ContextController.Tip?, NoError>?,
|
||||
dismissed: (() -> Void)?
|
||||
@ -1041,9 +1041,9 @@ final class ContextControllerActionsCustomStackItem: ContextControllerActionsSta
|
||||
}
|
||||
|
||||
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 {
|
||||
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<ContextController.Tip?, NoError>?
|
||||
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)?
|
||||
var storedScrollingState: CGFloat?
|
||||
let positionLock: CGFloat?
|
||||
@ -1182,7 +1182,7 @@ final class ContextControllerActionsStackNode: ASDisplayNode {
|
||||
item: ContextControllerActionsStackItem,
|
||||
tip: ContextController.Tip?,
|
||||
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)?,
|
||||
positionLock: CGFloat?
|
||||
) {
|
||||
@ -1333,7 +1333,7 @@ final class ContextControllerActionsStackNode: ASDisplayNode {
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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<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.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))
|
||||
}
|
||||
|
@ -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<AvailableReactions?, NoError>
|
||||
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<EmojiSearchCategories?, NoError>
|
||||
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<MessageReaction.Reaction>()
|
||||
|
||||
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<MediaId>()
|
||||
|
||||
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",
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user