mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Emoji UI improvements
This commit is contained in:
parent
52c60a3f0d
commit
b92d21f9d7
@ -252,6 +252,15 @@ public final class DefaultAnimatedStickerNodeImpl: ASDisplayNode, AnimatedSticke
|
||||
private var overlayColor: (UIColor?, Bool)? = nil
|
||||
private var size: CGSize?
|
||||
|
||||
public var dynamicColor: UIColor? {
|
||||
didSet {
|
||||
if let renderer = self.renderer?.renderer as? SoftwareAnimationRenderer {
|
||||
renderer.renderAsTemplateImage = self.dynamicColor != nil
|
||||
}
|
||||
self.renderer?.renderer.view.tintColor = self.dynamicColor
|
||||
}
|
||||
}
|
||||
|
||||
public init(useMetalCache: Bool = false) {
|
||||
self.queue = sharedQueue
|
||||
self.eventsNode = AnimatedStickerNodeDisplayEvents()
|
||||
@ -279,12 +288,12 @@ public final class DefaultAnimatedStickerNodeImpl: ASDisplayNode, AnimatedSticke
|
||||
if #available(iOS 10.0, *) {
|
||||
return CompressedAnimationRenderer()
|
||||
} else {
|
||||
return SoftwareAnimationRenderer()
|
||||
return SoftwareAnimationRenderer(templateImageSupport: true)
|
||||
}
|
||||
})
|
||||
|
||||
private static let softwareRendererPool = AnimationRendererPool(generate: {
|
||||
return SoftwareAnimationRenderer()
|
||||
return SoftwareAnimationRenderer(templateImageSupport: true)
|
||||
})
|
||||
|
||||
private weak var nodeToCopyFrameFrom: DefaultAnimatedStickerNodeImpl?
|
||||
@ -295,6 +304,12 @@ public final class DefaultAnimatedStickerNodeImpl: ASDisplayNode, AnimatedSticke
|
||||
self.renderer = DefaultAnimatedStickerNodeImpl.hardwareRendererPool.take()
|
||||
} else {
|
||||
self.renderer = DefaultAnimatedStickerNodeImpl.softwareRendererPool.take()
|
||||
|
||||
if let renderer = self.renderer?.renderer as? SoftwareAnimationRenderer {
|
||||
renderer.renderAsTemplateImage = self.dynamicColor != nil
|
||||
}
|
||||
self.renderer?.renderer.view.tintColor = self.dynamicColor
|
||||
|
||||
if let contents = self.nodeToCopyFrameFrom?.renderer?.renderer.contents {
|
||||
self.renderer?.renderer.contents = contents
|
||||
}
|
||||
|
@ -7,20 +7,30 @@ import YuvConversion
|
||||
import Accelerate
|
||||
|
||||
final class SoftwareAnimationRenderer: ASDisplayNode, AnimationRenderer {
|
||||
private let templateImageSupport: Bool
|
||||
|
||||
private var highlightedContentNode: ASDisplayNode?
|
||||
private var highlightedColor: UIColor?
|
||||
private var highlightReplacesContent = false
|
||||
public var renderAsTemplateImage: Bool = false
|
||||
|
||||
public var currentFrameImage: UIImage? {
|
||||
if let contents = self.contents {
|
||||
return UIImage(cgImage: contents as! CGImage)
|
||||
} else {
|
||||
return nil
|
||||
public private(set) var currentFrameImage: UIImage?
|
||||
|
||||
init(templateImageSupport: Bool) {
|
||||
self.templateImageSupport = templateImageSupport
|
||||
|
||||
super.init()
|
||||
|
||||
if templateImageSupport {
|
||||
self.setViewBlock({
|
||||
return UIImageView()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func render(queue: Queue, width: Int, height: Int, bytesPerRow: Int, data: Data, type: AnimationRendererFrameType, mulAlpha: Bool, completion: @escaping () -> Void) {
|
||||
assert(bytesPerRow > 0)
|
||||
let renderAsTemplateImage = self.renderAsTemplateImage
|
||||
queue.async { [weak self] in
|
||||
switch type {
|
||||
case .argb:
|
||||
@ -70,13 +80,21 @@ final class SoftwareAnimationRenderer: ASDisplayNode, AnimationRenderer {
|
||||
break
|
||||
}
|
||||
})
|
||||
if renderAsTemplateImage {
|
||||
image = image?.withRenderingMode(.alwaysTemplate)
|
||||
}
|
||||
}
|
||||
|
||||
Queue.mainQueue().async {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.contents = image?.cgImage
|
||||
strongSelf.currentFrameImage = image
|
||||
if strongSelf.templateImageSupport {
|
||||
(strongSelf.view as? UIImageView)?.image = image
|
||||
} else {
|
||||
strongSelf.contents = image?.cgImage
|
||||
}
|
||||
strongSelf.updateHighlightedContentNode()
|
||||
if strongSelf.highlightedContentNode?.frame != strongSelf.bounds {
|
||||
strongSelf.highlightedContentNode?.frame = strongSelf.bounds
|
||||
@ -90,12 +108,14 @@ final class SoftwareAnimationRenderer: ASDisplayNode, AnimationRenderer {
|
||||
guard let highlightedContentNode = self.highlightedContentNode, let highlightedColor = self.highlightedColor else {
|
||||
return
|
||||
}
|
||||
if let contents = self.contents, CFGetTypeID(contents as CFTypeRef) == CGImage.typeID {
|
||||
(highlightedContentNode.view as! UIImageView).image = UIImage(cgImage: contents as! CGImage).withRenderingMode(.alwaysTemplate)
|
||||
}
|
||||
(highlightedContentNode.view as! UIImageView).image = self.currentFrameImage?.withRenderingMode(.alwaysTemplate)
|
||||
highlightedContentNode.tintColor = highlightedColor
|
||||
if self.highlightReplacesContent {
|
||||
self.contents = nil
|
||||
if self.templateImageSupport {
|
||||
(self.view as? UIImageView)?.image = nil
|
||||
} else {
|
||||
self.contents = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,21 +136,30 @@ public struct Transition {
|
||||
//view.layer.position = CGPoint(x: frame.midX, y: frame.midY)
|
||||
view.layer.removeAnimation(forKey: "position")
|
||||
view.layer.removeAnimation(forKey: "bounds")
|
||||
view.layer.removeAnimation(forKey: "bounds.size")
|
||||
completion?(true)
|
||||
case .curve:
|
||||
let previousFrame: CGRect
|
||||
if (view.layer.animation(forKey: "position") != nil || view.layer.animation(forKey: "bounds") != nil), let presentation = view.layer.presentation() {
|
||||
previousFrame = presentation.frame
|
||||
let previousPosition: CGPoint
|
||||
let previousBounds: CGRect
|
||||
if (view.layer.animation(forKey: "position") != nil || view.layer.animation(forKey: "bounds") != nil || view.layer.animation(forKey: "bounds.size") != nil), let presentation = view.layer.presentation() {
|
||||
previousPosition = presentation.position
|
||||
previousBounds = presentation.bounds
|
||||
} else {
|
||||
previousFrame = view.frame
|
||||
previousPosition = view.layer.position
|
||||
previousBounds = view.layer.bounds
|
||||
}
|
||||
|
||||
view.frame = frame
|
||||
//view.bounds = CGRect(origin: previousBounds.origin, size: frame.size)
|
||||
//view.center = CGPoint(x: frame.midX, y: frame.midY)
|
||||
|
||||
let anchorPoint = view.layer.anchorPoint
|
||||
let updatedPosition = CGPoint(x: frame.minX + frame.width * anchorPoint.x, y: frame.minY + frame.height * anchorPoint.y)
|
||||
|
||||
self.animatePosition(view: view, from: CGPoint(x: previousFrame.midX, y: previousFrame.midY), to: CGPoint(x: frame.midX, y: frame.midY), completion: completion)
|
||||
self.animateBoundsSize(view: view, from: previousFrame.size, to: frame.size)
|
||||
self.animatePosition(view: view, from: previousPosition, to: updatedPosition, completion: completion)
|
||||
if previousBounds.size != frame.size {
|
||||
self.animateBoundsSize(view: view, from: previousBounds.size, to: frame.size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -193,10 +202,12 @@ public struct Transition {
|
||||
case .none:
|
||||
view.bounds = bounds
|
||||
view.layer.removeAnimation(forKey: "bounds")
|
||||
view.layer.removeAnimation(forKey: "bounds.origin")
|
||||
view.layer.removeAnimation(forKey: "bounds.size")
|
||||
completion?(true)
|
||||
case .curve:
|
||||
let previousBounds: CGRect
|
||||
if view.layer.animation(forKey: "bounds") != nil, let presentation = view.layer.presentation() {
|
||||
if (view.layer.animation(forKey: "bounds") != nil || view.layer.animation(forKey: "bounds.origin") != nil || view.layer.animation(forKey: "bounds.size") != nil), let presentation = view.layer.presentation() {
|
||||
previousBounds = presentation.bounds
|
||||
} else {
|
||||
previousBounds = view.layer.bounds
|
||||
@ -207,6 +218,30 @@ public struct Transition {
|
||||
}
|
||||
}
|
||||
|
||||
public func setBoundsOrigin(view: UIView, origin: CGPoint, completion: ((Bool) -> Void)? = nil) {
|
||||
if view.bounds.origin == origin {
|
||||
completion?(true)
|
||||
return
|
||||
}
|
||||
switch self.animation {
|
||||
case .none:
|
||||
view.bounds = CGRect(origin: origin, size: view.bounds.size)
|
||||
view.layer.removeAnimation(forKey: "bounds")
|
||||
view.layer.removeAnimation(forKey: "bounds.origin")
|
||||
completion?(true)
|
||||
case .curve:
|
||||
let previousOrigin: CGPoint
|
||||
if (view.layer.animation(forKey: "bounds") != nil || view.layer.animation(forKey: "bounds.origin") != nil), let presentation = view.layer.presentation() {
|
||||
previousOrigin = presentation.bounds.origin
|
||||
} else {
|
||||
previousOrigin = view.layer.bounds.origin
|
||||
}
|
||||
view.bounds = CGRect(origin: origin, size: view.bounds.size)
|
||||
|
||||
self.animateBoundsOrigin(view: view, from: previousOrigin, to: origin, completion: completion)
|
||||
}
|
||||
}
|
||||
|
||||
public func setBoundsSize(view: UIView, size: CGSize, completion: ((Bool) -> Void)? = nil) {
|
||||
if view.bounds.size == size {
|
||||
completion?(true)
|
||||
|
@ -395,6 +395,12 @@ public final class NavigationButtonNode: ContextControllerSourceNode {
|
||||
}
|
||||
}
|
||||
|
||||
public func updateManualAlpha(alpha: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
for node in self.nodes {
|
||||
transition.updateAlpha(node: node, alpha: alpha)
|
||||
}
|
||||
}
|
||||
|
||||
func updateManualText(_ text: String, isBack: Bool = true) {
|
||||
let node: NavigationButtonItemNode
|
||||
if self.nodes.count > 0 {
|
||||
|
@ -552,7 +552,7 @@ private final class FeaturedStickersScreenNode: ViewControllerTracingNode {
|
||||
}
|
||||
}))
|
||||
]
|
||||
return (itemNode.view, itemNode.bounds, StickerPreviewPeekContent(account: strongSelf.context.account, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, item: item, menu: menuItems, openPremiumIntro: { [weak self] in
|
||||
return (itemNode.view, itemNode.bounds, StickerPreviewPeekContent(context: strongSelf.context, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, item: item, menu: menuItems, openPremiumIntro: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
@ -640,7 +640,7 @@ private final class FeaturedStickersScreenNode: ViewControllerTracingNode {
|
||||
}
|
||||
}))
|
||||
]
|
||||
return (itemNode.view, itemNode.bounds, StickerPreviewPeekContent(account: strongSelf.context.account, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, item: .pack(item.file), menu: menuItems, openPremiumIntro: { [weak self] in
|
||||
return (itemNode.view, itemNode.bounds, StickerPreviewPeekContent(context: strongSelf.context, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, item: .pack(item.file), menu: menuItems, openPremiumIntro: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
@ -259,7 +259,7 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
|
||||
}
|
||||
})))
|
||||
}
|
||||
return .single((itemNode.view, itemNode.bounds, StickerPreviewPeekContent(account: strongSelf.context.account, item: item, menu: menuItems)))
|
||||
return .single((itemNode.view, itemNode.bounds, StickerPreviewPeekContent(context: strongSelf.context, item: item, menu: menuItems)))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -9,14 +9,15 @@ import StickerResources
|
||||
import AnimatedStickerNode
|
||||
import TelegramAnimatedStickerNode
|
||||
import ContextUI
|
||||
import AccountContext
|
||||
|
||||
final class StickerPreviewPeekContent: PeekControllerContent {
|
||||
let account: Account
|
||||
let context: AccountContext
|
||||
let item: ImportStickerPack.Sticker
|
||||
let menu: [ContextMenuItem]
|
||||
|
||||
init(account: Account, item: ImportStickerPack.Sticker, menu: [ContextMenuItem]) {
|
||||
self.account = account
|
||||
init(context: AccountContext, item: ImportStickerPack.Sticker, menu: [ContextMenuItem]) {
|
||||
self.context = context
|
||||
self.item = item
|
||||
self.menu = menu
|
||||
}
|
||||
@ -34,7 +35,7 @@ final class StickerPreviewPeekContent: PeekControllerContent {
|
||||
}
|
||||
|
||||
func node() -> PeekControllerContentNode & ASDisplayNode {
|
||||
return StickerPreviewPeekContentNode(account: self.account, item: self.item)
|
||||
return StickerPreviewPeekContentNode(account: self.context.account, item: self.item)
|
||||
}
|
||||
|
||||
func topAccessoryNode() -> ASDisplayNode? {
|
||||
|
@ -169,6 +169,7 @@ private final class SubItemNode: HighlightTrackingButtonNode {
|
||||
}
|
||||
} else {
|
||||
checkNode = CheckNode(theme: CheckNodeTheme(theme: presentationData.theme, style: .plain))
|
||||
checkNode.isUserInteractionEnabled = false
|
||||
self.checkNode = checkNode
|
||||
self.addSubnode(checkNode)
|
||||
}
|
||||
|
@ -460,7 +460,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
} else {
|
||||
strongSelf.stableEmptyResultEmoji = nil
|
||||
}
|
||||
emojiContent = emojiContent.withUpdatedItemGroups(panelItemGroups: emojiContent.panelItemGroups, contentItemGroups: emojiSearchResult.groups, itemContentUniqueId: emojiSearchResult.id, emptySearchResults: emptySearchResults)
|
||||
emojiContent = emojiContent.withUpdatedItemGroups(panelItemGroups: emojiContent.panelItemGroups, contentItemGroups: emojiSearchResult.groups, itemContentUniqueId: emojiSearchResult.id, emptySearchResults: emptySearchResults, searchState: .active)
|
||||
} else {
|
||||
strongSelf.stableEmptyResultEmoji = nil
|
||||
}
|
||||
|
@ -12,14 +12,22 @@ import AccountContext
|
||||
|
||||
public func autodownloadDataSizeString(_ size: Int64, decimalSeparator: String = ".") -> String {
|
||||
if size >= 1024 * 1024 * 1024 {
|
||||
let remainder = (size % (1024 * 1024 * 1024)) / (1024 * 1024 * 102)
|
||||
var remainder = (size % (1024 * 1024 * 1024)) / (1024 * 1024 * 102)
|
||||
while remainder != 0 && remainder % 10 == 0 {
|
||||
remainder /= 10
|
||||
}
|
||||
|
||||
if remainder != 0 {
|
||||
return "\(size / (1024 * 1024 * 1024))\(decimalSeparator)\(remainder) GB"
|
||||
} else {
|
||||
return "\(size / (1024 * 1024 * 1024)) GB"
|
||||
}
|
||||
} else if size >= 1024 * 1024 {
|
||||
let remainder = (size % (1024 * 1024)) / (1024 * 102)
|
||||
var remainder = (size % (1024 * 1024)) / (1024 * 102)
|
||||
while remainder != 0 && remainder % 10 == 0 {
|
||||
remainder /= 10
|
||||
}
|
||||
|
||||
if size < 10 * 1024 * 1024 {
|
||||
return "\(size / (1024 * 1024))\(decimalSeparator)\(remainder) MB"
|
||||
} else {
|
||||
|
@ -239,7 +239,7 @@ final class StickerPackPreviewControllerNode: ViewControllerTracingNode, UIScrol
|
||||
}
|
||||
})))
|
||||
}
|
||||
return (itemNode.view, itemNode.bounds, StickerPreviewPeekContent(account: strongSelf.context.account, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, item: .pack(item.file), isLocked: item.file.isPremiumSticker && !hasPremium, menu: menuItems, openPremiumIntro: {
|
||||
return (itemNode.view, itemNode.bounds, StickerPreviewPeekContent(context: strongSelf.context, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, item: .pack(item.file), isLocked: item.file.isPremiumSticker && !hasPremium, menu: menuItems, openPremiumIntro: {
|
||||
|
||||
}))
|
||||
} else {
|
||||
|
@ -481,7 +481,7 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
}
|
||||
})))
|
||||
}
|
||||
return (itemNode.view, itemNode.bounds, StickerPreviewPeekContent(account: strongSelf.context.account, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, item: .pack(item.file), isLocked: item.file.isPremiumSticker && !hasPremium, menu: menuItems, openPremiumIntro: { [weak self] in
|
||||
return (itemNode.view, itemNode.bounds, StickerPreviewPeekContent(context: strongSelf.context, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, item: .pack(item.file), isLocked: item.file.isPremiumSticker && !hasPremium, menu: menuItems, openPremiumIntro: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ public enum StickerPreviewPeekItem: Equatable {
|
||||
}
|
||||
|
||||
public final class StickerPreviewPeekContent: PeekControllerContent {
|
||||
let account: Account
|
||||
let context: AccountContext
|
||||
let theme: PresentationTheme
|
||||
let strings: PresentationStrings
|
||||
public let item: StickerPreviewPeekItem
|
||||
@ -37,8 +37,8 @@ public final class StickerPreviewPeekContent: PeekControllerContent {
|
||||
let menu: [ContextMenuItem]
|
||||
let openPremiumIntro: () -> Void
|
||||
|
||||
public init(account: Account, theme: PresentationTheme, strings: PresentationStrings, item: StickerPreviewPeekItem, isLocked: Bool = false, menu: [ContextMenuItem], openPremiumIntro: @escaping () -> Void) {
|
||||
self.account = account
|
||||
public init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, item: StickerPreviewPeekItem, isLocked: Bool = false, menu: [ContextMenuItem], openPremiumIntro: @escaping () -> Void) {
|
||||
self.context = context
|
||||
self.theme = theme
|
||||
self.strings = strings
|
||||
self.item = item
|
||||
@ -64,7 +64,7 @@ public final class StickerPreviewPeekContent: PeekControllerContent {
|
||||
}
|
||||
|
||||
public func node() -> PeekControllerContentNode & ASDisplayNode {
|
||||
return StickerPreviewPeekContentNode(account: self.account, item: self.item)
|
||||
return StickerPreviewPeekContentNode(context: self.context, item: self.item, theme: self.theme)
|
||||
}
|
||||
|
||||
public func topAccessoryNode() -> ASDisplayNode? {
|
||||
@ -91,7 +91,7 @@ public final class StickerPreviewPeekContent: PeekControllerContent {
|
||||
}
|
||||
|
||||
public final class StickerPreviewPeekContentNode: ASDisplayNode, PeekControllerContentNode {
|
||||
private let account: Account
|
||||
private let context: AccountContext
|
||||
private let item: StickerPreviewPeekItem
|
||||
|
||||
private var textNode: ASTextNode
|
||||
@ -105,8 +105,8 @@ public final class StickerPreviewPeekContentNode: ASDisplayNode, PeekControllerC
|
||||
|
||||
private let _ready = Promise<Bool>()
|
||||
|
||||
init(account: Account, item: StickerPreviewPeekItem) {
|
||||
self.account = account
|
||||
init(context: AccountContext, item: StickerPreviewPeekItem, theme: PresentationTheme) {
|
||||
self.context = context
|
||||
self.item = item
|
||||
|
||||
self.textNode = ASTextNode()
|
||||
@ -133,14 +133,18 @@ public final class StickerPreviewPeekContentNode: ASDisplayNode, PeekControllerC
|
||||
}
|
||||
let fittedDimensions = dimensions.cgSize.aspectFitted(fitSize)
|
||||
|
||||
animationNode.setup(source: AnimatedStickerResourceSource(account: account, resource: item.file.resource, isVideo: item.file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: isPremiumSticker ? .once : .loop, mode: .direct(cachePathPrefix: nil))
|
||||
if item.file.isCustomTemplateEmoji {
|
||||
animationNode.dynamicColor = theme.list.itemPrimaryTextColor
|
||||
}
|
||||
|
||||
animationNode.setup(source: AnimatedStickerResourceSource(account: context.account, resource: item.file.resource, isVideo: item.file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: isPremiumSticker ? .once : .loop, mode: .direct(cachePathPrefix: nil))
|
||||
animationNode.visibility = true
|
||||
animationNode.addSubnode(self.textNode)
|
||||
|
||||
if isPremiumSticker, let effect = item.file.videoThumbnails.first {
|
||||
self.effectDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, userLocation: .other, fileReference: .standalone(media: item.file), resource: effect.resource).start())
|
||||
self.effectDisposable.set(freeMediaFileResourceInteractiveFetched(account: context.account, userLocation: .other, fileReference: .standalone(media: item.file), resource: effect.resource).start())
|
||||
|
||||
let source = AnimatedStickerResourceSource(account: account, resource: effect.resource, fitzModifier: nil)
|
||||
let source = AnimatedStickerResourceSource(account: context.account, resource: effect.resource, fitzModifier: nil)
|
||||
let additionalAnimationNode = DefaultAnimatedStickerNodeImpl()
|
||||
additionalAnimationNode.setup(source: source, width: Int(fittedDimensions.width * 2.0), height: Int(fittedDimensions.height * 2.0), playbackMode: .once, mode: .direct(cachePathPrefix: nil))
|
||||
additionalAnimationNode.visibility = true
|
||||
@ -151,7 +155,7 @@ public final class StickerPreviewPeekContentNode: ASDisplayNode, PeekControllerC
|
||||
self.animationNode = nil
|
||||
}
|
||||
|
||||
self.imageNode.setSignal(chatMessageSticker(account: account, userLocation: .other, file: item.file, small: false, fetched: true))
|
||||
self.imageNode.setSignal(chatMessageSticker(account: context.account, userLocation: .other, file: item.file, small: false, fetched: true))
|
||||
|
||||
super.init()
|
||||
|
||||
|
@ -633,6 +633,9 @@ public final class TelegramMediaFile: Media, Equatable, Codable {
|
||||
if case .Sticker = attribute {
|
||||
hasSticker = true
|
||||
break
|
||||
} else if case .CustomEmoji = attribute {
|
||||
hasSticker = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return hasSticker
|
||||
|
@ -850,9 +850,9 @@ final class AvatarEditorScreenComponent: Component {
|
||||
}
|
||||
|
||||
if state?.keyboardContentId == AnyHashable("emoji") {
|
||||
data.emoji = data.emoji.withUpdatedItemGroups(panelItemGroups: data.emoji.panelItemGroups, contentItemGroups: searchResult.groups, itemContentUniqueId: searchResult.id, emptySearchResults: emptySearchResults)
|
||||
data.emoji = data.emoji.withUpdatedItemGroups(panelItemGroups: data.emoji.panelItemGroups, contentItemGroups: searchResult.groups, itemContentUniqueId: searchResult.id, emptySearchResults: emptySearchResults, searchState: .active)
|
||||
} else {
|
||||
data.stickers = data.stickers?.withUpdatedItemGroups(panelItemGroups: data.stickers?.panelItemGroups ?? searchResult.groups, contentItemGroups: searchResult.groups, itemContentUniqueId: searchResult.id, emptySearchResults: emptySearchResults)
|
||||
data.stickers = data.stickers?.withUpdatedItemGroups(panelItemGroups: data.stickers?.panelItemGroups ?? searchResult.groups, contentItemGroups: searchResult.groups, itemContentUniqueId: searchResult.id, emptySearchResults: emptySearchResults, searchState: .active)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -608,7 +608,11 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
strongSelf.currentUndoOverlayController = controller
|
||||
controllerInteraction.presentController(controller, nil)
|
||||
},
|
||||
copyEmoji: { file in
|
||||
copyEmoji: { [weak self] file in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
var text = "."
|
||||
var emojiAttribute: ChatTextInputTextCustomEmojiAttribute?
|
||||
loop: for attribute in file.attributes {
|
||||
@ -625,6 +629,20 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
|
||||
if let _ = emojiAttribute {
|
||||
storeMessageTextInPasteboard(text, entities: [MessageTextEntity(range: 0 ..< (text as NSString).length, type: .CustomEmoji(stickerPack: nil, fileId: file.fileId.id))])
|
||||
|
||||
var animateInAsReplacement = false
|
||||
if let currentUndoOverlayController = strongSelf.currentUndoOverlayController {
|
||||
currentUndoOverlayController.dismissWithCommitActionAndReplacementAnimation()
|
||||
strongSelf.currentUndoOverlayController = nil
|
||||
animateInAsReplacement = true
|
||||
}
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
//TODO:localize
|
||||
let controller = UndoOverlayController(presentationData: presentationData, content: .sticker(context: context, file: file, title: nil, text: "Emoji copied to clipboard.", undoText: nil, customAction: nil), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { _ in return false })
|
||||
strongSelf.currentUndoOverlayController = controller
|
||||
controllerInteraction.presentController(controller, nil)
|
||||
}
|
||||
},
|
||||
presentController: controllerInteraction.presentController,
|
||||
@ -1425,7 +1443,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
)
|
||||
}
|
||||
if let emoji = inputData.emoji {
|
||||
inputData.emoji = emoji.withUpdatedItemGroups(panelItemGroups: emoji.panelItemGroups, contentItemGroups: emojiSearchResult.groups, itemContentUniqueId: emojiSearchResult.id, emptySearchResults: emptySearchResults)
|
||||
inputData.emoji = emoji.withUpdatedItemGroups(panelItemGroups: emoji.panelItemGroups, contentItemGroups: emojiSearchResult.groups, itemContentUniqueId: emojiSearchResult.id, emptySearchResults: emptySearchResults, searchState: .active)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1439,7 +1457,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
)
|
||||
}
|
||||
if let stickers = inputData.stickers {
|
||||
inputData.stickers = stickers.withUpdatedItemGroups(panelItemGroups: stickers.panelItemGroups, contentItemGroups: stickerSearchResult.groups, itemContentUniqueId: stickerSearchResult.id, emptySearchResults: stickerSearchResults)
|
||||
inputData.stickers = stickers.withUpdatedItemGroups(panelItemGroups: stickers.panelItemGroups, contentItemGroups: stickerSearchResult.groups, itemContentUniqueId: stickerSearchResult.id, emptySearchResults: stickerSearchResults, searchState: .active)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1861,10 +1879,10 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
private func processInputData(inputData: InputData) -> InputData {
|
||||
return InputData(
|
||||
emoji: inputData.emoji.flatMap { emoji in
|
||||
return emoji.withUpdatedItemGroups(panelItemGroups: self.processStableItemGroupList(category: .emoji, itemGroups: emoji.panelItemGroups), contentItemGroups: self.processStableItemGroupList(category: .emoji, itemGroups: emoji.contentItemGroups), itemContentUniqueId: emoji.itemContentUniqueId, emptySearchResults: emoji.emptySearchResults)
|
||||
return emoji.withUpdatedItemGroups(panelItemGroups: self.processStableItemGroupList(category: .emoji, itemGroups: emoji.panelItemGroups), contentItemGroups: self.processStableItemGroupList(category: .emoji, itemGroups: emoji.contentItemGroups), itemContentUniqueId: emoji.itemContentUniqueId, emptySearchResults: emoji.emptySearchResults, searchState: emoji.searchState)
|
||||
},
|
||||
stickers: inputData.stickers.flatMap { stickers in
|
||||
return stickers.withUpdatedItemGroups(panelItemGroups: self.processStableItemGroupList(category: .stickers, itemGroups: stickers.panelItemGroups), contentItemGroups: self.processStableItemGroupList(category: .stickers, itemGroups: stickers.contentItemGroups), itemContentUniqueId: stickers.itemContentUniqueId, emptySearchResults: nil)
|
||||
return stickers.withUpdatedItemGroups(panelItemGroups: self.processStableItemGroupList(category: .stickers, itemGroups: stickers.panelItemGroups), contentItemGroups: self.processStableItemGroupList(category: .stickers, itemGroups: stickers.contentItemGroups), itemContentUniqueId: stickers.itemContentUniqueId, emptySearchResults: nil, searchState: stickers.searchState)
|
||||
},
|
||||
gifs: inputData.gifs,
|
||||
availableGifSearchEmojies: inputData.availableGifSearchEmojies
|
||||
@ -2503,7 +2521,7 @@ public final class EmojiContentPeekBehaviorImpl: EmojiContentPeekBehavior {
|
||||
return nil
|
||||
}
|
||||
|
||||
return (view, itemLayer.convert(itemLayer.bounds, to: view.layer), StickerPreviewPeekContent(account: context.account, theme: presentationData.theme, strings: presentationData.strings, item: .pack(file), isLocked: isLocked, menu: menuItems, openPremiumIntro: {
|
||||
return (view, itemLayer.convert(itemLayer.bounds, to: view.layer), StickerPreviewPeekContent(context: context, theme: presentationData.theme, strings: presentationData.strings, item: .pack(file), isLocked: isLocked, menu: menuItems, openPremiumIntro: {
|
||||
guard let strongSelf = self, let interaction = strongSelf.interaction else {
|
||||
return
|
||||
}
|
||||
@ -2632,7 +2650,7 @@ public final class EmojiContentPeekBehaviorImpl: EmojiContentPeekBehavior {
|
||||
return nil
|
||||
}
|
||||
|
||||
return (view, itemLayer.convert(itemLayer.bounds, to: view.layer), StickerPreviewPeekContent(account: context.account, theme: presentationData.theme, strings: presentationData.strings, item: .pack(file), isLocked: isLocked && !isStarred, menu: menuItems, openPremiumIntro: {
|
||||
return (view, itemLayer.convert(itemLayer.bounds, to: view.layer), StickerPreviewPeekContent(context: context, theme: presentationData.theme, strings: presentationData.strings, item: .pack(file), isLocked: isLocked && !isStarred, menu: menuItems, openPremiumIntro: {
|
||||
guard let strongSelf = self, let interaction = strongSelf.interaction else {
|
||||
return
|
||||
}
|
||||
|
@ -371,7 +371,7 @@ public final class EmojiStatusSelectionController: ViewController {
|
||||
} else {
|
||||
strongSelf.stableEmptyResultEmoji = nil
|
||||
}
|
||||
emojiContent = emojiContent.withUpdatedItemGroups(panelItemGroups: emojiContent.panelItemGroups, contentItemGroups: emojiSearchResult.groups, itemContentUniqueId: emojiSearchResult.id, emptySearchResults: emptySearchResults)
|
||||
emojiContent = emojiContent.withUpdatedItemGroups(panelItemGroups: emojiContent.panelItemGroups, contentItemGroups: emojiSearchResult.groups, itemContentUniqueId: emojiSearchResult.id, emptySearchResults: emptySearchResults, searchState: .active)
|
||||
} else {
|
||||
strongSelf.stableEmptyResultEmoji = nil
|
||||
}
|
||||
|
@ -1330,6 +1330,15 @@ private final class GroupEmbeddedView: UIScrollView, UIScrollViewDelegate, Pager
|
||||
self.layer.addSublayer(itemLayer)
|
||||
}
|
||||
|
||||
switch item.tintMode {
|
||||
case .accent:
|
||||
itemLayer.layerTintColor = theme.list.itemAccentColor.cgColor
|
||||
case .primary:
|
||||
itemLayer.layerTintColor = theme.list.itemPrimaryTextColor.cgColor
|
||||
case .none:
|
||||
itemLayer.layerTintColor = nil
|
||||
}
|
||||
|
||||
let itemFrame = itemLayout.frame(at: index)
|
||||
itemLayer.frame = itemFrame
|
||||
|
||||
@ -1708,17 +1717,24 @@ public final class EmojiSearchHeaderView: UIView, UITextFieldDelegate {
|
||||
if case .ended = recognizer.state {
|
||||
let location = recognizer.location(in: self)
|
||||
if self.backIconView.frame.contains(location) {
|
||||
if let placeholderContentView = self.placeholderContent.view as? EmojiSearchSearchBarComponent.View {
|
||||
placeholderContentView.clearSelection(dispatchEvent : true)
|
||||
}
|
||||
self.clearCategorySearch()
|
||||
} else {
|
||||
self.activateTextInput()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func clearCategorySearch() {
|
||||
if let placeholderContentView = self.placeholderContent.view as? EmojiSearchSearchBarComponent.View {
|
||||
placeholderContentView.clearSelection(dispatchEvent : true)
|
||||
}
|
||||
}
|
||||
|
||||
private func activateTextInput() {
|
||||
if self.textField == nil, let textFrame = self.textFrame, self.params?.canFocus == true {
|
||||
guard let params = self.params else {
|
||||
return
|
||||
}
|
||||
if self.textField == nil, let textFrame = self.textFrame, params.canFocus == true {
|
||||
let backgroundFrame = self.backgroundLayer.frame
|
||||
let textFieldFrame = CGRect(origin: CGPoint(x: textFrame.minX, y: backgroundFrame.minY), size: CGSize(width: backgroundFrame.maxX - textFrame.minX, height: backgroundFrame.height))
|
||||
|
||||
@ -1730,9 +1746,11 @@ public final class EmojiSearchHeaderView: UIView, UITextFieldDelegate {
|
||||
textField.addTarget(self, action: #selector(self.textFieldChanged(_:)), for: .editingChanged)
|
||||
}
|
||||
|
||||
self.currentPresetSearchTerm = nil
|
||||
if let placeholderContentView = self.placeholderContent.view as? EmojiSearchSearchBarComponent.View {
|
||||
placeholderContentView.clearSelection(dispatchEvent: false)
|
||||
if params.canFocus {
|
||||
self.currentPresetSearchTerm = nil
|
||||
if let placeholderContentView = self.placeholderContent.view as? EmojiSearchSearchBarComponent.View {
|
||||
placeholderContentView.clearSelection(dispatchEvent: false)
|
||||
}
|
||||
}
|
||||
|
||||
self.activated(true)
|
||||
@ -1968,9 +1986,9 @@ public final class EmojiSearchHeaderView: UIView, UITextFieldDelegate {
|
||||
self.currentPresetSearchTerm = term
|
||||
|
||||
if shouldChangeActivation {
|
||||
self.update(transition: Transition(animation: .curve(duration: 0.4, curve: .spring)))
|
||||
|
||||
if let term {
|
||||
self.update(transition: Transition(animation: .curve(duration: 0.4, curve: .spring)))
|
||||
|
||||
self.updateQuery(.category(value: term))
|
||||
self.activated(false)
|
||||
} else {
|
||||
@ -2049,6 +2067,7 @@ public final class EmojiSearchHeaderView: UIView, UITextFieldDelegate {
|
||||
cancelButtonTitleComponentView.isUserInteractionEnabled = false
|
||||
}
|
||||
transition.setFrame(view: cancelButtonTitleComponentView, frame: CGRect(origin: CGPoint(x: backgroundFrame.maxX + cancelButtonSpacing, y: floor((size.height - cancelTextSize.height) / 2.0)), size: cancelTextSize))
|
||||
transition.setAlpha(view: cancelButtonTitleComponentView, alpha: isActiveWithText ? 1.0 : 0.0)
|
||||
}
|
||||
if let cancelButtonTintTitleComponentView = self.cancelButtonTintTitle.view {
|
||||
if cancelButtonTintTitleComponentView.superview == nil {
|
||||
@ -2056,6 +2075,7 @@ public final class EmojiSearchHeaderView: UIView, UITextFieldDelegate {
|
||||
cancelButtonTintTitleComponentView.isUserInteractionEnabled = false
|
||||
}
|
||||
transition.setFrame(view: cancelButtonTintTitleComponentView, frame: CGRect(origin: CGPoint(x: backgroundFrame.maxX + cancelButtonSpacing, y: floor((size.height - cancelTextSize.height) / 2.0)), size: cancelTextSize))
|
||||
transition.setAlpha(view: cancelButtonTintTitleComponentView, alpha: isActiveWithText ? 1.0 : 0.0)
|
||||
}
|
||||
|
||||
var hasText = false
|
||||
@ -2103,9 +2123,9 @@ private final class EmptySearchResultsView: UIView {
|
||||
func update(context: AccountContext, theme: PresentationTheme, useOpaqueTheme: Bool, text: String, file: TelegramMediaFile?, size: CGSize, searchInitiallyHidden: Bool, transition: Transition) {
|
||||
let titleColor: UIColor
|
||||
if useOpaqueTheme {
|
||||
titleColor = theme.chat.inputMediaPanel.panelContentControlOpaqueOverlayColor
|
||||
titleColor = theme.chat.inputMediaPanel.panelContentOpaqueSearchOverlayColor
|
||||
} else {
|
||||
titleColor = theme.chat.inputMediaPanel.panelContentControlVibrantOverlayColor
|
||||
titleColor = theme.chat.inputMediaPanel.panelContentVibrantSearchOverlayColor
|
||||
}
|
||||
|
||||
let iconSize: CGSize
|
||||
@ -2513,6 +2533,12 @@ public final class EmojiPagerContentComponent: Component {
|
||||
case detailed
|
||||
}
|
||||
|
||||
public enum SearchState {
|
||||
case empty
|
||||
case searching
|
||||
case active
|
||||
}
|
||||
|
||||
public final class EmptySearchResults: Equatable {
|
||||
public let text: String
|
||||
public let iconFile: TelegramMediaFile?
|
||||
@ -2543,6 +2569,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
public let contentItemGroups: [ItemGroup]
|
||||
public let itemLayoutType: ItemLayoutType
|
||||
public let itemContentUniqueId: AnyHashable?
|
||||
public let searchState: SearchState
|
||||
public let warpContentsOnEdges: Bool
|
||||
public let displaySearchWithPlaceholder: String?
|
||||
public let searchCategories: EmojiSearchCategories?
|
||||
@ -2564,6 +2591,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
contentItemGroups: [ItemGroup],
|
||||
itemLayoutType: ItemLayoutType,
|
||||
itemContentUniqueId: AnyHashable?,
|
||||
searchState: SearchState,
|
||||
warpContentsOnEdges: Bool,
|
||||
displaySearchWithPlaceholder: String?,
|
||||
searchCategories: EmojiSearchCategories?,
|
||||
@ -2584,6 +2612,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
self.contentItemGroups = contentItemGroups
|
||||
self.itemLayoutType = itemLayoutType
|
||||
self.itemContentUniqueId = itemContentUniqueId
|
||||
self.searchState = searchState
|
||||
self.warpContentsOnEdges = warpContentsOnEdges
|
||||
self.displaySearchWithPlaceholder = displaySearchWithPlaceholder
|
||||
self.searchCategories = searchCategories
|
||||
@ -2595,7 +2624,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
self.selectedItems = selectedItems
|
||||
}
|
||||
|
||||
public func withUpdatedItemGroups(panelItemGroups: [ItemGroup], contentItemGroups: [ItemGroup], itemContentUniqueId: AnyHashable?, emptySearchResults: EmptySearchResults?) -> EmojiPagerContentComponent {
|
||||
public func withUpdatedItemGroups(panelItemGroups: [ItemGroup], contentItemGroups: [ItemGroup], itemContentUniqueId: AnyHashable?, emptySearchResults: EmptySearchResults?, searchState: SearchState) -> EmojiPagerContentComponent {
|
||||
return EmojiPagerContentComponent(
|
||||
id: self.id,
|
||||
context: self.context,
|
||||
@ -2607,6 +2636,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
contentItemGroups: contentItemGroups,
|
||||
itemLayoutType: self.itemLayoutType,
|
||||
itemContentUniqueId: itemContentUniqueId,
|
||||
searchState: searchState,
|
||||
warpContentsOnEdges: self.warpContentsOnEdges,
|
||||
displaySearchWithPlaceholder: self.displaySearchWithPlaceholder,
|
||||
searchCategories: self.searchCategories,
|
||||
@ -2650,6 +2680,12 @@ public final class EmojiPagerContentComponent: Component {
|
||||
if lhs.itemLayoutType != rhs.itemLayoutType {
|
||||
return false
|
||||
}
|
||||
if lhs.itemContentUniqueId != rhs.itemContentUniqueId {
|
||||
return false
|
||||
}
|
||||
if lhs.searchState != rhs.searchState {
|
||||
return false
|
||||
}
|
||||
if lhs.warpContentsOnEdges != rhs.warpContentsOnEdges {
|
||||
return false
|
||||
}
|
||||
@ -2662,6 +2698,9 @@ public final class EmojiPagerContentComponent: Component {
|
||||
if lhs.searchInitiallyHidden != rhs.searchInitiallyHidden {
|
||||
return false
|
||||
}
|
||||
if lhs.searchAlwaysActive != rhs.searchAlwaysActive {
|
||||
return false
|
||||
}
|
||||
if lhs.searchIsPlaceholderOnly != rhs.searchIsPlaceholderOnly {
|
||||
return false
|
||||
}
|
||||
@ -4313,6 +4352,12 @@ public final class EmojiPagerContentComponent: Component {
|
||||
guard let component = self.component, let pagerEnvironment = self.pagerEnvironment, let itemLayout = self.itemLayout else {
|
||||
return
|
||||
}
|
||||
|
||||
if self.isSearchActivated {
|
||||
self.visibleSearchHeader?.clearCategorySearch()
|
||||
return
|
||||
}
|
||||
|
||||
for groupIndex in 0 ..< itemLayout.itemGroupLayouts.count {
|
||||
let group = itemLayout.itemGroupLayouts[groupIndex]
|
||||
|
||||
@ -5044,7 +5089,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
scrollView.layer.removeAllAnimations()
|
||||
}
|
||||
|
||||
if self.isSearchActivated, let component = self.component, !component.searchAlwaysActive, let visibleSearchHeader = self.visibleSearchHeader, visibleSearchHeader.currentPresetSearchTerm == nil {
|
||||
if self.isSearchActivated, let component = self.component, component.searchState == .empty, !component.searchAlwaysActive, let visibleSearchHeader = self.visibleSearchHeader, visibleSearchHeader.currentPresetSearchTerm == nil {
|
||||
scrollView.isScrollEnabled = false
|
||||
DispatchQueue.main.async {
|
||||
scrollView.isScrollEnabled = true
|
||||
@ -6024,6 +6069,9 @@ public final class EmojiPagerContentComponent: Component {
|
||||
guard let strongSelf = self else {
|
||||
return nil
|
||||
}
|
||||
if !strongSelf.scrollViewClippingView.bounds.contains(strongSelf.convert(point, to: strongSelf.scrollViewClippingView)) {
|
||||
return nil
|
||||
}
|
||||
guard let item = strongSelf.item(atPoint: point), let itemLayer = strongSelf.visibleItemLayers[item.1], let file = item.0.itemFile else {
|
||||
return nil
|
||||
}
|
||||
@ -6459,12 +6507,15 @@ public final class EmojiPagerContentComponent: Component {
|
||||
|
||||
strongSelf.isSearchActivated = false
|
||||
strongSelf.pagerEnvironment?.onWantsExclusiveModeUpdated(false)
|
||||
if strongSelf.component?.searchInitiallyHidden == false {
|
||||
if !isFirstResponder {
|
||||
strongSelf.component?.inputInteractionHolder.inputInteraction?.requestUpdate(.easeInOut(duration: 0.2))
|
||||
}
|
||||
|
||||
if !isFirstResponder {
|
||||
strongSelf.component?.inputInteractionHolder.inputInteraction?.requestUpdate(
|
||||
Transition(animation: .curve(duration: 0.4, curve: .spring)))
|
||||
} else {
|
||||
strongSelf.component?.inputInteractionHolder.inputInteraction?.requestUpdate(.immediate)
|
||||
DispatchQueue.main.async {
|
||||
self?.component?.inputInteractionHolder.inputInteraction?.requestUpdate(
|
||||
Transition(animation: .curve(duration: 0.4, curve: .spring)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}, updateQuery: { [weak self] query in
|
||||
@ -6550,7 +6601,11 @@ public final class EmojiPagerContentComponent: Component {
|
||||
visibleEmptySearchResultsView = EmptySearchResultsView(frame: CGRect())
|
||||
self.visibleEmptySearchResultsView = visibleEmptySearchResultsView
|
||||
self.addSubview(visibleEmptySearchResultsView)
|
||||
self.mirrorContentClippingView?.addSubview(visibleEmptySearchResultsView.tintContainerView)
|
||||
if let mirrorContentClippingView = self.mirrorContentClippingView {
|
||||
mirrorContentClippingView.addSubview(visibleEmptySearchResultsView.tintContainerView)
|
||||
} else if let vibrancyEffectView = self.vibrancyEffectView {
|
||||
vibrancyEffectView.contentView.addSubview(visibleEmptySearchResultsView.tintContainerView)
|
||||
}
|
||||
}
|
||||
let emptySearchResultsSize = CGSize(width: availableSize.width, height: availableSize.height - itemLayout.searchInsets.top - itemLayout.searchHeight)
|
||||
visibleEmptySearchResultsView.update(
|
||||
@ -7550,6 +7605,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
contentItemGroups: allItemGroups,
|
||||
itemLayoutType: .compact,
|
||||
itemContentUniqueId: nil,
|
||||
searchState: .empty,
|
||||
warpContentsOnEdges: isReactionSelection || isStatusSelection || isProfilePhotoEmojiSelection || isGroupPhotoEmojiSelection,
|
||||
displaySearchWithPlaceholder: displaySearchWithPlaceholder,
|
||||
searchCategories: searchCategories,
|
||||
@ -8071,6 +8127,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
contentItemGroups: allItemGroups,
|
||||
itemLayoutType: .detailed,
|
||||
itemContentUniqueId: nil,
|
||||
searchState: .empty,
|
||||
warpContentsOnEdges: isProfilePhotoEmojiSelection || isGroupPhotoEmojiSelection,
|
||||
displaySearchWithPlaceholder: hasSearch ? strings.StickersSearch_SearchStickersPlaceholder : nil,
|
||||
searchCategories: searchCategories,
|
||||
|
@ -391,6 +391,7 @@ public final class EmojiSearchContent: ASDisplayNode, EntitySearchContainerNode
|
||||
contentItemGroups: self.itemGroups,
|
||||
itemLayoutType: .compact,
|
||||
itemContentUniqueId: "main",
|
||||
searchState: .empty,
|
||||
warpContentsOnEdges: false,
|
||||
displaySearchWithPlaceholder: "Search Emoji",
|
||||
searchCategories: nil,
|
||||
@ -410,7 +411,7 @@ public final class EmojiSearchContent: ASDisplayNode, EntitySearchContainerNode
|
||||
iconFile: nil
|
||||
)
|
||||
}
|
||||
emojiContent = emojiContent.withUpdatedItemGroups(panelItemGroups: emojiContent.panelItemGroups, contentItemGroups: emojiSearchResult.groups, itemContentUniqueId: emojiSearchResult.id, emptySearchResults: emptySearchResults)
|
||||
emojiContent = emojiContent.withUpdatedItemGroups(panelItemGroups: emojiContent.panelItemGroups, contentItemGroups: emojiSearchResult.groups, itemContentUniqueId: emojiSearchResult.id, emptySearchResults: emptySearchResults, searchState: .active)
|
||||
}
|
||||
|
||||
let _ = self.keyboardView.update(
|
||||
|
@ -131,9 +131,16 @@ final class EmojiSearchSearchBarComponent: Component {
|
||||
|
||||
self.textFrame = CGRect(origin: CGPoint(x: self.leftInset, y: floor((containerSize.height - textSize.height) * 0.5)), size: textSize)
|
||||
|
||||
self.itemStartX = self.textFrame.maxX + self.textSpacing
|
||||
let itemsWidth: CGFloat = self.itemSize.width * CGFloat(self.itemCount) + self.itemSpacing * CGFloat(max(0, self.itemCount - 1))
|
||||
|
||||
self.contentSize = CGSize(width: self.itemStartX + self.itemSize.width * CGFloat(self.itemCount) + self.itemSpacing * CGFloat(max(0, self.itemCount - 1)) + self.rightInset, height: containerSize.height)
|
||||
var itemStartX = self.textFrame.maxX + self.textSpacing
|
||||
if itemStartX + itemsWidth + self.rightInset < containerSize.width {
|
||||
itemStartX = containerSize.width - self.rightInset - itemsWidth
|
||||
}
|
||||
|
||||
self.itemStartX = itemStartX
|
||||
|
||||
self.contentSize = CGSize(width: self.itemStartX + itemsWidth + self.rightInset, height: containerSize.height)
|
||||
}
|
||||
|
||||
func visibleItems(for rect: CGRect) -> Range<Int>? {
|
||||
@ -310,7 +317,7 @@ final class EmojiSearchSearchBarComponent: Component {
|
||||
}
|
||||
} else {
|
||||
let transition = Transition(animation: .curve(duration: 0.4, curve: .spring))
|
||||
transition.setBounds(view: self.scrollView, bounds: CGRect(origin: CGPoint(), size: self.scrollView.bounds.size))
|
||||
transition.setBoundsOrigin(view: self.scrollView, origin: CGPoint())
|
||||
self.updateScrolling(transition: transition, fromScrolling: false)
|
||||
//self.scrollView.setContentOffset(CGPoint(), animated: true)
|
||||
|
||||
@ -329,7 +336,7 @@ final class EmojiSearchSearchBarComponent: Component {
|
||||
self.selectedItem = nil
|
||||
|
||||
let transition = Transition(animation: .curve(duration: 0.4, curve: .spring))
|
||||
transition.setBounds(view: self.scrollView, bounds: CGRect(origin: CGPoint(), size: self.scrollView.bounds.size))
|
||||
transition.setBoundsOrigin(view: self.scrollView, origin: CGPoint())
|
||||
self.updateScrolling(transition: transition, fromScrolling: false)
|
||||
|
||||
self.state?.updated(transition: transition)
|
||||
@ -544,7 +551,7 @@ final class EmojiSearchSearchBarComponent: Component {
|
||||
transition.setFrame(view: self.scrollView, frame: CGRect(origin: CGPoint(), size: availableSize))
|
||||
}
|
||||
if case .active = component.textInputState {
|
||||
transition.setBounds(view: self.scrollView, bounds: CGRect(origin: CGPoint(), size: availableSize))
|
||||
transition.setBoundsOrigin(view: self.scrollView, origin: CGPoint())
|
||||
}
|
||||
if self.scrollView.contentSize != itemLayout.contentSize {
|
||||
self.scrollView.contentSize = itemLayout.contentSize
|
||||
|
@ -98,7 +98,15 @@ private class GifVideoLayer: AVSampleBufferDisplayLayer {
|
||||
}
|
||||
|
||||
override init(layer: Any) {
|
||||
preconditionFailure()
|
||||
guard let layer = layer as? GifVideoLayer else {
|
||||
preconditionFailure()
|
||||
}
|
||||
|
||||
self.context = layer.context
|
||||
self.userLocation = layer.userLocation
|
||||
self.file = layer.file
|
||||
|
||||
super.init(layer: layer)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
@ -375,6 +383,13 @@ public final class GifPagerContentComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
override init(layer: Any) {
|
||||
self.item = nil
|
||||
self.onUpdateDisplayPlaceholder = { _, _ in }
|
||||
|
||||
super.init(layer: layer)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ public final class LottieComponent: Component {
|
||||
|
||||
if delay != 0.0 {
|
||||
self.isHidden = true
|
||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.08, execute: { [weak self] in
|
||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delay, execute: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
@ -43,13 +43,13 @@ final class DataCategoriesComponent: Component {
|
||||
let theme: PresentationTheme
|
||||
let strings: PresentationStrings
|
||||
let categories: [CategoryData]
|
||||
let toggleCategoryExpanded: (DataUsageScreenComponent.Category) -> Void
|
||||
let toggleCategoryExpanded: ((DataUsageScreenComponent.Category) -> Void)?
|
||||
|
||||
init(
|
||||
theme: PresentationTheme,
|
||||
strings: PresentationStrings,
|
||||
categories: [CategoryData],
|
||||
toggleCategoryExpanded: @escaping (DataUsageScreenComponent.Category) -> Void
|
||||
toggleCategoryExpanded: ((DataUsageScreenComponent.Category) -> Void)?
|
||||
) {
|
||||
self.theme = theme
|
||||
self.strings = strings
|
||||
@ -138,11 +138,11 @@ final class DataCategoriesComponent: Component {
|
||||
category: category,
|
||||
isExpanded: category.isExpanded,
|
||||
hasNext: i != component.categories.count - 1,
|
||||
action: { [weak self] key in
|
||||
action: component.toggleCategoryExpanded == nil ? nil : { [weak self] key in
|
||||
guard let self, let component = self.component else {
|
||||
return
|
||||
}
|
||||
component.toggleCategoryExpanded(key)
|
||||
component.toggleCategoryExpanded?(key)
|
||||
}
|
||||
)),
|
||||
environment: {},
|
||||
|
@ -52,7 +52,7 @@ private final class SubItemComponent: Component {
|
||||
return true
|
||||
}
|
||||
|
||||
class View: HighlightTrackingButton {
|
||||
class View: UIView {
|
||||
private let iconView: UIImageView
|
||||
private let title = ComponentView<Empty>()
|
||||
private let titleValue = ComponentView<Empty>()
|
||||
@ -74,7 +74,7 @@ private final class SubItemComponent: Component {
|
||||
|
||||
self.addSubview(self.iconView)
|
||||
|
||||
self.highligthedChanged = { [weak self] isHighlighted in
|
||||
/*self.highligthedChanged = { [weak self] isHighlighted in
|
||||
guard let self, let component = self.component, let highlightBackgroundFrame = self.highlightBackgroundFrame else {
|
||||
return
|
||||
}
|
||||
@ -103,7 +103,7 @@ private final class SubItemComponent: Component {
|
||||
}
|
||||
}
|
||||
self.addTarget(self, action: #selector(self.pressed), for: .touchUpInside)
|
||||
self.isUserInteractionEnabled = false
|
||||
self.isEnabled = false*/
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
@ -243,7 +243,7 @@ final class DataCategoryItemComponent: Component {
|
||||
let category: DataCategoriesComponent.CategoryData
|
||||
let isExpanded: Bool
|
||||
let hasNext: Bool
|
||||
let action: (DataUsageScreenComponent.Category) -> Void
|
||||
let action: ((DataUsageScreenComponent.Category) -> Void)?
|
||||
|
||||
init(
|
||||
theme: PresentationTheme,
|
||||
@ -251,7 +251,7 @@ final class DataCategoryItemComponent: Component {
|
||||
category: DataCategoriesComponent.CategoryData,
|
||||
isExpanded: Bool,
|
||||
hasNext: Bool,
|
||||
action: @escaping (DataUsageScreenComponent.Category) -> Void
|
||||
action: ((DataUsageScreenComponent.Category) -> Void)?
|
||||
) {
|
||||
self.theme = theme
|
||||
self.strings = strings
|
||||
@ -350,14 +350,14 @@ final class DataCategoryItemComponent: Component {
|
||||
guard let component = self.component else {
|
||||
return
|
||||
}
|
||||
component.action(component.category.key)
|
||||
component.action?(component.category.key)
|
||||
}
|
||||
|
||||
@objc private func checkPressed() {
|
||||
guard let component = self.component else {
|
||||
return
|
||||
}
|
||||
component.action(component.category.key)
|
||||
component.action?(component.category.key)
|
||||
}
|
||||
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
@ -597,6 +597,8 @@ final class DataCategoryItemComponent: Component {
|
||||
|
||||
transition.setFrame(view: self.subcategoryClippingContainer, frame: CGRect(origin: CGPoint(), size: CGSize(width: availableSize.width, height: height)))
|
||||
|
||||
self.isEnabled = component.action != nil
|
||||
|
||||
return CGSize(width: availableSize.width, height: height)
|
||||
}
|
||||
}
|
||||
|
@ -468,7 +468,9 @@ final class DataUsageScreenComponent: Component {
|
||||
transition.setBounds(view: self.headerOffsetContainer, bounds: CGRect(origin: CGPoint(x: 0.0, y: headerOffset), size: self.headerOffsetContainer.bounds.size))
|
||||
|
||||
if let controller = self.controller?(), let backButtonNode = controller.navigationBar?.backButtonNode {
|
||||
if backButtonNode.alpha != navigationButtonAlpha {
|
||||
backButtonNode.updateManualAlpha(alpha: navigationButtonAlpha, transition: animatedTransition.containedViewLayoutTransition)
|
||||
|
||||
/*if backButtonNode.alpha != navigationButtonAlpha {
|
||||
if backButtonNode.isHidden {
|
||||
backButtonNode.alpha = 0.0
|
||||
backButtonNode.isHidden = false
|
||||
@ -480,7 +482,7 @@ final class DataUsageScreenComponent: Component {
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1035,8 +1037,7 @@ final class DataUsageScreenComponent: Component {
|
||||
theme: environment.theme,
|
||||
strings: environment.strings,
|
||||
categories: totalCategories,
|
||||
toggleCategoryExpanded: { _ in
|
||||
}
|
||||
toggleCategoryExpanded: nil
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: .greatestFiniteMagnitude)
|
||||
|
@ -522,7 +522,7 @@ final class PieChartComponent: Component {
|
||||
|
||||
let fractionValue: Double = floor(displayValue * 100.0 * 10.0) / 10.0
|
||||
let fractionString: String
|
||||
if fractionValue == 0.0 {
|
||||
if displayValue == 0.0 {
|
||||
fractionString = ""
|
||||
} else if fractionValue < 0.1 {
|
||||
fractionString = "<0.1%"
|
||||
|
@ -1662,7 +1662,7 @@ final class ChatMediaInputNode: ChatInputNode {
|
||||
}
|
||||
}
|
||||
})))
|
||||
return (itemNode.view, itemNode.bounds, StickerPreviewPeekContent(account: strongSelf.context.account, theme: strongSelf.theme, strings: strongSelf.strings, item: item, menu: menuItems, openPremiumIntro: { [weak self] in
|
||||
return (itemNode.view, itemNode.bounds, StickerPreviewPeekContent(context: strongSelf.context, theme: strongSelf.theme, strings: strongSelf.strings, item: item, menu: menuItems, openPremiumIntro: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
@ -1819,7 +1819,7 @@ final class ChatMediaInputNode: ChatInputNode {
|
||||
}
|
||||
}))
|
||||
)
|
||||
return (itemNode.view, itemNode.bounds, StickerPreviewPeekContent(account: strongSelf.context.account, theme: strongSelf.theme, strings: strongSelf.strings, item: .pack(item.file), isLocked: item.file.isPremiumSticker && !hasPremium, menu: menuItems, openPremiumIntro: { [weak self] in
|
||||
return (itemNode.view, itemNode.bounds, StickerPreviewPeekContent(context: strongSelf.context, theme: strongSelf.theme, strings: strongSelf.strings, item: .pack(item.file), isLocked: item.file.isPremiumSticker && !hasPremium, menu: menuItems, openPremiumIntro: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
@ -423,7 +423,7 @@ final class EmojisChatInputContextPanelNode: ChatInputContextPanelNode {
|
||||
return nil
|
||||
}
|
||||
|
||||
let content = StickerPreviewPeekContent(account: context.account, theme: presentationData.theme, strings: presentationData.strings, item: .pack(file), isLocked: isLocked, menu: menuItems, openPremiumIntro: { [weak self] in
|
||||
let content = StickerPreviewPeekContent(context: context, theme: presentationData.theme, strings: presentationData.strings, item: .pack(file), isLocked: isLocked, menu: menuItems, openPremiumIntro: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
@ -46,8 +46,8 @@ private struct HorizontalListContextResultsChatInputContextPanelEntry: Comparabl
|
||||
return lhs.index < rhs.index
|
||||
}
|
||||
|
||||
func item(account: Account, resultSelected: @escaping (ChatContextResult, ASDisplayNode, CGRect) -> Bool) -> ListViewItem {
|
||||
return HorizontalListContextResultsChatInputPanelItem(account: account, theme: self.theme, result: self.result, resultSelected: resultSelected)
|
||||
func item(context: AccountContext, resultSelected: @escaping (ChatContextResult, ASDisplayNode, CGRect) -> Bool) -> ListViewItem {
|
||||
return HorizontalListContextResultsChatInputPanelItem(context: context, theme: self.theme, result: self.result, resultSelected: resultSelected)
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,12 +69,12 @@ private final class HorizontalListContextResultsOpaqueState {
|
||||
}
|
||||
}
|
||||
|
||||
private func preparedTransition(from fromEntries: [HorizontalListContextResultsChatInputContextPanelEntry], to toEntries: [HorizontalListContextResultsChatInputContextPanelEntry], hasMore: Bool, account: Account, resultSelected: @escaping (ChatContextResult, ASDisplayNode, CGRect) -> Bool) -> HorizontalListContextResultsChatInputContextPanelTransition {
|
||||
private func preparedTransition(from fromEntries: [HorizontalListContextResultsChatInputContextPanelEntry], to toEntries: [HorizontalListContextResultsChatInputContextPanelEntry], hasMore: Bool, context: AccountContext, resultSelected: @escaping (ChatContextResult, ASDisplayNode, CGRect) -> Bool) -> HorizontalListContextResultsChatInputContextPanelTransition {
|
||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
||||
|
||||
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, resultSelected: resultSelected), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, resultSelected: resultSelected), directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, resultSelected: resultSelected), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, resultSelected: resultSelected), directionHint: nil) }
|
||||
|
||||
return HorizontalListContextResultsChatInputContextPanelTransition(deletions: deletions, insertions: insertions, updates: updates, entryCount: toEntries.count, hasMore: hasMore)
|
||||
}
|
||||
@ -147,6 +147,7 @@ final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputCont
|
||||
}
|
||||
|
||||
var selectedItemNodeAndContent: (UIView, CGRect, PeekControllerContent)?
|
||||
selectedItemNodeAndContent = nil
|
||||
strongSelf.listView.forEachItemNode { itemNode in
|
||||
if itemNode.frame.contains(convertedPoint), let itemNode = itemNode as? HorizontalListContextResultsChatInputPanelItemNode, let item = itemNode.item {
|
||||
if case let .internalReference(internalReference) = item.result, let file = internalReference.file, file.isSticker {
|
||||
@ -177,7 +178,7 @@ final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputCont
|
||||
}
|
||||
})))
|
||||
}
|
||||
selectedItemNodeAndContent = (itemNode.view, itemNode.bounds, StickerPreviewPeekContent(account: item.account, theme: strongSelf.theme, strings: strongSelf.strings, item: .found(FoundStickerItem(file: file, stringRepresentations: [])), menu: menuItems, openPremiumIntro: { [weak self] in
|
||||
selectedItemNodeAndContent = (itemNode.view, itemNode.bounds, StickerPreviewPeekContent(context: item.context, theme: strongSelf.theme, strings: strongSelf.strings, item: .found(FoundStickerItem(file: file, stringRepresentations: [])), menu: menuItems, openPremiumIntro: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
@ -230,7 +231,7 @@ final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputCont
|
||||
f(.default)
|
||||
let _ = item.resultSelected(item.result, itemNode, itemNode.bounds)
|
||||
})))
|
||||
selectedItemNodeAndContent = (itemNode.view, itemNode.bounds, ChatContextResultPeekContent(account: item.account, contextResult: item.result, menu: menuItems))
|
||||
selectedItemNodeAndContent = (itemNode.view, itemNode.bounds, ChatContextResultPeekContent(account: item.context.account, contextResult: item.result, menu: menuItems))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -313,7 +314,7 @@ final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputCont
|
||||
}
|
||||
|
||||
let firstTime = self.currentEntries == nil
|
||||
let transition = preparedTransition(from: self.currentEntries ?? [], to: entries, hasMore: results.nextOffset != nil, account: self.context.account, resultSelected: { [weak self] result, node, rect in
|
||||
let transition = preparedTransition(from: self.currentEntries ?? [], to: entries, hasMore: results.nextOffset != nil, context: self.context, resultSelected: { [weak self] result, node, rect in
|
||||
if let strongSelf = self, let interfaceInteraction = strongSelf.interfaceInteraction {
|
||||
return interfaceInteraction.sendContextResult(results, result, node, rect)
|
||||
} else {
|
||||
|
@ -18,15 +18,15 @@ import SoftwareVideo
|
||||
import MultiplexedVideoNode
|
||||
|
||||
final class HorizontalListContextResultsChatInputPanelItem: ListViewItem {
|
||||
let account: Account
|
||||
let context: AccountContext
|
||||
let theme: PresentationTheme
|
||||
let result: ChatContextResult
|
||||
let resultSelected: (ChatContextResult, ASDisplayNode, CGRect) -> Bool
|
||||
|
||||
let selectable: Bool = true
|
||||
|
||||
public init(account: Account, theme: PresentationTheme, result: ChatContextResult, resultSelected: @escaping (ChatContextResult, ASDisplayNode, CGRect) -> Bool) {
|
||||
self.account = account
|
||||
public init(context: AccountContext, theme: PresentationTheme, result: ChatContextResult, resultSelected: @escaping (ChatContextResult, ASDisplayNode, CGRect) -> Bool) {
|
||||
self.context = context
|
||||
self.theme = theme
|
||||
self.result = result
|
||||
self.resultSelected = resultSelected
|
||||
@ -265,9 +265,9 @@ final class HorizontalListContextResultsChatInputPanelItemNode: ListViewItemNode
|
||||
}
|
||||
|
||||
if let file = videoFile {
|
||||
updatedStatusSignal = item.account.postbox.mediaBox.resourceStatus(file.resource)
|
||||
updatedStatusSignal = item.context.account.postbox.mediaBox.resourceStatus(file.resource)
|
||||
} else if let imageResource = imageResource {
|
||||
updatedStatusSignal = item.account.postbox.mediaBox.resourceStatus(imageResource)
|
||||
updatedStatusSignal = item.context.account.postbox.mediaBox.resourceStatus(imageResource)
|
||||
}
|
||||
case let .internalReference(internalReference):
|
||||
if let image = internalReference.image {
|
||||
@ -296,12 +296,12 @@ final class HorizontalListContextResultsChatInputPanelItemNode: ListViewItemNode
|
||||
if file.isVideo && file.isAnimated {
|
||||
videoFile = file
|
||||
imageResource = nil
|
||||
updatedStatusSignal = item.account.postbox.mediaBox.resourceStatus(file.resource)
|
||||
updatedStatusSignal = item.context.account.postbox.mediaBox.resourceStatus(file.resource)
|
||||
} else if let imageResource = imageResource {
|
||||
updatedStatusSignal = item.account.postbox.mediaBox.resourceStatus(imageResource)
|
||||
updatedStatusSignal = item.context.account.postbox.mediaBox.resourceStatus(imageResource)
|
||||
}
|
||||
} else if let imageResource = imageResource {
|
||||
updatedStatusSignal = item.account.postbox.mediaBox.resourceStatus(imageResource)
|
||||
updatedStatusSignal = item.context.account.postbox.mediaBox.resourceStatus(imageResource)
|
||||
}
|
||||
}
|
||||
|
||||
@ -351,11 +351,11 @@ final class HorizontalListContextResultsChatInputPanelItemNode: ListViewItemNode
|
||||
if updatedImageResource {
|
||||
if let imageResource = imageResource {
|
||||
if let stickerFile = stickerFile {
|
||||
updateImageSignal = chatMessageSticker(account: item.account, userLocation: .other, file: stickerFile, small: false, fetched: true)
|
||||
updateImageSignal = chatMessageSticker(account: item.context.account, userLocation: .other, file: stickerFile, small: false, fetched: true)
|
||||
} else {
|
||||
let tmpRepresentation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(CGSize(width: fittedImageDimensions.width * 2.0, height: fittedImageDimensions.height * 2.0)), resource: imageResource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false)
|
||||
let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [tmpRepresentation], immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])
|
||||
updateImageSignal = chatMessagePhoto(postbox: item.account.postbox, userLocation: .other, photoReference: .standalone(media: tmpImage), synchronousLoad: true)
|
||||
updateImageSignal = chatMessagePhoto(postbox: item.context.account.postbox, userLocation: .other, photoReference: .standalone(media: tmpImage), synchronousLoad: true)
|
||||
}
|
||||
} else {
|
||||
updateImageSignal = .complete()
|
||||
@ -391,7 +391,7 @@ final class HorizontalListContextResultsChatInputPanelItemNode: ListViewItemNode
|
||||
}
|
||||
|
||||
if let videoFile = videoFile {
|
||||
let thumbnailLayer = SoftwareVideoThumbnailNode(account: item.account, fileReference: .standalone(media: videoFile), synchronousLoad: synchronousLoads)
|
||||
let thumbnailLayer = SoftwareVideoThumbnailNode(account: item.context.account, fileReference: .standalone(media: videoFile), synchronousLoad: synchronousLoads)
|
||||
thumbnailLayer.transform = CATransform3DMakeRotation(CGFloat.pi / 2.0, 0.0, 0.0, 1.0)
|
||||
strongSelf.addSubnode(thumbnailLayer)
|
||||
let layerHolder = takeSampleBufferLayer()
|
||||
@ -399,7 +399,7 @@ final class HorizontalListContextResultsChatInputPanelItemNode: ListViewItemNode
|
||||
layerHolder.layer.transform = CATransform3DMakeRotation(CGFloat.pi / 2.0, 0.0, 0.0, 1.0)
|
||||
strongSelf.layer.addSublayer(layerHolder.layer)
|
||||
|
||||
let manager = SoftwareVideoLayerFrameManager(account: item.account, userLocation: .other, userContentType: .other, fileReference: .standalone(media: videoFile), layerHolder: layerHolder)
|
||||
let manager = SoftwareVideoLayerFrameManager(account: item.context.account, userLocation: .other, userContentType: .other, fileReference: .standalone(media: videoFile), layerHolder: layerHolder)
|
||||
strongSelf.videoLayer = (thumbnailLayer, manager, layerHolder)
|
||||
thumbnailLayer.ready = { [weak thumbnailLayer, weak manager] in
|
||||
if let strongSelf = self, let thumbnailLayer = thumbnailLayer, let manager = manager {
|
||||
@ -437,8 +437,8 @@ final class HorizontalListContextResultsChatInputPanelItemNode: ListViewItemNode
|
||||
}
|
||||
let dimensions = animatedStickerFile.dimensions ?? PixelDimensions(width: 512, height: 512)
|
||||
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))
|
||||
strongSelf.fetchDisposable.set(freeMediaFileResourceInteractiveFetched(account: item.account, userLocation: .other, fileReference: stickerPackFileReference(animatedStickerFile), resource: animatedStickerFile.resource).start())
|
||||
animationNode.setup(source: AnimatedStickerResourceSource(account: item.account, resource: animatedStickerFile.resource, isVideo: animatedStickerFile.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .cached)
|
||||
strongSelf.fetchDisposable.set(freeMediaFileResourceInteractiveFetched(account: item.context.account, userLocation: .other, fileReference: stickerPackFileReference(animatedStickerFile), resource: animatedStickerFile.resource).start())
|
||||
animationNode.setup(source: AnimatedStickerResourceSource(account: item.context.account, resource: animatedStickerFile.resource, isVideo: animatedStickerFile.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .cached)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -243,7 +243,7 @@ final class HorizontalStickersChatContextPanelNode: ChatInputContextPanelNode {
|
||||
}
|
||||
}))
|
||||
]
|
||||
return (itemNode.view, itemNode.bounds, StickerPreviewPeekContent(account: strongSelf.context.account, theme: strongSelf.theme, strings: strongSelf.strings, item: .pack(item.file), menu: menuItems, openPremiumIntro: { [weak self] in
|
||||
return (itemNode.view, itemNode.bounds, StickerPreviewPeekContent(context: strongSelf.context, theme: strongSelf.theme, strings: strongSelf.strings, item: .pack(item.file), menu: menuItems, openPremiumIntro: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
@ -198,7 +198,7 @@ private final class InlineReactionSearchStickersNode: ASDisplayNode, UIScrollVie
|
||||
}
|
||||
}))
|
||||
)
|
||||
return (itemNode.view, itemNode.bounds, StickerPreviewPeekContent(account: strongSelf.context.account, theme: strongSelf.theme, strings: strongSelf.strings, item: .pack(item.file), menu: menuItems, openPremiumIntro: { [weak self] in
|
||||
return (itemNode.view, itemNode.bounds, StickerPreviewPeekContent(context: strongSelf.context, theme: strongSelf.theme, strings: strongSelf.strings, item: .pack(item.file), menu: menuItems, openPremiumIntro: { [weak self] in
|
||||
guard let strongSelf = self, let controllerInteraction = strongSelf.getControllerInteraction?() else {
|
||||
return
|
||||
}
|
||||
|
@ -199,7 +199,7 @@ final class StickersChatInputContextPanelNode: ChatInputContextPanelNode {
|
||||
}
|
||||
}))
|
||||
]
|
||||
return (itemNode.view, itemNode.bounds, StickerPreviewPeekContent(account: strongSelf.context.account, theme: strongSelf.theme, strings: strongSelf.strings, item: .pack(item.file), menu: menuItems, openPremiumIntro: { [weak self] in
|
||||
return (itemNode.view, itemNode.bounds, StickerPreviewPeekContent(context: strongSelf.context, theme: strongSelf.theme, strings: strongSelf.strings, item: .pack(item.file), menu: menuItems, openPremiumIntro: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user