mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
5259ccb0c7
@ -7237,6 +7237,13 @@ Sorry for the inconvenience.";
|
||||
"PeerInfo.AllowedReactions.AllowAllGroupInfo" = "Allow subscribers to react to group messages.";
|
||||
"PeerInfo.AllowedReactions.AllowAllChannelInfo" = "Allow subscribers to react to channel posts.";
|
||||
"PeerInfo.AllowedReactions.ReactionListHeader" = "AVAILABLE REACTIONS";
|
||||
"PeerInfo.AllowedReactions.OptionAllReactions" = "All Reactions";
|
||||
"PeerInfo.AllowedReactions.OptionSomeReactions" = "Some Reactions";
|
||||
"PeerInfo.AllowedReactions.OptionNoReactions" = "No Reactions";
|
||||
|
||||
"PeerInfo.AllowedReactions.GroupOptionAllInfo" = "Members of this group can use any emoji as reactions to messages.";
|
||||
"PeerInfo.AllowedReactions.GroupOptionSomeInfo" = "Members of the group can use only some allowed emoji as reactions to messages.";
|
||||
"PeerInfo.AllowedReactions.GroupOptionNoInfo" = "Members of the group can't add any reactions to messages.";
|
||||
|
||||
"PeerInfo.Reactions" = "Reactions";
|
||||
"PeerInfo.ReactionsDisabled" = "Disabled";
|
||||
@ -7249,6 +7256,9 @@ Sorry for the inconvenience.";
|
||||
"Settings.QuickReactionSetup.DemoMessageAuthor" = "Dino";
|
||||
"Settings.QuickReactionSetup.DemoMessageText" = "I hope you're enjoying your day as much as I am.";
|
||||
|
||||
"Settings.QuickReactionSetup.ChooseQuickReaction" = "Choose Your Quick Reaction";
|
||||
"Settings.QuickReactionSetup.ChooseQuickReactionInfo" = "You can set any emoji as your quick reaction.";
|
||||
|
||||
"Chat.ContextReactionCount_1" = "1 reaction";
|
||||
"Chat.ContextReactionCount_any" = "%@ reactions";
|
||||
"Chat.OutgoingContextReactionCount_1" = "1 reacted";
|
||||
@ -8046,3 +8056,22 @@ Sorry for the inconvenience.";
|
||||
|
||||
"Premium.EmojiStatus" = "Emoji Status";
|
||||
"Premium.EmojiStatusInfo" = "Add any of thousands emojis next to your name to display current activity.";
|
||||
|
||||
"PeerStatusSetup.NoTimerTitle" = "Long tap to set a timer";
|
||||
"Chat.PremiumReactionToastTitle" = "Subscribe to **Telegram Premium** to unlock this reaction.";
|
||||
"Chat.PremiumReactionToastAction" = "More";
|
||||
|
||||
"Chat.ClearReactionsAlertText" = "Do you want to clear your recent reaction emoji from suggestions?";
|
||||
"Chat.ClearReactionsAlertAction" = "Clear Recent Emoji";
|
||||
|
||||
"EmojiStatusSetup.SetUntil" = "Set Until";
|
||||
"EmojiStatusSetup.TimerOther" = "Other";
|
||||
|
||||
"Chat.ReactionSection.Popular" = "Popular";
|
||||
"Chat.ReactionSection.Recent" = "Recently Used";
|
||||
|
||||
"PeerInfo.SetEmojiStatus" = "Set Emoji Status";
|
||||
"PeerInfo.ChangeEmojiStatus" = "Change Emoji Status";
|
||||
|
||||
"PeerInfo.LabelAllReactions" = "All Reactions";
|
||||
|
||||
|
@ -852,8 +852,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
private func openStatusSetup(sourceView: UIView) {
|
||||
self.emojiStatusSelectionController?.dismiss()
|
||||
var selectedItems = Set<MediaId>()
|
||||
//TODO:localize
|
||||
var topStatusTitle = "Long tap to set a timer"
|
||||
var topStatusTitle = self.presentationData.strings.PeerStatusSetup_NoTimerTitle
|
||||
if let peerStatus = self.titleView.title.peerStatus, case let .emoji(emojiStatus) = peerStatus {
|
||||
selectedItems.insert(MediaId(namespace: Namespaces.Media.CloudFile, id: emojiStatus.fileId))
|
||||
|
||||
|
@ -568,9 +568,8 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
|
||||
animateInAsReplacement = true
|
||||
}
|
||||
|
||||
//TODO:localize
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let undoController = UndoOverlayController(presentationData: presentationData, content: .sticker(context: context, file: file, title: nil, text: "Subscribe to **Telegram Premium** to unlock this reaction.", undoText: "More", customAction: { [weak controller] in
|
||||
let undoController = UndoOverlayController(presentationData: presentationData, content: .sticker(context: context, file: file, title: nil, text: presentationData.strings.Chat_PremiumReactionToastTitle, undoText: presentationData.strings.Chat_PremiumReactionToastAction, customAction: { [weak controller] in
|
||||
controller?.premiumReactionsSelected?()
|
||||
}), elevatedLayout: false, position: position, animateInAsReplacement: animateInAsReplacement, action: { _ in true })
|
||||
strongSelf.currentUndoController = undoController
|
||||
|
@ -278,8 +278,7 @@ private func peerAllowedReactionListControllerEntries(
|
||||
|
||||
if let peer = peer, let availableReactions = availableReactions, let allowedReactions = state.updatedAllowedReactions, let mode = state.updatedMode {
|
||||
if let channel = peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
//TODO:localize
|
||||
entries.append(.allowSwitch(text: "Allow Reactions", value: mode != .empty))
|
||||
entries.append(.allowSwitch(text: presentationData.strings.PeerInfo_AllowedReactions_AllowAllText, value: mode != .empty))
|
||||
|
||||
entries.append(.itemsHeader(presentationData.strings.PeerInfo_AllowedReactions_ReactionListHeader))
|
||||
var index = 0
|
||||
@ -291,32 +290,30 @@ private func peerAllowedReactionListControllerEntries(
|
||||
index += 1
|
||||
}
|
||||
} else {
|
||||
//TODO:localize
|
||||
entries.append(.allowAllHeader("AVAILABLE REACTIONS"))
|
||||
entries.append(.allowAllHeader(presentationData.strings.PeerInfo_AllowedReactions_ReactionListHeader))
|
||||
|
||||
//TODO:localize
|
||||
entries.append(.allowAll(text: "All Reactions", isEnabled: mode == .all))
|
||||
entries.append(.allowSome(text: "Some Reactions", isEnabled: mode == .some))
|
||||
entries.append(.allowNone(text: "No Reactions", isEnabled: mode == .empty))
|
||||
entries.append(.allowAll(text: presentationData.strings.PeerInfo_AllowedReactions_OptionAllReactions, isEnabled: mode == .all))
|
||||
entries.append(.allowSome(text: presentationData.strings.PeerInfo_AllowedReactions_OptionSomeReactions, isEnabled: mode == .some))
|
||||
entries.append(.allowNone(text: presentationData.strings.PeerInfo_AllowedReactions_OptionNoReactions, isEnabled: mode == .empty))
|
||||
|
||||
let allInfoText: String
|
||||
if let peer = peer as? TelegramChannel, case .broadcast = peer.info {
|
||||
switch mode {
|
||||
case .all:
|
||||
allInfoText = "Subscribers of this channel can use any emoji as reactions to messages."
|
||||
allInfoText = presentationData.strings.PeerInfo_AllowedReactions_GroupOptionAllInfo
|
||||
case .some:
|
||||
allInfoText = "You can select emoji that will allow subscribers of your channel to react to messages."
|
||||
allInfoText = presentationData.strings.PeerInfo_AllowedReactions_GroupOptionSomeInfo
|
||||
case .empty:
|
||||
allInfoText = "Subscribers of the channel can't add any reactions to messages."
|
||||
allInfoText = presentationData.strings.PeerInfo_AllowedReactions_GroupOptionNoInfo
|
||||
}
|
||||
} else {
|
||||
switch mode {
|
||||
case .all:
|
||||
allInfoText = "Members of this group can use any emoji as reactions to messages."
|
||||
allInfoText = presentationData.strings.PeerInfo_AllowedReactions_GroupOptionAllInfo
|
||||
case .some:
|
||||
allInfoText = "Members of the group can use only some allowed emoji as reactions to messages."
|
||||
allInfoText = presentationData.strings.PeerInfo_AllowedReactions_GroupOptionSomeInfo
|
||||
case .empty:
|
||||
allInfoText = "Members of the group can't add any reactions to messages."
|
||||
allInfoText = presentationData.strings.PeerInfo_AllowedReactions_GroupOptionNoInfo
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -798,7 +798,7 @@ private final class DemoSheetContent: CombinedComponent {
|
||||
context: component.context,
|
||||
position: .top,
|
||||
videoFile: configuration.videos["infinite_reactions"],
|
||||
decoration: .badgeStars
|
||||
decoration: .swirlStars
|
||||
)),
|
||||
title: strings.Premium_InfiniteReactions,
|
||||
text: strings.Premium_InfiniteReactionsInfo,
|
||||
@ -834,7 +834,7 @@ private final class DemoSheetContent: CombinedComponent {
|
||||
context: component.context,
|
||||
position: .top,
|
||||
videoFile: configuration.videos["emoji_status"],
|
||||
decoration: .swirlStars
|
||||
decoration: .badgeStars
|
||||
)),
|
||||
title: strings.Premium_EmojiStatus,
|
||||
text: strings.Premium_EmojiStatusInfo,
|
||||
|
@ -323,6 +323,7 @@ private final class PremiumGiftScreenContentComponent: CombinedComponent {
|
||||
let gradientColors: [UIColor] = [
|
||||
UIColor(rgb: 0xF27C30),
|
||||
UIColor(rgb: 0xE36850),
|
||||
UIColor(rgb: 0xda5d63),
|
||||
UIColor(rgb: 0xD15078),
|
||||
UIColor(rgb: 0xC14998),
|
||||
UIColor(rgb: 0xB24CB5),
|
||||
@ -332,7 +333,7 @@ private final class PremiumGiftScreenContentComponent: CombinedComponent {
|
||||
UIColor(rgb: 0x5A6EEE),
|
||||
UIColor(rgb: 0x548DFF),
|
||||
UIColor(rgb: 0x54A3FF),
|
||||
UIColor(rgb: 0x54A3FF)
|
||||
UIColor(rgb: 0x54bdff)
|
||||
]
|
||||
|
||||
i = 0
|
||||
|
@ -260,7 +260,7 @@ enum PremiumPerk: CaseIterable {
|
||||
case .animatedEmoji:
|
||||
return "Premium/Perk/Emoji"
|
||||
case .emojiStatus:
|
||||
return "Premium/Perk/Emoji"
|
||||
return "Premium/Perk/Status"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1261,6 +1261,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
||||
let gradientColors: [UIColor] = [
|
||||
UIColor(rgb: 0xF27C30),
|
||||
UIColor(rgb: 0xE36850),
|
||||
UIColor(rgb: 0xda5d63),
|
||||
UIColor(rgb: 0xD15078),
|
||||
UIColor(rgb: 0xC14998),
|
||||
UIColor(rgb: 0xB24CB5),
|
||||
@ -1270,7 +1271,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
||||
UIColor(rgb: 0x5A6EEE),
|
||||
UIColor(rgb: 0x548DFF),
|
||||
UIColor(rgb: 0x54A3FF),
|
||||
UIColor(rgb: 0x54A3FF)
|
||||
UIColor(rgb: 0x54bdff)
|
||||
]
|
||||
|
||||
let accountContext = context.component.context
|
||||
|
@ -33,6 +33,7 @@ swift_library(
|
||||
"//submodules/Components/ComponentDisplayAdapters:ComponentDisplayAdapters",
|
||||
"//submodules/TextFormat:TextFormat",
|
||||
"//submodules/GZip:GZip",
|
||||
"//submodules/ShimmerEffect:ShimmerEffect",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -1145,9 +1145,8 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
let actionSheet = ActionSheetController(theme: ActionSheetControllerTheme(presentationTheme: presentationData.theme, fontSize: presentationData.listsFontSize))
|
||||
var items: [ActionSheetItem] = []
|
||||
let context = strongSelf.context
|
||||
//TODO:localize
|
||||
items.append(ActionSheetTextItem(title: "Do you want to clear your recent reaction emoji from suggestions?", parseMarkdown: true))
|
||||
items.append(ActionSheetButtonItem(title: presentationData.strings.Emoji_ClearRecent, color: .destructive, action: { [weak actionSheet] in
|
||||
items.append(ActionSheetTextItem(title: presentationData.strings.Chat_ClearReactionsAlertText, parseMarkdown: true))
|
||||
items.append(ActionSheetButtonItem(title: presentationData.strings.Chat_ClearReactionsAlertAction, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -1180,6 +1179,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
externalBackground: EmojiPagerContentComponent.ExternalBackground(
|
||||
effectContainerView: self.backgroundNode.vibrancyEffectView?.contentView
|
||||
),
|
||||
externalExpansionView: self.view,
|
||||
useOpaqueTheme: false
|
||||
)
|
||||
}
|
||||
@ -1423,13 +1423,16 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
|
||||
let expandedFrame = CGRect(origin: CGPoint(x: selfTargetRect.midX - expandedSize.width / 2.0, y: selfTargetRect.midY - expandedSize.height / 2.0), size: expandedSize)
|
||||
|
||||
let effectFrame: CGRect
|
||||
var effectFrame: CGRect
|
||||
let incomingMessage: Bool = expandedFrame.midX < self.bounds.width / 2.0
|
||||
if self.didTriggerExpandedReaction {
|
||||
let expandFactor: CGFloat = 0.5
|
||||
effectFrame = expandedFrame.insetBy(dx: -expandedFrame.width * expandFactor, dy: -expandedFrame.height * expandFactor).offsetBy(dx: incomingMessage ? (expandedFrame.width - 50.0) : (-expandedFrame.width + 50.0), dy: 0.0)
|
||||
} else {
|
||||
effectFrame = expandedFrame.insetBy(dx: -expandedSize.width, dy: -expandedSize.height)
|
||||
if itemNode.item.isCustom {
|
||||
effectFrame = effectFrame.insetBy(dx: -expandedSize.width, dy: -expandedSize.height)
|
||||
}
|
||||
}
|
||||
|
||||
let transition: ContainedViewLayoutTransition = .animated(duration: 0.2, curve: .linear)
|
||||
@ -1442,11 +1445,28 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
let additionalAnimationNode: DefaultAnimatedStickerNodeImpl?
|
||||
var genericAnimationView: AnimationView?
|
||||
|
||||
let additionalAnimation: TelegramMediaFile?
|
||||
var additionalAnimation: TelegramMediaFile?
|
||||
if self.didTriggerExpandedReaction {
|
||||
additionalAnimation = itemNode.item.largeApplicationAnimation
|
||||
} else {
|
||||
additionalAnimation = itemNode.item.applicationAnimation
|
||||
|
||||
if additionalAnimation == nil && itemNode.item.isCustom {
|
||||
outer: for attribute in itemNode.item.stillAnimation.attributes {
|
||||
if case let .CustomEmoji(_, alt, _) = attribute {
|
||||
if let availableReactions = self.availableReactions {
|
||||
for availableReaction in availableReactions.reactions {
|
||||
if availableReaction.value == .builtin(alt) {
|
||||
additionalAnimation = availableReaction.aroundAnimation
|
||||
break outer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let additionalAnimation = additionalAnimation {
|
||||
@ -1676,6 +1696,10 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
recognizer.state = .cancelled
|
||||
return
|
||||
}
|
||||
if !itemNode.isAnimationLoaded {
|
||||
recognizer.state = .cancelled
|
||||
return
|
||||
}
|
||||
|
||||
self.highlightedReaction = itemNode.item.reaction
|
||||
if #available(iOS 13.0, *) {
|
||||
@ -1871,6 +1895,9 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
public func reaction(at point: CGPoint) -> ReactionContextItem? {
|
||||
let itemNode = self.reactionItemNode(at: point)
|
||||
if let itemNode = itemNode as? ReactionNode {
|
||||
if !itemNode.isAnimationLoaded {
|
||||
return nil
|
||||
}
|
||||
return .reaction(itemNode.item)
|
||||
} else if let _ = itemNode as? PremiumReactionsNode {
|
||||
return .premium
|
||||
|
@ -12,6 +12,7 @@ import StickerResources
|
||||
import AccountContext
|
||||
import AnimationCache
|
||||
import MultiAnimationRenderer
|
||||
import ShimmerEffect
|
||||
|
||||
private func generateBubbleImage(foreground: UIColor, diameter: CGFloat, shadowBlur: CGFloat) -> UIImage? {
|
||||
return generateImage(CGSize(width: diameter + shadowBlur * 2.0, height: diameter + shadowBlur * 2.0), rotatedContext: { size, context in
|
||||
@ -48,6 +49,7 @@ protocol ReactionItemNode: ASDisplayNode {
|
||||
|
||||
public final class ReactionNode: ASDisplayNode, ReactionItemNode {
|
||||
let context: AccountContext
|
||||
let theme: PresentationTheme
|
||||
let item: ReactionItem
|
||||
private let loopIdle: Bool
|
||||
private let hasAppearAnimation: Bool
|
||||
@ -57,6 +59,7 @@ public final class ReactionNode: ASDisplayNode, ReactionItemNode {
|
||||
let selectionView: UIView
|
||||
|
||||
private var animateInAnimationNode: AnimatedStickerNode?
|
||||
private var staticAnimationPlaceholderView: UIImageView?
|
||||
private let staticAnimationNode: AnimatedStickerNode
|
||||
private var stillAnimationNode: AnimatedStickerNode?
|
||||
private var customContentsNode: ASDisplayNode?
|
||||
@ -83,8 +86,13 @@ public final class ReactionNode: ASDisplayNode, ReactionItemNode {
|
||||
return self.staticAnimationNode.currentFrameImage
|
||||
}
|
||||
|
||||
var isAnimationLoaded: Bool {
|
||||
return self.staticAnimationNode.currentFrameImage != nil
|
||||
}
|
||||
|
||||
public init(context: AccountContext, theme: PresentationTheme, item: ReactionItem, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, loopIdle: Bool, hasAppearAnimation: Bool = true, useDirectRendering: Bool = false) {
|
||||
self.context = context
|
||||
self.theme = theme
|
||||
self.item = item
|
||||
self.loopIdle = loopIdle
|
||||
self.hasAppearAnimation = hasAppearAnimation
|
||||
@ -361,6 +369,33 @@ public final class ReactionNode: ASDisplayNode, ReactionItemNode {
|
||||
if self.animationNode == nil {
|
||||
self.didSetupStillAnimation = true
|
||||
|
||||
let staticFile: TelegramMediaFile
|
||||
if !self.hasAppearAnimation {
|
||||
staticFile = self.item.largeListAnimation
|
||||
} else {
|
||||
staticFile = self.item.stillAnimation
|
||||
}
|
||||
|
||||
if self.staticAnimationPlaceholderView == nil, let immediateThumbnailData = staticFile.immediateThumbnailData {
|
||||
let staticAnimationPlaceholderView = UIImageView()
|
||||
self.view.addSubview(staticAnimationPlaceholderView)
|
||||
self.staticAnimationPlaceholderView = staticAnimationPlaceholderView
|
||||
|
||||
if let image = generateStickerPlaceholderImage(data: immediateThumbnailData, size: animationDisplaySize, scale: min(2.0, UIScreenScale), imageSize: staticFile.dimensions?.cgSize ?? CGSize(width: 512.0, height: 512.0), backgroundColor: nil, foregroundColor: self.theme.chat.inputPanel.primaryTextColor.withMultipliedAlpha(0.1)) {
|
||||
staticAnimationPlaceholderView.image = image
|
||||
}
|
||||
}
|
||||
|
||||
self.staticAnimationNode.started = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if let staticAnimationPlaceholderView = strongSelf.staticAnimationPlaceholderView {
|
||||
strongSelf.staticAnimationPlaceholderView = nil
|
||||
staticAnimationPlaceholderView.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
self.staticAnimationNode.automaticallyLoadFirstFrame = true
|
||||
if !self.hasAppearAnimation {
|
||||
self.staticAnimationNode.setup(source: AnimatedStickerResourceSource(account: self.context.account, resource: self.item.largeListAnimation.resource, isVideo: self.item.largeListAnimation.isVideoEmoji || self.item.largeListAnimation.isVideoSticker || self.item.largeListAnimation.isStaticSticker || self.item.largeListAnimation.isStaticEmoji), width: Int(expandedAnimationFrame.width * 2.0), height: Int(expandedAnimationFrame.height * 2.0), playbackMode: .still(.start), mode: .direct(cachePathPrefix: self.context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(self.item.largeListAnimation.resource.id)))
|
||||
@ -372,6 +407,11 @@ public final class ReactionNode: ASDisplayNode, ReactionItemNode {
|
||||
self.staticAnimationNode.updateLayout(size: animationFrame.size)
|
||||
self.staticAnimationNode.visibility = true
|
||||
|
||||
if let staticAnimationPlaceholderView = self.staticAnimationPlaceholderView {
|
||||
staticAnimationPlaceholderView.center = animationFrame.center
|
||||
staticAnimationPlaceholderView.bounds = CGRect(origin: CGPoint(), size: animationFrame.size)
|
||||
}
|
||||
|
||||
if let animateInAnimationNode = self.animateInAnimationNode {
|
||||
animateInAnimationNode.setup(source: AnimatedStickerResourceSource(account: self.context.account, resource: self.item.appearAnimation.resource, isVideo: self.item.appearAnimation.isVideoEmoji || self.item.appearAnimation.isVideoSticker || self.item.appearAnimation.isStaticSticker || self.item.appearAnimation.isStaticEmoji), width: Int(animationDisplaySize.width * 2.0), height: Int(animationDisplaySize.height * 2.0), playbackMode: .once, mode: .direct(cachePathPrefix: self.context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(self.item.appearAnimation.resource.id)))
|
||||
animateInAnimationNode.position = animationFrame.center
|
||||
@ -383,6 +423,11 @@ public final class ReactionNode: ASDisplayNode, ReactionItemNode {
|
||||
transition.updatePosition(node: self.staticAnimationNode, position: animationFrame.center, beginWithCurrentState: true)
|
||||
transition.updateTransformScale(node: self.staticAnimationNode, scale: animationFrame.size.width / self.staticAnimationNode.bounds.width, beginWithCurrentState: true)
|
||||
|
||||
if let staticAnimationPlaceholderView = self.staticAnimationPlaceholderView {
|
||||
transition.updatePosition(layer: staticAnimationPlaceholderView.layer, position: animationFrame.center)
|
||||
transition.updateTransformScale(layer: staticAnimationPlaceholderView.layer, scale: animationFrame.size.width / self.staticAnimationNode.bounds.width)
|
||||
}
|
||||
|
||||
if let animateInAnimationNode = self.animateInAnimationNode {
|
||||
transition.updatePosition(node: animateInAnimationNode, position: animationFrame.center, beginWithCurrentState: true)
|
||||
transition.updateTransformScale(node: animateInAnimationNode, scale: animationFrame.size.width / animateInAnimationNode.bounds.width, beginWithCurrentState: true)
|
||||
|
@ -189,11 +189,9 @@ private func quickReactionSetupControllerEntries(
|
||||
))
|
||||
entries.append(.demoDescription(presentationData.strings.Settings_QuickReactionSetup_DemoInfo))
|
||||
|
||||
//TODO:localize
|
||||
entries.append(.quickReaction("Choose Your Quick Reaction", reactionSettings.quickReaction, availableReactions))
|
||||
entries.append(.quickReaction(presentationData.strings.Settings_QuickReactionSetup_ChooseQuickReaction, reactionSettings.quickReaction, availableReactions))
|
||||
|
||||
//TODO:localize
|
||||
entries.append(.quickReactionDescription("You can set any emoji as your quick reaction."))
|
||||
entries.append(.quickReactionDescription(presentationData.strings.Settings_QuickReactionSetup_ChooseQuickReactionInfo))
|
||||
}
|
||||
|
||||
return entries
|
||||
|
@ -66,12 +66,17 @@ public func mergedMessageReactionsAndPeers(accountPeer: EnginePeer?, message: Me
|
||||
|
||||
if message.id.peerId.namespace == Namespaces.Peer.CloudUser {
|
||||
for reaction in attribute.reactions {
|
||||
var selfCount: Int32 = 0
|
||||
if reaction.isSelected {
|
||||
selfCount += 1
|
||||
if let accountPeer = accountPeer {
|
||||
recentPeers.append((reaction.value, accountPeer))
|
||||
}
|
||||
} else if let peer = message.peers[message.id.peerId] {
|
||||
recentPeers.append((reaction.value, EnginePeer(peer)))
|
||||
}
|
||||
if reaction.count > selfCount + 1 {
|
||||
if let peer = message.peers[message.id.peerId] {
|
||||
recentPeers.append((reaction.value, EnginePeer(peer)))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -1629,6 +1629,15 @@ func extractEmojiFileIds(message: StoreMessage, fileIds: inout Set<Int64>) {
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if let attribute = attribute as? ReactionsMessageAttribute {
|
||||
for reaction in attribute.reactions {
|
||||
switch reaction.value {
|
||||
case let .custom(fileId):
|
||||
fileIds.insert(fileId)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1648,10 +1657,22 @@ private func messagesFromOperations(state: AccountMutableState) -> [StoreMessage
|
||||
return messages
|
||||
}
|
||||
|
||||
private func reactionsFromState(_ state: AccountMutableState) -> [MessageReaction.Reaction] {
|
||||
var result: [MessageReaction.Reaction] = []
|
||||
for operation in state.operations {
|
||||
if case let .UpdateMessageReactions(_, reactions, _) = operation {
|
||||
for reaction in ReactionsMessageAttribute(apiReactions: reactions).reactions {
|
||||
result.append(reaction.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private func resolveAssociatedMessages(postbox: Postbox, network: Network, state: AccountMutableState) -> Signal<AccountMutableState, NoError> {
|
||||
let missingMessageIds = state.referencedMessageIds.subtracting(state.storedMessages)
|
||||
if missingMessageIds.isEmpty {
|
||||
return resolveUnknownEmojiFiles(postbox: postbox, source: .network(network), messages: messagesFromOperations(state: state), result: state)
|
||||
return resolveUnknownEmojiFiles(postbox: postbox, source: .network(network), messages: messagesFromOperations(state: state), reactions: reactionsFromState(state), result: state)
|
||||
} else {
|
||||
var missingPeers = false
|
||||
let _ = missingPeers
|
||||
@ -1713,7 +1734,7 @@ private func resolveAssociatedMessages(postbox: Postbox, network: Network, state
|
||||
return updatedState
|
||||
}
|
||||
|> mapToSignal { updatedState -> Signal<AccountMutableState, NoError> in
|
||||
return resolveUnknownEmojiFiles(postbox: postbox, source: .network(network), messages: messagesFromOperations(state: updatedState), result: updatedState)
|
||||
return resolveUnknownEmojiFiles(postbox: postbox, source: .network(network), messages: messagesFromOperations(state: updatedState), reactions: reactionsFromState(updatedState), result: updatedState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -390,7 +390,7 @@ func fetchChatList(postbox: Postbox, network: Network, location: FetchChatListLo
|
||||
folderSummaries: folderSummaries,
|
||||
peerGroupIds: peerGroupIds
|
||||
)
|
||||
return resolveUnknownEmojiFiles(postbox: postbox, source: .network(network), messages: storeMessages, result: result)
|
||||
return resolveUnknownEmojiFiles(postbox: postbox, source: .network(network), messages: storeMessages, reactions: [], result: result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -43,13 +43,19 @@ enum FetchMessageHistoryHoleSource {
|
||||
}
|
||||
}
|
||||
|
||||
func resolveUnknownEmojiFiles<T>(postbox: Postbox, source: FetchMessageHistoryHoleSource, messages: [StoreMessage], result: T) -> Signal<T, NoError> {
|
||||
func resolveUnknownEmojiFiles<T>(postbox: Postbox, source: FetchMessageHistoryHoleSource, messages: [StoreMessage], reactions: [MessageReaction.Reaction], result: T) -> Signal<T, NoError> {
|
||||
var fileIds = Set<Int64>()
|
||||
|
||||
for message in messages {
|
||||
extractEmojiFileIds(message: message, fileIds: &fileIds)
|
||||
}
|
||||
|
||||
for reaction in reactions {
|
||||
if case let .custom(fileId) = reaction {
|
||||
fileIds.insert(fileId)
|
||||
}
|
||||
}
|
||||
|
||||
if fileIds.isEmpty {
|
||||
return .single(result)
|
||||
} else {
|
||||
@ -111,7 +117,7 @@ private func withResolvedAssociatedMessages<T>(postbox: Postbox, source: FetchMe
|
||||
referencedIds.subtract(transaction.filterStoredMessageIds(referencedIds))
|
||||
|
||||
if referencedIds.isEmpty {
|
||||
return resolveUnknownEmojiFiles(postbox: postbox, source: source, messages: storeMessages, result: Void())
|
||||
return resolveUnknownEmojiFiles(postbox: postbox, source: source, messages: storeMessages, reactions: [], result: Void())
|
||||
|> mapToSignal { _ -> Signal<T, NoError> in
|
||||
return postbox.transaction { transaction -> T in
|
||||
return f(transaction, [], [])
|
||||
@ -174,7 +180,7 @@ private func withResolvedAssociatedMessages<T>(postbox: Postbox, source: FetchMe
|
||||
}
|
||||
}
|
||||
|
||||
return resolveUnknownEmojiFiles(postbox: postbox, source: source, messages: storeMessages + additionalMessages, result: Void())
|
||||
return resolveUnknownEmojiFiles(postbox: postbox, source: source, messages: storeMessages + additionalMessages, reactions: [], result: Void())
|
||||
|> mapToSignal { _ -> Signal<T, NoError> in
|
||||
return postbox.transaction { transaction -> T in
|
||||
return f(transaction, additionalPeers, additionalMessages)
|
||||
|
@ -1390,6 +1390,12 @@ private func findHigherResolutionFileForAdaptation(itemDirectoryPath: String, ba
|
||||
|
||||
public final class AnimationCacheImpl: AnimationCache {
|
||||
private final class Impl {
|
||||
private struct ItemKey: Hashable {
|
||||
var id: String
|
||||
var width: Int
|
||||
var height: Int
|
||||
}
|
||||
|
||||
private final class ItemContext {
|
||||
let subscribers = Bag<(AnimationCacheItemResult) -> Void>()
|
||||
let disposable = MetaDisposable()
|
||||
@ -1406,7 +1412,7 @@ public final class AnimationCacheImpl: AnimationCache {
|
||||
private let fetchQueues: [Queue]
|
||||
private var nextFetchQueueIndex: Int = 0
|
||||
|
||||
private var itemContexts: [String: ItemContext] = [:]
|
||||
private var itemContexts: [ItemKey: ItemContext] = [:]
|
||||
|
||||
init(queue: Queue, basePath: String, allocateTempFile: @escaping () -> String) {
|
||||
self.queue = queue
|
||||
@ -1437,14 +1443,15 @@ public final class AnimationCacheImpl: AnimationCache {
|
||||
|
||||
return EmptyDisposable
|
||||
}
|
||||
let key = ItemKey(id: sourceId, width: Int(size.width), height: Int(size.height))
|
||||
|
||||
let itemContext: ItemContext
|
||||
var beginFetch = false
|
||||
if let current = self.itemContexts[sourceId] {
|
||||
if let current = self.itemContexts[key] {
|
||||
itemContext = current
|
||||
} else {
|
||||
itemContext = ItemContext()
|
||||
self.itemContexts[sourceId] = itemContext
|
||||
self.itemContexts[key] = itemContext
|
||||
beginFetch = true
|
||||
}
|
||||
|
||||
@ -1459,11 +1466,11 @@ public final class AnimationCacheImpl: AnimationCache {
|
||||
let allocateTempFile = self.allocateTempFile
|
||||
guard let writer = AnimationCacheItemWriterImpl(queue: self.fetchQueues[fetchQueueIndex % self.fetchQueues.count], allocateTempFile: self.allocateTempFile, completion: { [weak self, weak itemContext] result in
|
||||
queue.async {
|
||||
guard let strongSelf = self, let itemContext = itemContext, itemContext === strongSelf.itemContexts[sourceId] else {
|
||||
guard let strongSelf = self, let itemContext = itemContext, itemContext === strongSelf.itemContexts[key] else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.itemContexts.removeValue(forKey: sourceId)
|
||||
strongSelf.itemContexts.removeValue(forKey: key)
|
||||
|
||||
guard let result = result else {
|
||||
return
|
||||
@ -1503,13 +1510,13 @@ public final class AnimationCacheImpl: AnimationCache {
|
||||
|
||||
return ActionDisposable { [weak self, weak itemContext] in
|
||||
queue.async {
|
||||
guard let strongSelf = self, let itemContext = itemContext, itemContext === strongSelf.itemContexts[sourceId] else {
|
||||
guard let strongSelf = self, let itemContext = itemContext, itemContext === strongSelf.itemContexts[key] else {
|
||||
return
|
||||
}
|
||||
itemContext.subscribers.remove(index)
|
||||
if itemContext.subscribers.isEmpty {
|
||||
itemContext.disposable.dispose()
|
||||
strongSelf.itemContexts.removeValue(forKey: sourceId)
|
||||
strongSelf.itemContexts.removeValue(forKey: key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -437,10 +437,9 @@ private final class TimeSelectionControlComponent: Component {
|
||||
let pickerSize = CGSize(width: availableSize.width, height: 216.0)
|
||||
let pickerFrame = CGRect(origin: CGPoint(x: 0.0, y: topPanelHeight + pickerSpacing), size: pickerSize)
|
||||
|
||||
//TODO:localize
|
||||
let titleSize = self.titleView.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(Text(text: "Set Until", font: Font.semibold(17.0), color: component.theme.list.itemPrimaryTextColor)),
|
||||
component: AnyComponent(Text(text: component.strings.EmojiStatusSetup_SetUntil, font: Font.semibold(17.0), color: component.theme.list.itemPrimaryTextColor)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width, height: 100.0)
|
||||
)
|
||||
@ -473,11 +472,10 @@ private final class TimeSelectionControlComponent: Component {
|
||||
transition.setFrame(view: leftButtonComponentView, frame: CGRect(origin: CGPoint(x: 16.0, y: floor((topPanelHeight - leftButtonSize.height) / 2.0)), size: leftButtonSize))
|
||||
}
|
||||
|
||||
//TODO:localize
|
||||
let actionButtonSize = self.actionButtonView.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(SolidRoundedButtonComponent(
|
||||
title: "Set Until",
|
||||
title: component.strings.EmojiStatusSetup_SetUntil,
|
||||
icon: nil,
|
||||
theme: SolidRoundedButtonComponent.Theme(theme: component.theme),
|
||||
font: .bold,
|
||||
@ -674,9 +672,8 @@ final class EmojiStatusPreviewScreenComponent: Component {
|
||||
}
|
||||
))))
|
||||
}
|
||||
//TODO:localize
|
||||
menuItems.append(AnyComponentWithIdentity(id: "Other", component: AnyComponent(ContextMenuActionItem(
|
||||
title: "Other",
|
||||
title: component.strings.EmojiStatusSetup_TimerOther,
|
||||
action: { [weak self] in
|
||||
self?.toggleState()
|
||||
return .clearHighlight
|
||||
|
@ -345,6 +345,7 @@ public final class EmojiStatusSelectionController: ViewController {
|
||||
peekBehavior: nil,
|
||||
customLayout: nil,
|
||||
externalBackground: nil,
|
||||
externalExpansionView: nil,
|
||||
useOpaqueTheme: true
|
||||
)
|
||||
|
||||
|
@ -1581,6 +1581,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
public let peekBehavior: EmojiContentPeekBehavior?
|
||||
public let customLayout: CustomLayout?
|
||||
public let externalBackground: ExternalBackground?
|
||||
public let externalExpansionView: UIView?
|
||||
public let useOpaqueTheme: Bool
|
||||
|
||||
public init(
|
||||
@ -1599,6 +1600,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
peekBehavior: EmojiContentPeekBehavior?,
|
||||
customLayout: CustomLayout?,
|
||||
externalBackground: ExternalBackground?,
|
||||
externalExpansionView: UIView?,
|
||||
useOpaqueTheme: Bool
|
||||
) {
|
||||
self.performItemAction = performItemAction
|
||||
@ -1616,6 +1618,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
self.peekBehavior = peekBehavior
|
||||
self.customLayout = customLayout
|
||||
self.externalBackground = externalBackground
|
||||
self.externalExpansionView = externalExpansionView
|
||||
self.useOpaqueTheme = useOpaqueTheme
|
||||
}
|
||||
}
|
||||
@ -2201,6 +2204,9 @@ public final class EmojiPagerContentComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
final class CloneItemLayer: SimpleLayer {
|
||||
}
|
||||
|
||||
public final class ItemLayer: MultiAnimationRenderTarget {
|
||||
public struct Key: Hashable {
|
||||
var groupId: AnyHashable
|
||||
@ -2244,6 +2250,22 @@ public final class EmojiPagerContentComponent: Component {
|
||||
}
|
||||
public private(set) var displayPlaceholder: Bool = false
|
||||
public let onUpdateDisplayPlaceholder: (Bool, Double) -> Void
|
||||
|
||||
weak var cloneLayer: CloneItemLayer? {
|
||||
didSet {
|
||||
if let cloneLayer = self.cloneLayer {
|
||||
cloneLayer.contents = self.contents
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override public var contents: Any? {
|
||||
didSet {
|
||||
if let cloneLayer = self.cloneLayer {
|
||||
cloneLayer.contents = self.contents
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public init(
|
||||
item: Item,
|
||||
@ -3374,6 +3396,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
|
||||
private let longPressDuration: Double = 0.5
|
||||
private var longPressItem: EmojiPagerContentComponent.View.ItemLayer.Key?
|
||||
private var currentLongPressLayer: CloneItemLayer?
|
||||
private var hapticFeedback: HapticFeedback?
|
||||
private var continuousHaptic: AnyObject?
|
||||
private var longPressTimer: SwiftSignalKit.Timer?
|
||||
@ -3402,9 +3425,23 @@ public final class EmojiPagerContentComponent: Component {
|
||||
self.hapticFeedback = HapticFeedback()
|
||||
}
|
||||
|
||||
let _ = itemLayer
|
||||
//let transition = Transition(animation: .curve(duration: longPressDuration, curve: .easeInOut))
|
||||
//transition.setScale(layer: itemLayer, scale: 1.3)
|
||||
if let externalExpansionView = self.component?.inputInteractionHolder.inputInteraction?.externalExpansionView {
|
||||
if let currentLongPressLayer = self.currentLongPressLayer {
|
||||
self.currentLongPressLayer = nil
|
||||
currentLongPressLayer.removeFromSuperlayer()
|
||||
}
|
||||
let currentLongPressLayer = CloneItemLayer()
|
||||
currentLongPressLayer.position = self.scrollView.layer.convert(itemLayer.position, to: externalExpansionView.layer)
|
||||
currentLongPressLayer.bounds = itemLayer.convert(itemLayer.bounds, to: externalExpansionView.layer)
|
||||
currentLongPressLayer.transform = itemLayer.transform
|
||||
externalExpansionView.layer.addSublayer(currentLongPressLayer)
|
||||
self.currentLongPressLayer = currentLongPressLayer
|
||||
itemLayer.cloneLayer = currentLongPressLayer
|
||||
|
||||
itemLayer.isHidden = true
|
||||
let transition = Transition(animation: .curve(duration: longPressDuration, curve: .easeInOut))
|
||||
transition.setScale(layer: currentLongPressLayer, scale: 1.85)
|
||||
}
|
||||
|
||||
self.longPressTimer?.invalidate()
|
||||
self.longPressTimer = SwiftSignalKit.Timer(timeout: longPressDuration, repeat: false, completion: { [weak self] in
|
||||
@ -3431,7 +3468,23 @@ public final class EmojiPagerContentComponent: Component {
|
||||
if let itemLayer = self.visibleItemLayers[itemKey] {
|
||||
let transition = Transition(animation: .curve(duration: 0.3, curve: .spring))
|
||||
transition.setScale(layer: itemLayer, scale: 1.0)
|
||||
|
||||
if let currentLongPressLayer = self.currentLongPressLayer {
|
||||
self.currentLongPressLayer = nil
|
||||
|
||||
let transition = Transition(animation: .curve(duration: 0.3, curve: .spring))
|
||||
transition.setScale(layer: currentLongPressLayer, scale: 1.0, completion: { [weak itemLayer, weak currentLongPressLayer] _ in
|
||||
itemLayer?.isHidden = false
|
||||
currentLongPressLayer?.removeFromSuperlayer()
|
||||
})
|
||||
}
|
||||
} else if let currentLongPressLayer = self.currentLongPressLayer {
|
||||
self.currentLongPressLayer = nil
|
||||
currentLongPressLayer.removeFromSuperlayer()
|
||||
}
|
||||
} else if let currentLongPressLayer = self.currentLongPressLayer {
|
||||
self.currentLongPressLayer = nil
|
||||
currentLongPressLayer.removeFromSuperlayer()
|
||||
}
|
||||
case .ended:
|
||||
self.longPressTimer?.invalidate()
|
||||
@ -3441,11 +3494,32 @@ public final class EmojiPagerContentComponent: Component {
|
||||
self.longPressItem = nil
|
||||
|
||||
if let component = self.component, let itemLayer = self.visibleItemLayers[itemKey] {
|
||||
component.inputInteractionHolder.inputInteraction?.performItemAction(itemKey.groupId, itemLayer.item, self, self.scrollView.convert(itemLayer.frame, to: self), itemLayer, true)
|
||||
if let externalExpansionView = self.component?.inputInteractionHolder.inputInteraction?.externalExpansionView, let currentLongPressLayer = self.currentLongPressLayer {
|
||||
component.inputInteractionHolder.inputInteraction?.performItemAction(itemKey.groupId, itemLayer.item, externalExpansionView, currentLongPressLayer.frame, currentLongPressLayer, true)
|
||||
} else {
|
||||
component.inputInteractionHolder.inputInteraction?.performItemAction(itemKey.groupId, itemLayer.item, self, self.scrollView.convert(itemLayer.frame, to: self), itemLayer, true)
|
||||
}
|
||||
} else {
|
||||
if let itemLayer = self.visibleItemLayers[itemKey] {
|
||||
let transition = Transition(animation: .curve(duration: 0.3, curve: .spring))
|
||||
transition.setScale(layer: itemLayer, scale: 1.0)
|
||||
|
||||
if let currentLongPressLayer = self.currentLongPressLayer {
|
||||
self.currentLongPressLayer = nil
|
||||
|
||||
let transition = Transition(animation: .curve(duration: 0.3, curve: .spring))
|
||||
transition.setScale(layer: currentLongPressLayer, scale: 1.0, completion: { [weak itemLayer, weak currentLongPressLayer] _ in
|
||||
itemLayer?.isHidden = false
|
||||
currentLongPressLayer?.removeFromSuperlayer()
|
||||
})
|
||||
}
|
||||
} else if let currentLongPressLayer = self.currentLongPressLayer {
|
||||
self.currentLongPressLayer = nil
|
||||
|
||||
let transition = Transition(animation: .curve(duration: 0.3, curve: .spring))
|
||||
transition.setScale(layer: currentLongPressLayer, scale: 1.0, completion: { [weak currentLongPressLayer] _ in
|
||||
currentLongPressLayer?.removeFromSuperlayer()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4911,7 +4985,6 @@ public final class EmojiPagerContentComponent: Component {
|
||||
itemGroups[groupIndex].items.append(resultItem)
|
||||
} else {
|
||||
itemGroupIndexById[groupId] = itemGroups.count
|
||||
//TODO:localize
|
||||
itemGroups.append(ItemGroup(supergroupId: groupId, id: groupId, title: topStatusTitle?.uppercased(), subtitle: nil, isPremiumLocked: false, isFeatured: false, collapsedLineCount: 5, isClearable: false, headerItem: nil, items: [resultItem]))
|
||||
}
|
||||
|
||||
@ -5121,8 +5194,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
maxRecentLineCount = 5
|
||||
}
|
||||
|
||||
//TODO:localize
|
||||
let popularTitle = hasRecent ? "Recently Used" : "Popular"
|
||||
let popularTitle = hasRecent ? strings.Chat_ReactionSection_Recent : strings.Chat_ReactionSection_Popular
|
||||
|
||||
if let availableReactions = availableReactions {
|
||||
for reactionItem in availableReactions.reactions {
|
||||
|
12
submodules/TelegramUI/Images.xcassets/Premium/Perk/Status.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Premium/Perk/Status.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "status.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
98
submodules/TelegramUI/Images.xcassets/Premium/Perk/Status.imageset/status.pdf
vendored
Normal file
98
submodules/TelegramUI/Images.xcassets/Premium/Perk/Status.imageset/status.pdf
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 4.320007 2.144306 cm
|
||||
1.000000 1.000000 1.000000 scn
|
||||
10.373089 2.859669 m
|
||||
8.050100 4.488478 6.380870 6.558828 3.543569 9.138160 c
|
||||
2.650327 9.950203 1.641354 10.812672 0.459726 11.727699 c
|
||||
-0.718856 12.606317 0.605010 14.381629 1.780190 13.505348 c
|
||||
4.284061 11.489586 l
|
||||
6.457295 9.740021 l
|
||||
6.992327 9.341235 7.617038 10.095894 7.164679 10.554753 c
|
||||
4.466011 13.444919 l
|
||||
1.629065 16.483160 l
|
||||
0.624206 17.494774 2.149370 19.019176 3.158343 18.003448 c
|
||||
5.809479 15.159142 l
|
||||
8.512616 12.259024 l
|
||||
8.970663 11.794324 9.717808 12.423758 9.318109 12.953712 c
|
||||
6.570284 16.767281 l
|
||||
3.620909 20.860554 l
|
||||
2.785100 22.005569 4.518925 23.287643 5.364432 22.129528 c
|
||||
8.200413 18.189003 l
|
||||
10.914721 14.417480 l
|
||||
11.343112 13.849086 12.225386 14.414383 11.897745 15.040059 c
|
||||
10.236182 18.412340 l
|
||||
8.358698 22.222813 l
|
||||
7.680108 23.518496 9.637980 24.552961 10.320377 23.250320 c
|
||||
11.154460 21.568140 11.866667 20.137379 12.507627 18.893036 c
|
||||
13.583073 16.805317 14.458187 15.242372 15.372757 13.896872 c
|
||||
13.810370 12.772676 13.260306 10.794797 13.271935 9.282023 c
|
||||
13.275491 8.803411 13.960783 8.714442 14.085299 9.177669 c
|
||||
14.549135 10.905348 15.014800 11.856633 16.730038 12.322754 c
|
||||
17.129433 14.205773 17.395172 15.580981 17.659184 16.554203 c
|
||||
17.974028 17.714911 19.216745 18.364452 20.352518 17.951246 c
|
||||
20.763287 17.801796 20.978804 17.334660 20.833061 16.909876 c
|
||||
19.358932 12.613934 19.128233 10.638695 19.061661 6.794147 c
|
||||
18.995644 2.557825 13.450433 0.701872 10.373089 2.859669 c
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
1544
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Pages 5 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000001634 00000 n
|
||||
0000001657 00000 n
|
||||
0000001830 00000 n
|
||||
0000001904 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
1963
|
||||
%%EOF
|
@ -6718,6 +6718,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
switch result {
|
||||
case let .result(messageId):
|
||||
if let messageId = messageId {
|
||||
strongSelf.chatDisplayNode.historyNode.suspendReadingReactions = true
|
||||
strongSelf.navigateToMessage(from: nil, to: .id(messageId, nil), scrollPosition: .center(.top), completion: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -6743,34 +6744,28 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return
|
||||
}
|
||||
|
||||
guard let availableReactions = item.associatedData.availableReactions else {
|
||||
return
|
||||
}
|
||||
|
||||
var avatarPeers: [EnginePeer] = []
|
||||
if item.message.id.peerId.namespace != Namespaces.Peer.CloudUser, let updatedReactionPeer = updatedReactionPeer {
|
||||
avatarPeers.append(updatedReactionPeer)
|
||||
}
|
||||
|
||||
guard let availableReactions = item.associatedData.availableReactions, let targetView = itemNode.targetReactionView(value: updatedReaction) else {
|
||||
return
|
||||
}
|
||||
for reaction in availableReactions.reactions {
|
||||
guard let centerAnimation = reaction.centerAnimation else {
|
||||
continue
|
||||
}
|
||||
guard let aroundAnimation = reaction.aroundAnimation else {
|
||||
continue
|
||||
}
|
||||
|
||||
if reaction.value == updatedReaction {
|
||||
let standaloneReactionAnimation = StandaloneReactionAnimation(genericReactionEffect: strongSelf.chatDisplayNode.historyNode.takeGenericReactionEffect())
|
||||
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.addMessageStandaloneReactionAnimation(messageId: item.message.id, standaloneReactionAnimation: standaloneReactionAnimation)
|
||||
|
||||
strongSelf.chatDisplayNode.addSubnode(standaloneReactionAnimation)
|
||||
standaloneReactionAnimation.frame = strongSelf.chatDisplayNode.bounds
|
||||
standaloneReactionAnimation.animateReactionSelection(
|
||||
context: strongSelf.context,
|
||||
theme: strongSelf.presentationData.theme,
|
||||
animationCache: strongSelf.controllerInteraction!.presentationContext.animationCache,
|
||||
reaction: ReactionItem(
|
||||
var reactionItem: ReactionItem?
|
||||
|
||||
switch updatedReaction {
|
||||
case .builtin:
|
||||
for reaction in availableReactions.reactions {
|
||||
guard let centerAnimation = reaction.centerAnimation else {
|
||||
continue
|
||||
}
|
||||
guard let aroundAnimation = reaction.aroundAnimation else {
|
||||
continue
|
||||
}
|
||||
if reaction.value == updatedReaction {
|
||||
reactionItem = ReactionItem(
|
||||
reaction: ReactionItem.Reaction(rawValue: reaction.value),
|
||||
appearAnimation: reaction.appearAnimation,
|
||||
stillAnimation: reaction.selectAnimation,
|
||||
@ -6779,28 +6774,60 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
applicationAnimation: aroundAnimation,
|
||||
largeApplicationAnimation: reaction.effectAnimation,
|
||||
isCustom: false
|
||||
),
|
||||
avatarPeers: avatarPeers,
|
||||
playHaptic: true,
|
||||
isLarge: updatedReactionIsLarge,
|
||||
targetView: targetView,
|
||||
addStandaloneReactionAnimation: { standaloneReactionAnimation in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.addMessageStandaloneReactionAnimation(messageId: item.message.id, standaloneReactionAnimation: standaloneReactionAnimation)
|
||||
standaloneReactionAnimation.frame = strongSelf.chatDisplayNode.bounds
|
||||
strongSelf.chatDisplayNode.addSubnode(standaloneReactionAnimation)
|
||||
},
|
||||
completion: { [weak standaloneReactionAnimation] in
|
||||
standaloneReactionAnimation?.removeFromSupernode()
|
||||
}
|
||||
)
|
||||
break
|
||||
}
|
||||
}
|
||||
case let .custom(fileId):
|
||||
if let itemFile = item.message.associatedMedia[MediaId(namespace: Namespaces.Media.CloudFile, id: fileId)] as? TelegramMediaFile {
|
||||
reactionItem = ReactionItem(
|
||||
reaction: ReactionItem.Reaction(rawValue: updatedReaction),
|
||||
appearAnimation: itemFile,
|
||||
stillAnimation: itemFile,
|
||||
listAnimation: itemFile,
|
||||
largeListAnimation: itemFile,
|
||||
applicationAnimation: nil,
|
||||
largeApplicationAnimation: nil,
|
||||
isCustom: true
|
||||
)
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
guard let targetView = itemNode.targetReactionView(value: updatedReaction) else {
|
||||
return
|
||||
}
|
||||
if let reactionItem = reactionItem {
|
||||
let standaloneReactionAnimation = StandaloneReactionAnimation(genericReactionEffect: strongSelf.chatDisplayNode.historyNode.takeGenericReactionEffect())
|
||||
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.addMessageStandaloneReactionAnimation(messageId: item.message.id, standaloneReactionAnimation: standaloneReactionAnimation)
|
||||
|
||||
strongSelf.chatDisplayNode.addSubnode(standaloneReactionAnimation)
|
||||
standaloneReactionAnimation.frame = strongSelf.chatDisplayNode.bounds
|
||||
standaloneReactionAnimation.animateReactionSelection(
|
||||
context: strongSelf.context,
|
||||
theme: strongSelf.presentationData.theme,
|
||||
animationCache: strongSelf.controllerInteraction!.presentationContext.animationCache,
|
||||
reaction: reactionItem,
|
||||
avatarPeers: avatarPeers,
|
||||
playHaptic: true,
|
||||
isLarge: updatedReactionIsLarge,
|
||||
targetView: targetView,
|
||||
addStandaloneReactionAnimation: { standaloneReactionAnimation in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.addMessageStandaloneReactionAnimation(messageId: item.message.id, standaloneReactionAnimation: standaloneReactionAnimation)
|
||||
standaloneReactionAnimation.frame = strongSelf.chatDisplayNode.bounds
|
||||
strongSelf.chatDisplayNode.addSubnode(standaloneReactionAnimation)
|
||||
},
|
||||
completion: { [weak standaloneReactionAnimation] in
|
||||
standaloneReactionAnimation?.removeFromSupernode()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
strongSelf.chatDisplayNode.historyNode.suspendReadingReactions = false
|
||||
})
|
||||
}
|
||||
case .loading:
|
||||
@ -17031,6 +17058,10 @@ enum AllowedReactions {
|
||||
}
|
||||
|
||||
func peerMessageAllowedReactions(context: AccountContext, message: Message) -> Signal<AllowedReactions?, NoError> {
|
||||
if message.containsSecretMedia {
|
||||
return .single(AllowedReactions.set(Set()))
|
||||
}
|
||||
|
||||
return combineLatest(
|
||||
context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: message.id.peerId),
|
||||
@ -17045,20 +17076,26 @@ func peerMessageAllowedReactions(context: AccountContext, message: Message) -> S
|
||||
return .set(Set(effectiveReactions.map(\.value)))
|
||||
}
|
||||
|
||||
if case let .channel(channel) = peer, case .broadcast = channel.info {
|
||||
if let availableReactions = availableReactions {
|
||||
return .set(Set(availableReactions.reactions.map(\.value)))
|
||||
} else {
|
||||
return .set(Set())
|
||||
}
|
||||
}
|
||||
|
||||
switch allowedReactions {
|
||||
case .unknown:
|
||||
if case let .channel(channel) = peer, case .broadcast = channel.info {
|
||||
if let availableReactions = availableReactions {
|
||||
return .set(Set(availableReactions.reactions.map(\.value)))
|
||||
} else {
|
||||
return .set(Set())
|
||||
}
|
||||
}
|
||||
return .all
|
||||
case let .known(value):
|
||||
switch value {
|
||||
case .all:
|
||||
if case let .channel(channel) = peer, case .broadcast = channel.info {
|
||||
if let availableReactions = availableReactions {
|
||||
return .set(Set(availableReactions.reactions.map(\.value)))
|
||||
} else {
|
||||
return .set(Set())
|
||||
}
|
||||
}
|
||||
return .all
|
||||
case let .limited(reactions):
|
||||
return .set(Set(reactions))
|
||||
|
@ -1105,6 +1105,7 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
peekBehavior: nil,
|
||||
customLayout: nil,
|
||||
externalBackground: nil,
|
||||
externalExpansionView: nil,
|
||||
useOpaqueTheme: false
|
||||
)
|
||||
|
||||
@ -1310,6 +1311,7 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
peekBehavior: stickerPeekBehavior,
|
||||
customLayout: nil,
|
||||
externalBackground: nil,
|
||||
externalExpansionView: nil,
|
||||
useOpaqueTheme: false
|
||||
)
|
||||
|
||||
@ -2020,6 +2022,7 @@ final class EntityInputView: UIView, AttachmentTextInputPanelInputView, UIInputV
|
||||
peekBehavior: nil,
|
||||
customLayout: nil,
|
||||
externalBackground: nil,
|
||||
externalExpansionView: nil,
|
||||
useOpaqueTheme: false
|
||||
)
|
||||
|
||||
|
@ -451,6 +451,16 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
let canReadHistory = Promise<Bool>()
|
||||
private var canReadHistoryValue: Bool = false
|
||||
private var canReadHistoryDisposable: Disposable?
|
||||
|
||||
var suspendReadingReactions: Bool = false {
|
||||
didSet {
|
||||
if self.suspendReadingReactions != oldValue {
|
||||
if !self.suspendReadingReactions {
|
||||
self.attemptReadingReactions()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var messageIdsScheduledForMarkAsSeen = Set<MessageId>()
|
||||
private var messageIdsWithReactionsScheduledForMarkAsSeen = Set<MessageId>()
|
||||
@ -728,7 +738,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if strongSelf.canReadHistoryValue && !strongSelf.context.sharedContext.immediateExperimentalUISettings.skipReadHistory {
|
||||
if strongSelf.canReadHistoryValue && !strongSelf.suspendReadingReactions && !strongSelf.context.sharedContext.immediateExperimentalUISettings.skipReadHistory {
|
||||
strongSelf.context.account.viewTracker.updateMarkReactionsSeenForMessageIds(messageIds: messageIds)
|
||||
} else {
|
||||
strongSelf.messageIdsWithReactionsScheduledForMarkAsSeen.formUnion(messageIds)
|
||||
@ -1365,20 +1375,13 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
strongSelf.canReadHistoryValue = value
|
||||
strongSelf.updateReadHistoryActions()
|
||||
|
||||
if strongSelf.canReadHistoryValue && !strongSelf.messageIdsScheduledForMarkAsSeen.isEmpty {
|
||||
if strongSelf.canReadHistoryValue && !strongSelf.suspendReadingReactions && !strongSelf.messageIdsScheduledForMarkAsSeen.isEmpty {
|
||||
let messageIds = strongSelf.messageIdsScheduledForMarkAsSeen
|
||||
strongSelf.messageIdsScheduledForMarkAsSeen.removeAll()
|
||||
context?.account.viewTracker.updateMarkMentionsSeenForMessageIds(messageIds: messageIds)
|
||||
}
|
||||
|
||||
if strongSelf.canReadHistoryValue && !strongSelf.context.sharedContext.immediateExperimentalUISettings.skipReadHistory && !strongSelf.messageIdsWithReactionsScheduledForMarkAsSeen.isEmpty {
|
||||
let messageIds = strongSelf.messageIdsWithReactionsScheduledForMarkAsSeen
|
||||
|
||||
let _ = strongSelf.displayUnseenReactionAnimations(messageIds: Array(messageIds))
|
||||
|
||||
strongSelf.messageIdsWithReactionsScheduledForMarkAsSeen.removeAll()
|
||||
context?.account.viewTracker.updateMarkReactionsSeenForMessageIds(messageIds: messageIds)
|
||||
}
|
||||
strongSelf.attemptReadingReactions()
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -1598,6 +1601,17 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
self.genericReactionEffectDisposable?.dispose()
|
||||
}
|
||||
|
||||
private func attemptReadingReactions() {
|
||||
if self.canReadHistoryValue && !self.suspendReadingReactions && !self.context.sharedContext.immediateExperimentalUISettings.skipReadHistory && !self.messageIdsWithReactionsScheduledForMarkAsSeen.isEmpty {
|
||||
let messageIds = self.messageIdsWithReactionsScheduledForMarkAsSeen
|
||||
|
||||
let _ = self.displayUnseenReactionAnimations(messageIds: Array(messageIds))
|
||||
|
||||
self.messageIdsWithReactionsScheduledForMarkAsSeen.removeAll()
|
||||
self.context.account.viewTracker.updateMarkReactionsSeenForMessageIds(messageIds: messageIds)
|
||||
}
|
||||
}
|
||||
|
||||
func takeGenericReactionEffect() -> String? {
|
||||
let result = self.genericReactionEffect
|
||||
self.loadNextGenericReactionEffect(context: self.context)
|
||||
@ -2754,32 +2768,20 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
|
||||
visibleNewIncomingReactionMessageIds.append(item.content.firstMessage.id)
|
||||
|
||||
if let availableReactions = item.associatedData.availableReactions, let targetView = itemNode.targetReactionView(value: updatedReaction) {
|
||||
for reaction in availableReactions.reactions {
|
||||
guard let centerAnimation = reaction.centerAnimation else {
|
||||
continue
|
||||
}
|
||||
guard let aroundAnimation = reaction.aroundAnimation else {
|
||||
continue
|
||||
}
|
||||
|
||||
if reaction.value == updatedReaction {
|
||||
let standaloneReactionAnimation = StandaloneReactionAnimation(genericReactionEffect: self.genericReactionEffect)
|
||||
|
||||
chatDisplayNode.messageTransitionNode.addMessageStandaloneReactionAnimation(messageId: item.message.id, standaloneReactionAnimation: standaloneReactionAnimation)
|
||||
|
||||
var avatarPeers: [EnginePeer] = []
|
||||
if item.message.id.peerId.namespace != Namespaces.Peer.CloudUser, let updateReactionPeer = updateReactionPeer {
|
||||
avatarPeers = [updateReactionPeer]
|
||||
var reactionItem: ReactionItem?
|
||||
|
||||
switch updatedReaction {
|
||||
case .builtin:
|
||||
if let availableReactions = item.associatedData.availableReactions {
|
||||
for reaction in availableReactions.reactions {
|
||||
guard let centerAnimation = reaction.centerAnimation else {
|
||||
continue
|
||||
}
|
||||
|
||||
chatDisplayNode.addSubnode(standaloneReactionAnimation)
|
||||
standaloneReactionAnimation.frame = chatDisplayNode.bounds
|
||||
standaloneReactionAnimation.animateReactionSelection(
|
||||
context: self.context,
|
||||
theme: item.presentationData.theme.theme,
|
||||
animationCache: self.controllerInteraction.presentationContext.animationCache,
|
||||
reaction: ReactionItem(
|
||||
guard let aroundAnimation = reaction.aroundAnimation else {
|
||||
continue
|
||||
}
|
||||
if reaction.value == updatedReaction {
|
||||
reactionItem = ReactionItem(
|
||||
reaction: ReactionItem.Reaction(rawValue: reaction.value),
|
||||
appearAnimation: reaction.appearAnimation,
|
||||
stillAnimation: reaction.selectAnimation,
|
||||
@ -2788,25 +2790,59 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
applicationAnimation: aroundAnimation,
|
||||
largeApplicationAnimation: reaction.effectAnimation,
|
||||
isCustom: false
|
||||
),
|
||||
avatarPeers: avatarPeers,
|
||||
playHaptic: true,
|
||||
isLarge: updatedReactionIsLarge,
|
||||
targetView: targetView,
|
||||
addStandaloneReactionAnimation: { [weak self] standaloneReactionAnimation in
|
||||
guard let strongSelf = self, let chatDisplayNode = strongSelf.controllerInteraction.chatControllerNode() as? ChatControllerNode else {
|
||||
return
|
||||
}
|
||||
chatDisplayNode.messageTransitionNode.addMessageStandaloneReactionAnimation(messageId: item.message.id, standaloneReactionAnimation: standaloneReactionAnimation)
|
||||
standaloneReactionAnimation.frame = chatDisplayNode.bounds
|
||||
chatDisplayNode.addSubnode(standaloneReactionAnimation)
|
||||
},
|
||||
completion: { [weak standaloneReactionAnimation] in
|
||||
standaloneReactionAnimation?.removeFromSupernode()
|
||||
}
|
||||
)
|
||||
)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
case let .custom(fileId):
|
||||
if let itemFile = item.message.associatedMedia[MediaId(namespace: Namespaces.Media.CloudFile, id: fileId)] as? TelegramMediaFile {
|
||||
reactionItem = ReactionItem(
|
||||
reaction: ReactionItem.Reaction(rawValue: updatedReaction),
|
||||
appearAnimation: itemFile,
|
||||
stillAnimation: itemFile,
|
||||
listAnimation: itemFile,
|
||||
largeListAnimation: itemFile,
|
||||
applicationAnimation: nil,
|
||||
largeApplicationAnimation: nil,
|
||||
isCustom: true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if let reactionItem = reactionItem, let targetView = itemNode.targetReactionView(value: updatedReaction) {
|
||||
let standaloneReactionAnimation = StandaloneReactionAnimation(genericReactionEffect: self.genericReactionEffect)
|
||||
|
||||
chatDisplayNode.messageTransitionNode.addMessageStandaloneReactionAnimation(messageId: item.message.id, standaloneReactionAnimation: standaloneReactionAnimation)
|
||||
|
||||
var avatarPeers: [EnginePeer] = []
|
||||
if item.message.id.peerId.namespace != Namespaces.Peer.CloudUser, let updateReactionPeer = updateReactionPeer {
|
||||
avatarPeers = [updateReactionPeer]
|
||||
}
|
||||
|
||||
chatDisplayNode.addSubnode(standaloneReactionAnimation)
|
||||
standaloneReactionAnimation.frame = chatDisplayNode.bounds
|
||||
standaloneReactionAnimation.animateReactionSelection(
|
||||
context: self.context,
|
||||
theme: item.presentationData.theme.theme,
|
||||
animationCache: self.controllerInteraction.presentationContext.animationCache,
|
||||
reaction: reactionItem,
|
||||
avatarPeers: avatarPeers,
|
||||
playHaptic: true,
|
||||
isLarge: updatedReactionIsLarge,
|
||||
targetView: targetView,
|
||||
addStandaloneReactionAnimation: { [weak self] standaloneReactionAnimation in
|
||||
guard let strongSelf = self, let chatDisplayNode = strongSelf.controllerInteraction.chatControllerNode() as? ChatControllerNode else {
|
||||
return
|
||||
}
|
||||
chatDisplayNode.messageTransitionNode.addMessageStandaloneReactionAnimation(messageId: item.message.id, standaloneReactionAnimation: standaloneReactionAnimation)
|
||||
standaloneReactionAnimation.frame = chatDisplayNode.bounds
|
||||
chatDisplayNode.addSubnode(standaloneReactionAnimation)
|
||||
},
|
||||
completion: { [weak standaloneReactionAnimation] in
|
||||
standaloneReactionAnimation?.removeFromSupernode()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
return visibleNewIncomingReactionMessageIds
|
||||
|
@ -633,11 +633,9 @@ private func settingsItems(data: PeerInfoScreenData?, context: AccountContext, p
|
||||
if let peer = data.peer as? TelegramUser, peer.isPremium {
|
||||
if peer.emojiStatus != nil {
|
||||
hasEmojiStatus = true
|
||||
//TODO:localize
|
||||
setStatusTitle = "Change Emoji Status"
|
||||
setStatusTitle = presentationData.strings.PeerInfo_ChangeEmojiStatus
|
||||
} else {
|
||||
//TODO:localize
|
||||
setStatusTitle = "Set Emoji Status"
|
||||
setStatusTitle = presentationData.strings.PeerInfo_SetEmojiStatus
|
||||
}
|
||||
displaySetStatus = true
|
||||
} else {
|
||||
@ -1301,8 +1299,7 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
||||
if let cachedData = data.cachedData as? CachedChannelData, case let .known(allowedReactions) = cachedData.allowedReactions {
|
||||
switch allowedReactions {
|
||||
case .all:
|
||||
//TODO:localize
|
||||
label = "All Reactions"
|
||||
label = presentationData.strings.PeerInfo_LabelAllReactions
|
||||
case .empty:
|
||||
label = presentationData.strings.PeerInfo_ReactionsDisabled
|
||||
case let .limited(reactions):
|
||||
@ -1467,8 +1464,7 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
||||
if let cachedData = data.cachedData as? CachedChannelData, case let .known(allowedReactions) = cachedData.allowedReactions {
|
||||
switch allowedReactions {
|
||||
case .all:
|
||||
//TODO:localize
|
||||
label = "All Reactions"
|
||||
label = presentationData.strings.PeerInfo_LabelAllReactions
|
||||
case .empty:
|
||||
label = presentationData.strings.PeerInfo_ReactionsDisabled
|
||||
case let .limited(reactions):
|
||||
@ -1493,8 +1489,7 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
||||
if let cachedData = data.cachedData as? CachedChannelData, case let .known(allowedReactions) = cachedData.allowedReactions {
|
||||
switch allowedReactions {
|
||||
case .all:
|
||||
//TODO:localize
|
||||
label = "All Reactions"
|
||||
label = presentationData.strings.PeerInfo_LabelAllReactions
|
||||
case .empty:
|
||||
label = presentationData.strings.PeerInfo_ReactionsDisabled
|
||||
case let .limited(reactions):
|
||||
@ -1607,8 +1602,7 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
||||
if let cachedData = data.cachedData as? CachedGroupData, case let .known(allowedReactions) = cachedData.allowedReactions {
|
||||
switch allowedReactions {
|
||||
case .all:
|
||||
//TODO:localize
|
||||
label = "All Reactions"
|
||||
label = presentationData.strings.PeerInfo_LabelAllReactions
|
||||
case .empty:
|
||||
label = presentationData.strings.PeerInfo_ReactionsDisabled
|
||||
case let .limited(reactions):
|
||||
@ -3119,7 +3113,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}
|
||||
}
|
||||
}
|
||||
//TODO:localize
|
||||
|
||||
let emojiStatusSelectionController = EmojiStatusSelectionController(
|
||||
context: strongSelf.context,
|
||||
mode: .statusSelection,
|
||||
|
Loading…
x
Reference in New Issue
Block a user