mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-08 09:49:51 +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 overlayColor: (UIColor?, Bool)? = nil
|
||||||
private var size: CGSize?
|
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) {
|
public init(useMetalCache: Bool = false) {
|
||||||
self.queue = sharedQueue
|
self.queue = sharedQueue
|
||||||
self.eventsNode = AnimatedStickerNodeDisplayEvents()
|
self.eventsNode = AnimatedStickerNodeDisplayEvents()
|
||||||
@ -279,12 +288,12 @@ public final class DefaultAnimatedStickerNodeImpl: ASDisplayNode, AnimatedSticke
|
|||||||
if #available(iOS 10.0, *) {
|
if #available(iOS 10.0, *) {
|
||||||
return CompressedAnimationRenderer()
|
return CompressedAnimationRenderer()
|
||||||
} else {
|
} else {
|
||||||
return SoftwareAnimationRenderer()
|
return SoftwareAnimationRenderer(templateImageSupport: true)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
private static let softwareRendererPool = AnimationRendererPool(generate: {
|
private static let softwareRendererPool = AnimationRendererPool(generate: {
|
||||||
return SoftwareAnimationRenderer()
|
return SoftwareAnimationRenderer(templateImageSupport: true)
|
||||||
})
|
})
|
||||||
|
|
||||||
private weak var nodeToCopyFrameFrom: DefaultAnimatedStickerNodeImpl?
|
private weak var nodeToCopyFrameFrom: DefaultAnimatedStickerNodeImpl?
|
||||||
@ -295,6 +304,12 @@ public final class DefaultAnimatedStickerNodeImpl: ASDisplayNode, AnimatedSticke
|
|||||||
self.renderer = DefaultAnimatedStickerNodeImpl.hardwareRendererPool.take()
|
self.renderer = DefaultAnimatedStickerNodeImpl.hardwareRendererPool.take()
|
||||||
} else {
|
} else {
|
||||||
self.renderer = DefaultAnimatedStickerNodeImpl.softwareRendererPool.take()
|
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 {
|
if let contents = self.nodeToCopyFrameFrom?.renderer?.renderer.contents {
|
||||||
self.renderer?.renderer.contents = contents
|
self.renderer?.renderer.contents = contents
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,20 +7,30 @@ import YuvConversion
|
|||||||
import Accelerate
|
import Accelerate
|
||||||
|
|
||||||
final class SoftwareAnimationRenderer: ASDisplayNode, AnimationRenderer {
|
final class SoftwareAnimationRenderer: ASDisplayNode, AnimationRenderer {
|
||||||
|
private let templateImageSupport: Bool
|
||||||
|
|
||||||
private var highlightedContentNode: ASDisplayNode?
|
private var highlightedContentNode: ASDisplayNode?
|
||||||
private var highlightedColor: UIColor?
|
private var highlightedColor: UIColor?
|
||||||
private var highlightReplacesContent = false
|
private var highlightReplacesContent = false
|
||||||
|
public var renderAsTemplateImage: Bool = false
|
||||||
|
|
||||||
public var currentFrameImage: UIImage? {
|
public private(set) var currentFrameImage: UIImage?
|
||||||
if let contents = self.contents {
|
|
||||||
return UIImage(cgImage: contents as! CGImage)
|
init(templateImageSupport: Bool) {
|
||||||
} else {
|
self.templateImageSupport = templateImageSupport
|
||||||
return nil
|
|
||||||
|
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) {
|
func render(queue: Queue, width: Int, height: Int, bytesPerRow: Int, data: Data, type: AnimationRendererFrameType, mulAlpha: Bool, completion: @escaping () -> Void) {
|
||||||
assert(bytesPerRow > 0)
|
assert(bytesPerRow > 0)
|
||||||
|
let renderAsTemplateImage = self.renderAsTemplateImage
|
||||||
queue.async { [weak self] in
|
queue.async { [weak self] in
|
||||||
switch type {
|
switch type {
|
||||||
case .argb:
|
case .argb:
|
||||||
@ -70,13 +80,21 @@ final class SoftwareAnimationRenderer: ASDisplayNode, AnimationRenderer {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
if renderAsTemplateImage {
|
||||||
|
image = image?.withRenderingMode(.alwaysTemplate)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Queue.mainQueue().async {
|
Queue.mainQueue().async {
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
strongSelf.contents = image?.cgImage
|
strongSelf.currentFrameImage = image
|
||||||
|
if strongSelf.templateImageSupport {
|
||||||
|
(strongSelf.view as? UIImageView)?.image = image
|
||||||
|
} else {
|
||||||
|
strongSelf.contents = image?.cgImage
|
||||||
|
}
|
||||||
strongSelf.updateHighlightedContentNode()
|
strongSelf.updateHighlightedContentNode()
|
||||||
if strongSelf.highlightedContentNode?.frame != strongSelf.bounds {
|
if strongSelf.highlightedContentNode?.frame != strongSelf.bounds {
|
||||||
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 {
|
guard let highlightedContentNode = self.highlightedContentNode, let highlightedColor = self.highlightedColor else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if let contents = self.contents, CFGetTypeID(contents as CFTypeRef) == CGImage.typeID {
|
(highlightedContentNode.view as! UIImageView).image = self.currentFrameImage?.withRenderingMode(.alwaysTemplate)
|
||||||
(highlightedContentNode.view as! UIImageView).image = UIImage(cgImage: contents as! CGImage).withRenderingMode(.alwaysTemplate)
|
|
||||||
}
|
|
||||||
highlightedContentNode.tintColor = highlightedColor
|
highlightedContentNode.tintColor = highlightedColor
|
||||||
if self.highlightReplacesContent {
|
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.position = CGPoint(x: frame.midX, y: frame.midY)
|
||||||
view.layer.removeAnimation(forKey: "position")
|
view.layer.removeAnimation(forKey: "position")
|
||||||
view.layer.removeAnimation(forKey: "bounds")
|
view.layer.removeAnimation(forKey: "bounds")
|
||||||
|
view.layer.removeAnimation(forKey: "bounds.size")
|
||||||
completion?(true)
|
completion?(true)
|
||||||
case .curve:
|
case .curve:
|
||||||
let previousFrame: CGRect
|
let previousPosition: CGPoint
|
||||||
if (view.layer.animation(forKey: "position") != nil || view.layer.animation(forKey: "bounds") != nil), let presentation = view.layer.presentation() {
|
let previousBounds: CGRect
|
||||||
previousFrame = presentation.frame
|
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 {
|
} else {
|
||||||
previousFrame = view.frame
|
previousPosition = view.layer.position
|
||||||
|
previousBounds = view.layer.bounds
|
||||||
}
|
}
|
||||||
|
|
||||||
view.frame = frame
|
view.frame = frame
|
||||||
//view.bounds = CGRect(origin: previousBounds.origin, size: frame.size)
|
//view.bounds = CGRect(origin: previousBounds.origin, size: frame.size)
|
||||||
//view.center = CGPoint(x: frame.midX, y: frame.midY)
|
//view.center = CGPoint(x: frame.midX, y: frame.midY)
|
||||||
|
|
||||||
self.animatePosition(view: view, from: CGPoint(x: previousFrame.midX, y: previousFrame.midY), to: CGPoint(x: frame.midX, y: frame.midY), completion: completion)
|
let anchorPoint = view.layer.anchorPoint
|
||||||
self.animateBoundsSize(view: view, from: previousFrame.size, to: frame.size)
|
let updatedPosition = CGPoint(x: frame.minX + frame.width * anchorPoint.x, y: frame.minY + frame.height * anchorPoint.y)
|
||||||
|
|
||||||
|
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:
|
case .none:
|
||||||
view.bounds = bounds
|
view.bounds = bounds
|
||||||
view.layer.removeAnimation(forKey: "bounds")
|
view.layer.removeAnimation(forKey: "bounds")
|
||||||
|
view.layer.removeAnimation(forKey: "bounds.origin")
|
||||||
|
view.layer.removeAnimation(forKey: "bounds.size")
|
||||||
completion?(true)
|
completion?(true)
|
||||||
case .curve:
|
case .curve:
|
||||||
let previousBounds: CGRect
|
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
|
previousBounds = presentation.bounds
|
||||||
} else {
|
} else {
|
||||||
previousBounds = view.layer.bounds
|
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) {
|
public func setBoundsSize(view: UIView, size: CGSize, completion: ((Bool) -> Void)? = nil) {
|
||||||
if view.bounds.size == size {
|
if view.bounds.size == size {
|
||||||
completion?(true)
|
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) {
|
func updateManualText(_ text: String, isBack: Bool = true) {
|
||||||
let node: NavigationButtonItemNode
|
let node: NavigationButtonItemNode
|
||||||
if self.nodes.count > 0 {
|
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 {
|
guard let strongSelf = self else {
|
||||||
return
|
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 {
|
guard let strongSelf = self else {
|
||||||
return
|
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
|
return nil
|
||||||
|
|||||||
@ -9,14 +9,15 @@ import StickerResources
|
|||||||
import AnimatedStickerNode
|
import AnimatedStickerNode
|
||||||
import TelegramAnimatedStickerNode
|
import TelegramAnimatedStickerNode
|
||||||
import ContextUI
|
import ContextUI
|
||||||
|
import AccountContext
|
||||||
|
|
||||||
final class StickerPreviewPeekContent: PeekControllerContent {
|
final class StickerPreviewPeekContent: PeekControllerContent {
|
||||||
let account: Account
|
let context: AccountContext
|
||||||
let item: ImportStickerPack.Sticker
|
let item: ImportStickerPack.Sticker
|
||||||
let menu: [ContextMenuItem]
|
let menu: [ContextMenuItem]
|
||||||
|
|
||||||
init(account: Account, item: ImportStickerPack.Sticker, menu: [ContextMenuItem]) {
|
init(context: AccountContext, item: ImportStickerPack.Sticker, menu: [ContextMenuItem]) {
|
||||||
self.account = account
|
self.context = context
|
||||||
self.item = item
|
self.item = item
|
||||||
self.menu = menu
|
self.menu = menu
|
||||||
}
|
}
|
||||||
@ -34,7 +35,7 @@ final class StickerPreviewPeekContent: PeekControllerContent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func node() -> PeekControllerContentNode & ASDisplayNode {
|
func node() -> PeekControllerContentNode & ASDisplayNode {
|
||||||
return StickerPreviewPeekContentNode(account: self.account, item: self.item)
|
return StickerPreviewPeekContentNode(account: self.context.account, item: self.item)
|
||||||
}
|
}
|
||||||
|
|
||||||
func topAccessoryNode() -> ASDisplayNode? {
|
func topAccessoryNode() -> ASDisplayNode? {
|
||||||
|
|||||||
@ -169,6 +169,7 @@ private final class SubItemNode: HighlightTrackingButtonNode {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
checkNode = CheckNode(theme: CheckNodeTheme(theme: presentationData.theme, style: .plain))
|
checkNode = CheckNode(theme: CheckNodeTheme(theme: presentationData.theme, style: .plain))
|
||||||
|
checkNode.isUserInteractionEnabled = false
|
||||||
self.checkNode = checkNode
|
self.checkNode = checkNode
|
||||||
self.addSubnode(checkNode)
|
self.addSubnode(checkNode)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -460,7 +460,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
} else {
|
} else {
|
||||||
strongSelf.stableEmptyResultEmoji = nil
|
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 {
|
} else {
|
||||||
strongSelf.stableEmptyResultEmoji = nil
|
strongSelf.stableEmptyResultEmoji = nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,14 +12,22 @@ import AccountContext
|
|||||||
|
|
||||||
public func autodownloadDataSizeString(_ size: Int64, decimalSeparator: String = ".") -> String {
|
public func autodownloadDataSizeString(_ size: Int64, decimalSeparator: String = ".") -> String {
|
||||||
if size >= 1024 * 1024 * 1024 {
|
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 {
|
if remainder != 0 {
|
||||||
return "\(size / (1024 * 1024 * 1024))\(decimalSeparator)\(remainder) GB"
|
return "\(size / (1024 * 1024 * 1024))\(decimalSeparator)\(remainder) GB"
|
||||||
} else {
|
} else {
|
||||||
return "\(size / (1024 * 1024 * 1024)) GB"
|
return "\(size / (1024 * 1024 * 1024)) GB"
|
||||||
}
|
}
|
||||||
} else if size >= 1024 * 1024 {
|
} 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 {
|
if size < 10 * 1024 * 1024 {
|
||||||
return "\(size / (1024 * 1024))\(decimalSeparator)\(remainder) MB"
|
return "\(size / (1024 * 1024))\(decimalSeparator)\(remainder) MB"
|
||||||
} else {
|
} 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 {
|
} 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 {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,7 +29,7 @@ public enum StickerPreviewPeekItem: Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class StickerPreviewPeekContent: PeekControllerContent {
|
public final class StickerPreviewPeekContent: PeekControllerContent {
|
||||||
let account: Account
|
let context: AccountContext
|
||||||
let theme: PresentationTheme
|
let theme: PresentationTheme
|
||||||
let strings: PresentationStrings
|
let strings: PresentationStrings
|
||||||
public let item: StickerPreviewPeekItem
|
public let item: StickerPreviewPeekItem
|
||||||
@ -37,8 +37,8 @@ public final class StickerPreviewPeekContent: PeekControllerContent {
|
|||||||
let menu: [ContextMenuItem]
|
let menu: [ContextMenuItem]
|
||||||
let openPremiumIntro: () -> Void
|
let openPremiumIntro: () -> Void
|
||||||
|
|
||||||
public init(account: Account, theme: PresentationTheme, strings: PresentationStrings, item: StickerPreviewPeekItem, isLocked: Bool = false, menu: [ContextMenuItem], openPremiumIntro: @escaping () -> Void) {
|
public init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, item: StickerPreviewPeekItem, isLocked: Bool = false, menu: [ContextMenuItem], openPremiumIntro: @escaping () -> Void) {
|
||||||
self.account = account
|
self.context = context
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
self.item = item
|
self.item = item
|
||||||
@ -64,7 +64,7 @@ public final class StickerPreviewPeekContent: PeekControllerContent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func node() -> PeekControllerContentNode & ASDisplayNode {
|
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? {
|
public func topAccessoryNode() -> ASDisplayNode? {
|
||||||
@ -91,7 +91,7 @@ public final class StickerPreviewPeekContent: PeekControllerContent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class StickerPreviewPeekContentNode: ASDisplayNode, PeekControllerContentNode {
|
public final class StickerPreviewPeekContentNode: ASDisplayNode, PeekControllerContentNode {
|
||||||
private let account: Account
|
private let context: AccountContext
|
||||||
private let item: StickerPreviewPeekItem
|
private let item: StickerPreviewPeekItem
|
||||||
|
|
||||||
private var textNode: ASTextNode
|
private var textNode: ASTextNode
|
||||||
@ -105,8 +105,8 @@ public final class StickerPreviewPeekContentNode: ASDisplayNode, PeekControllerC
|
|||||||
|
|
||||||
private let _ready = Promise<Bool>()
|
private let _ready = Promise<Bool>()
|
||||||
|
|
||||||
init(account: Account, item: StickerPreviewPeekItem) {
|
init(context: AccountContext, item: StickerPreviewPeekItem, theme: PresentationTheme) {
|
||||||
self.account = account
|
self.context = context
|
||||||
self.item = item
|
self.item = item
|
||||||
|
|
||||||
self.textNode = ASTextNode()
|
self.textNode = ASTextNode()
|
||||||
@ -133,14 +133,18 @@ public final class StickerPreviewPeekContentNode: ASDisplayNode, PeekControllerC
|
|||||||
}
|
}
|
||||||
let fittedDimensions = dimensions.cgSize.aspectFitted(fitSize)
|
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.visibility = true
|
||||||
animationNode.addSubnode(self.textNode)
|
animationNode.addSubnode(self.textNode)
|
||||||
|
|
||||||
if isPremiumSticker, let effect = item.file.videoThumbnails.first {
|
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()
|
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.setup(source: source, width: Int(fittedDimensions.width * 2.0), height: Int(fittedDimensions.height * 2.0), playbackMode: .once, mode: .direct(cachePathPrefix: nil))
|
||||||
additionalAnimationNode.visibility = true
|
additionalAnimationNode.visibility = true
|
||||||
@ -151,7 +155,7 @@ public final class StickerPreviewPeekContentNode: ASDisplayNode, PeekControllerC
|
|||||||
self.animationNode = nil
|
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()
|
super.init()
|
||||||
|
|
||||||
|
|||||||
@ -633,6 +633,9 @@ public final class TelegramMediaFile: Media, Equatable, Codable {
|
|||||||
if case .Sticker = attribute {
|
if case .Sticker = attribute {
|
||||||
hasSticker = true
|
hasSticker = true
|
||||||
break
|
break
|
||||||
|
} else if case .CustomEmoji = attribute {
|
||||||
|
hasSticker = true
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return hasSticker
|
return hasSticker
|
||||||
|
|||||||
@ -850,9 +850,9 @@ final class AvatarEditorScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if state?.keyboardContentId == AnyHashable("emoji") {
|
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 {
|
} 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
|
strongSelf.currentUndoOverlayController = controller
|
||||||
controllerInteraction.presentController(controller, nil)
|
controllerInteraction.presentController(controller, nil)
|
||||||
},
|
},
|
||||||
copyEmoji: { file in
|
copyEmoji: { [weak self] file in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var text = "."
|
var text = "."
|
||||||
var emojiAttribute: ChatTextInputTextCustomEmojiAttribute?
|
var emojiAttribute: ChatTextInputTextCustomEmojiAttribute?
|
||||||
loop: for attribute in file.attributes {
|
loop: for attribute in file.attributes {
|
||||||
@ -625,6 +629,20 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||||||
|
|
||||||
if let _ = emojiAttribute {
|
if let _ = emojiAttribute {
|
||||||
storeMessageTextInPasteboard(text, entities: [MessageTextEntity(range: 0 ..< (text as NSString).length, type: .CustomEmoji(stickerPack: nil, fileId: file.fileId.id))])
|
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,
|
presentController: controllerInteraction.presentController,
|
||||||
@ -1425,7 +1443,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
if let emoji = inputData.emoji {
|
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 {
|
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 {
|
private func processInputData(inputData: InputData) -> InputData {
|
||||||
return InputData(
|
return InputData(
|
||||||
emoji: inputData.emoji.flatMap { emoji in
|
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
|
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,
|
gifs: inputData.gifs,
|
||||||
availableGifSearchEmojies: inputData.availableGifSearchEmojies
|
availableGifSearchEmojies: inputData.availableGifSearchEmojies
|
||||||
@ -2503,7 +2521,7 @@ public final class EmojiContentPeekBehaviorImpl: EmojiContentPeekBehavior {
|
|||||||
return nil
|
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 {
|
guard let strongSelf = self, let interaction = strongSelf.interaction else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -2632,7 +2650,7 @@ public final class EmojiContentPeekBehaviorImpl: EmojiContentPeekBehavior {
|
|||||||
return nil
|
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 {
|
guard let strongSelf = self, let interaction = strongSelf.interaction else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -371,7 +371,7 @@ public final class EmojiStatusSelectionController: ViewController {
|
|||||||
} else {
|
} else {
|
||||||
strongSelf.stableEmptyResultEmoji = nil
|
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 {
|
} else {
|
||||||
strongSelf.stableEmptyResultEmoji = nil
|
strongSelf.stableEmptyResultEmoji = nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1330,6 +1330,15 @@ private final class GroupEmbeddedView: UIScrollView, UIScrollViewDelegate, Pager
|
|||||||
self.layer.addSublayer(itemLayer)
|
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)
|
let itemFrame = itemLayout.frame(at: index)
|
||||||
itemLayer.frame = itemFrame
|
itemLayer.frame = itemFrame
|
||||||
|
|
||||||
@ -1708,17 +1717,24 @@ public final class EmojiSearchHeaderView: UIView, UITextFieldDelegate {
|
|||||||
if case .ended = recognizer.state {
|
if case .ended = recognizer.state {
|
||||||
let location = recognizer.location(in: self)
|
let location = recognizer.location(in: self)
|
||||||
if self.backIconView.frame.contains(location) {
|
if self.backIconView.frame.contains(location) {
|
||||||
if let placeholderContentView = self.placeholderContent.view as? EmojiSearchSearchBarComponent.View {
|
self.clearCategorySearch()
|
||||||
placeholderContentView.clearSelection(dispatchEvent : true)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
self.activateTextInput()
|
self.activateTextInput()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func clearCategorySearch() {
|
||||||
|
if let placeholderContentView = self.placeholderContent.view as? EmojiSearchSearchBarComponent.View {
|
||||||
|
placeholderContentView.clearSelection(dispatchEvent : true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func activateTextInput() {
|
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 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))
|
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)
|
textField.addTarget(self, action: #selector(self.textFieldChanged(_:)), for: .editingChanged)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.currentPresetSearchTerm = nil
|
if params.canFocus {
|
||||||
if let placeholderContentView = self.placeholderContent.view as? EmojiSearchSearchBarComponent.View {
|
self.currentPresetSearchTerm = nil
|
||||||
placeholderContentView.clearSelection(dispatchEvent: false)
|
if let placeholderContentView = self.placeholderContent.view as? EmojiSearchSearchBarComponent.View {
|
||||||
|
placeholderContentView.clearSelection(dispatchEvent: false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.activated(true)
|
self.activated(true)
|
||||||
@ -1968,9 +1986,9 @@ public final class EmojiSearchHeaderView: UIView, UITextFieldDelegate {
|
|||||||
self.currentPresetSearchTerm = term
|
self.currentPresetSearchTerm = term
|
||||||
|
|
||||||
if shouldChangeActivation {
|
if shouldChangeActivation {
|
||||||
self.update(transition: Transition(animation: .curve(duration: 0.4, curve: .spring)))
|
|
||||||
|
|
||||||
if let term {
|
if let term {
|
||||||
|
self.update(transition: Transition(animation: .curve(duration: 0.4, curve: .spring)))
|
||||||
|
|
||||||
self.updateQuery(.category(value: term))
|
self.updateQuery(.category(value: term))
|
||||||
self.activated(false)
|
self.activated(false)
|
||||||
} else {
|
} else {
|
||||||
@ -2049,6 +2067,7 @@ public final class EmojiSearchHeaderView: UIView, UITextFieldDelegate {
|
|||||||
cancelButtonTitleComponentView.isUserInteractionEnabled = false
|
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.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 let cancelButtonTintTitleComponentView = self.cancelButtonTintTitle.view {
|
||||||
if cancelButtonTintTitleComponentView.superview == nil {
|
if cancelButtonTintTitleComponentView.superview == nil {
|
||||||
@ -2056,6 +2075,7 @@ public final class EmojiSearchHeaderView: UIView, UITextFieldDelegate {
|
|||||||
cancelButtonTintTitleComponentView.isUserInteractionEnabled = false
|
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.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
|
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) {
|
func update(context: AccountContext, theme: PresentationTheme, useOpaqueTheme: Bool, text: String, file: TelegramMediaFile?, size: CGSize, searchInitiallyHidden: Bool, transition: Transition) {
|
||||||
let titleColor: UIColor
|
let titleColor: UIColor
|
||||||
if useOpaqueTheme {
|
if useOpaqueTheme {
|
||||||
titleColor = theme.chat.inputMediaPanel.panelContentControlOpaqueOverlayColor
|
titleColor = theme.chat.inputMediaPanel.panelContentOpaqueSearchOverlayColor
|
||||||
} else {
|
} else {
|
||||||
titleColor = theme.chat.inputMediaPanel.panelContentControlVibrantOverlayColor
|
titleColor = theme.chat.inputMediaPanel.panelContentVibrantSearchOverlayColor
|
||||||
}
|
}
|
||||||
|
|
||||||
let iconSize: CGSize
|
let iconSize: CGSize
|
||||||
@ -2513,6 +2533,12 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
case detailed
|
case detailed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum SearchState {
|
||||||
|
case empty
|
||||||
|
case searching
|
||||||
|
case active
|
||||||
|
}
|
||||||
|
|
||||||
public final class EmptySearchResults: Equatable {
|
public final class EmptySearchResults: Equatable {
|
||||||
public let text: String
|
public let text: String
|
||||||
public let iconFile: TelegramMediaFile?
|
public let iconFile: TelegramMediaFile?
|
||||||
@ -2543,6 +2569,7 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
public let contentItemGroups: [ItemGroup]
|
public let contentItemGroups: [ItemGroup]
|
||||||
public let itemLayoutType: ItemLayoutType
|
public let itemLayoutType: ItemLayoutType
|
||||||
public let itemContentUniqueId: AnyHashable?
|
public let itemContentUniqueId: AnyHashable?
|
||||||
|
public let searchState: SearchState
|
||||||
public let warpContentsOnEdges: Bool
|
public let warpContentsOnEdges: Bool
|
||||||
public let displaySearchWithPlaceholder: String?
|
public let displaySearchWithPlaceholder: String?
|
||||||
public let searchCategories: EmojiSearchCategories?
|
public let searchCategories: EmojiSearchCategories?
|
||||||
@ -2564,6 +2591,7 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
contentItemGroups: [ItemGroup],
|
contentItemGroups: [ItemGroup],
|
||||||
itemLayoutType: ItemLayoutType,
|
itemLayoutType: ItemLayoutType,
|
||||||
itemContentUniqueId: AnyHashable?,
|
itemContentUniqueId: AnyHashable?,
|
||||||
|
searchState: SearchState,
|
||||||
warpContentsOnEdges: Bool,
|
warpContentsOnEdges: Bool,
|
||||||
displaySearchWithPlaceholder: String?,
|
displaySearchWithPlaceholder: String?,
|
||||||
searchCategories: EmojiSearchCategories?,
|
searchCategories: EmojiSearchCategories?,
|
||||||
@ -2584,6 +2612,7 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
self.contentItemGroups = contentItemGroups
|
self.contentItemGroups = contentItemGroups
|
||||||
self.itemLayoutType = itemLayoutType
|
self.itemLayoutType = itemLayoutType
|
||||||
self.itemContentUniqueId = itemContentUniqueId
|
self.itemContentUniqueId = itemContentUniqueId
|
||||||
|
self.searchState = searchState
|
||||||
self.warpContentsOnEdges = warpContentsOnEdges
|
self.warpContentsOnEdges = warpContentsOnEdges
|
||||||
self.displaySearchWithPlaceholder = displaySearchWithPlaceholder
|
self.displaySearchWithPlaceholder = displaySearchWithPlaceholder
|
||||||
self.searchCategories = searchCategories
|
self.searchCategories = searchCategories
|
||||||
@ -2595,7 +2624,7 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
self.selectedItems = selectedItems
|
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(
|
return EmojiPagerContentComponent(
|
||||||
id: self.id,
|
id: self.id,
|
||||||
context: self.context,
|
context: self.context,
|
||||||
@ -2607,6 +2636,7 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
contentItemGroups: contentItemGroups,
|
contentItemGroups: contentItemGroups,
|
||||||
itemLayoutType: self.itemLayoutType,
|
itemLayoutType: self.itemLayoutType,
|
||||||
itemContentUniqueId: itemContentUniqueId,
|
itemContentUniqueId: itemContentUniqueId,
|
||||||
|
searchState: searchState,
|
||||||
warpContentsOnEdges: self.warpContentsOnEdges,
|
warpContentsOnEdges: self.warpContentsOnEdges,
|
||||||
displaySearchWithPlaceholder: self.displaySearchWithPlaceholder,
|
displaySearchWithPlaceholder: self.displaySearchWithPlaceholder,
|
||||||
searchCategories: self.searchCategories,
|
searchCategories: self.searchCategories,
|
||||||
@ -2650,6 +2680,12 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
if lhs.itemLayoutType != rhs.itemLayoutType {
|
if lhs.itemLayoutType != rhs.itemLayoutType {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.itemContentUniqueId != rhs.itemContentUniqueId {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.searchState != rhs.searchState {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhs.warpContentsOnEdges != rhs.warpContentsOnEdges {
|
if lhs.warpContentsOnEdges != rhs.warpContentsOnEdges {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -2662,6 +2698,9 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
if lhs.searchInitiallyHidden != rhs.searchInitiallyHidden {
|
if lhs.searchInitiallyHidden != rhs.searchInitiallyHidden {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.searchAlwaysActive != rhs.searchAlwaysActive {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhs.searchIsPlaceholderOnly != rhs.searchIsPlaceholderOnly {
|
if lhs.searchIsPlaceholderOnly != rhs.searchIsPlaceholderOnly {
|
||||||
return false
|
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 {
|
guard let component = self.component, let pagerEnvironment = self.pagerEnvironment, let itemLayout = self.itemLayout else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.isSearchActivated {
|
||||||
|
self.visibleSearchHeader?.clearCategorySearch()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
for groupIndex in 0 ..< itemLayout.itemGroupLayouts.count {
|
for groupIndex in 0 ..< itemLayout.itemGroupLayouts.count {
|
||||||
let group = itemLayout.itemGroupLayouts[groupIndex]
|
let group = itemLayout.itemGroupLayouts[groupIndex]
|
||||||
|
|
||||||
@ -5044,7 +5089,7 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
scrollView.layer.removeAllAnimations()
|
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
|
scrollView.isScrollEnabled = false
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
scrollView.isScrollEnabled = true
|
scrollView.isScrollEnabled = true
|
||||||
@ -6024,6 +6069,9 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return nil
|
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 {
|
guard let item = strongSelf.item(atPoint: point), let itemLayer = strongSelf.visibleItemLayers[item.1], let file = item.0.itemFile else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -6459,12 +6507,15 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
|
|
||||||
strongSelf.isSearchActivated = false
|
strongSelf.isSearchActivated = false
|
||||||
strongSelf.pagerEnvironment?.onWantsExclusiveModeUpdated(false)
|
strongSelf.pagerEnvironment?.onWantsExclusiveModeUpdated(false)
|
||||||
if strongSelf.component?.searchInitiallyHidden == false {
|
|
||||||
if !isFirstResponder {
|
if !isFirstResponder {
|
||||||
strongSelf.component?.inputInteractionHolder.inputInteraction?.requestUpdate(.easeInOut(duration: 0.2))
|
strongSelf.component?.inputInteractionHolder.inputInteraction?.requestUpdate(
|
||||||
}
|
Transition(animation: .curve(duration: 0.4, curve: .spring)))
|
||||||
} else {
|
} 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
|
}, updateQuery: { [weak self] query in
|
||||||
@ -6550,7 +6601,11 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
visibleEmptySearchResultsView = EmptySearchResultsView(frame: CGRect())
|
visibleEmptySearchResultsView = EmptySearchResultsView(frame: CGRect())
|
||||||
self.visibleEmptySearchResultsView = visibleEmptySearchResultsView
|
self.visibleEmptySearchResultsView = visibleEmptySearchResultsView
|
||||||
self.addSubview(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)
|
let emptySearchResultsSize = CGSize(width: availableSize.width, height: availableSize.height - itemLayout.searchInsets.top - itemLayout.searchHeight)
|
||||||
visibleEmptySearchResultsView.update(
|
visibleEmptySearchResultsView.update(
|
||||||
@ -7550,6 +7605,7 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
contentItemGroups: allItemGroups,
|
contentItemGroups: allItemGroups,
|
||||||
itemLayoutType: .compact,
|
itemLayoutType: .compact,
|
||||||
itemContentUniqueId: nil,
|
itemContentUniqueId: nil,
|
||||||
|
searchState: .empty,
|
||||||
warpContentsOnEdges: isReactionSelection || isStatusSelection || isProfilePhotoEmojiSelection || isGroupPhotoEmojiSelection,
|
warpContentsOnEdges: isReactionSelection || isStatusSelection || isProfilePhotoEmojiSelection || isGroupPhotoEmojiSelection,
|
||||||
displaySearchWithPlaceholder: displaySearchWithPlaceholder,
|
displaySearchWithPlaceholder: displaySearchWithPlaceholder,
|
||||||
searchCategories: searchCategories,
|
searchCategories: searchCategories,
|
||||||
@ -8071,6 +8127,7 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
contentItemGroups: allItemGroups,
|
contentItemGroups: allItemGroups,
|
||||||
itemLayoutType: .detailed,
|
itemLayoutType: .detailed,
|
||||||
itemContentUniqueId: nil,
|
itemContentUniqueId: nil,
|
||||||
|
searchState: .empty,
|
||||||
warpContentsOnEdges: isProfilePhotoEmojiSelection || isGroupPhotoEmojiSelection,
|
warpContentsOnEdges: isProfilePhotoEmojiSelection || isGroupPhotoEmojiSelection,
|
||||||
displaySearchWithPlaceholder: hasSearch ? strings.StickersSearch_SearchStickersPlaceholder : nil,
|
displaySearchWithPlaceholder: hasSearch ? strings.StickersSearch_SearchStickersPlaceholder : nil,
|
||||||
searchCategories: searchCategories,
|
searchCategories: searchCategories,
|
||||||
|
|||||||
@ -391,6 +391,7 @@ public final class EmojiSearchContent: ASDisplayNode, EntitySearchContainerNode
|
|||||||
contentItemGroups: self.itemGroups,
|
contentItemGroups: self.itemGroups,
|
||||||
itemLayoutType: .compact,
|
itemLayoutType: .compact,
|
||||||
itemContentUniqueId: "main",
|
itemContentUniqueId: "main",
|
||||||
|
searchState: .empty,
|
||||||
warpContentsOnEdges: false,
|
warpContentsOnEdges: false,
|
||||||
displaySearchWithPlaceholder: "Search Emoji",
|
displaySearchWithPlaceholder: "Search Emoji",
|
||||||
searchCategories: nil,
|
searchCategories: nil,
|
||||||
@ -410,7 +411,7 @@ public final class EmojiSearchContent: ASDisplayNode, EntitySearchContainerNode
|
|||||||
iconFile: nil
|
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(
|
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.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>? {
|
func visibleItems(for rect: CGRect) -> Range<Int>? {
|
||||||
@ -310,7 +317,7 @@ final class EmojiSearchSearchBarComponent: Component {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let transition = Transition(animation: .curve(duration: 0.4, curve: .spring))
|
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.updateScrolling(transition: transition, fromScrolling: false)
|
||||||
//self.scrollView.setContentOffset(CGPoint(), animated: true)
|
//self.scrollView.setContentOffset(CGPoint(), animated: true)
|
||||||
|
|
||||||
@ -329,7 +336,7 @@ final class EmojiSearchSearchBarComponent: Component {
|
|||||||
self.selectedItem = nil
|
self.selectedItem = nil
|
||||||
|
|
||||||
let transition = Transition(animation: .curve(duration: 0.4, curve: .spring))
|
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.updateScrolling(transition: transition, fromScrolling: false)
|
||||||
|
|
||||||
self.state?.updated(transition: transition)
|
self.state?.updated(transition: transition)
|
||||||
@ -544,7 +551,7 @@ final class EmojiSearchSearchBarComponent: Component {
|
|||||||
transition.setFrame(view: self.scrollView, frame: CGRect(origin: CGPoint(), size: availableSize))
|
transition.setFrame(view: self.scrollView, frame: CGRect(origin: CGPoint(), size: availableSize))
|
||||||
}
|
}
|
||||||
if case .active = component.textInputState {
|
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 {
|
if self.scrollView.contentSize != itemLayout.contentSize {
|
||||||
self.scrollView.contentSize = itemLayout.contentSize
|
self.scrollView.contentSize = itemLayout.contentSize
|
||||||
|
|||||||
@ -98,7 +98,15 @@ private class GifVideoLayer: AVSampleBufferDisplayLayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override init(layer: Any) {
|
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) {
|
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) {
|
required init?(coder: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -106,7 +106,7 @@ public final class LottieComponent: Component {
|
|||||||
|
|
||||||
if delay != 0.0 {
|
if delay != 0.0 {
|
||||||
self.isHidden = true
|
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 {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,13 +43,13 @@ final class DataCategoriesComponent: Component {
|
|||||||
let theme: PresentationTheme
|
let theme: PresentationTheme
|
||||||
let strings: PresentationStrings
|
let strings: PresentationStrings
|
||||||
let categories: [CategoryData]
|
let categories: [CategoryData]
|
||||||
let toggleCategoryExpanded: (DataUsageScreenComponent.Category) -> Void
|
let toggleCategoryExpanded: ((DataUsageScreenComponent.Category) -> Void)?
|
||||||
|
|
||||||
init(
|
init(
|
||||||
theme: PresentationTheme,
|
theme: PresentationTheme,
|
||||||
strings: PresentationStrings,
|
strings: PresentationStrings,
|
||||||
categories: [CategoryData],
|
categories: [CategoryData],
|
||||||
toggleCategoryExpanded: @escaping (DataUsageScreenComponent.Category) -> Void
|
toggleCategoryExpanded: ((DataUsageScreenComponent.Category) -> Void)?
|
||||||
) {
|
) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
@ -138,11 +138,11 @@ final class DataCategoriesComponent: Component {
|
|||||||
category: category,
|
category: category,
|
||||||
isExpanded: category.isExpanded,
|
isExpanded: category.isExpanded,
|
||||||
hasNext: i != component.categories.count - 1,
|
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 {
|
guard let self, let component = self.component else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
component.toggleCategoryExpanded(key)
|
component.toggleCategoryExpanded?(key)
|
||||||
}
|
}
|
||||||
)),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
|
|||||||
@ -52,7 +52,7 @@ private final class SubItemComponent: Component {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
class View: HighlightTrackingButton {
|
class View: UIView {
|
||||||
private let iconView: UIImageView
|
private let iconView: UIImageView
|
||||||
private let title = ComponentView<Empty>()
|
private let title = ComponentView<Empty>()
|
||||||
private let titleValue = ComponentView<Empty>()
|
private let titleValue = ComponentView<Empty>()
|
||||||
@ -74,7 +74,7 @@ private final class SubItemComponent: Component {
|
|||||||
|
|
||||||
self.addSubview(self.iconView)
|
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 {
|
guard let self, let component = self.component, let highlightBackgroundFrame = self.highlightBackgroundFrame else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -103,7 +103,7 @@ private final class SubItemComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.addTarget(self, action: #selector(self.pressed), for: .touchUpInside)
|
self.addTarget(self, action: #selector(self.pressed), for: .touchUpInside)
|
||||||
self.isUserInteractionEnabled = false
|
self.isEnabled = false*/
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
@ -243,7 +243,7 @@ final class DataCategoryItemComponent: Component {
|
|||||||
let category: DataCategoriesComponent.CategoryData
|
let category: DataCategoriesComponent.CategoryData
|
||||||
let isExpanded: Bool
|
let isExpanded: Bool
|
||||||
let hasNext: Bool
|
let hasNext: Bool
|
||||||
let action: (DataUsageScreenComponent.Category) -> Void
|
let action: ((DataUsageScreenComponent.Category) -> Void)?
|
||||||
|
|
||||||
init(
|
init(
|
||||||
theme: PresentationTheme,
|
theme: PresentationTheme,
|
||||||
@ -251,7 +251,7 @@ final class DataCategoryItemComponent: Component {
|
|||||||
category: DataCategoriesComponent.CategoryData,
|
category: DataCategoriesComponent.CategoryData,
|
||||||
isExpanded: Bool,
|
isExpanded: Bool,
|
||||||
hasNext: Bool,
|
hasNext: Bool,
|
||||||
action: @escaping (DataUsageScreenComponent.Category) -> Void
|
action: ((DataUsageScreenComponent.Category) -> Void)?
|
||||||
) {
|
) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
@ -350,14 +350,14 @@ final class DataCategoryItemComponent: Component {
|
|||||||
guard let component = self.component else {
|
guard let component = self.component else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
component.action(component.category.key)
|
component.action?(component.category.key)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func checkPressed() {
|
@objc private func checkPressed() {
|
||||||
guard let component = self.component else {
|
guard let component = self.component else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
component.action(component.category.key)
|
component.action?(component.category.key)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
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)))
|
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)
|
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))
|
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 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 {
|
if backButtonNode.isHidden {
|
||||||
backButtonNode.alpha = 0.0
|
backButtonNode.alpha = 0.0
|
||||||
backButtonNode.isHidden = false
|
backButtonNode.isHidden = false
|
||||||
@ -480,7 +482,7 @@ final class DataUsageScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1035,8 +1037,7 @@ final class DataUsageScreenComponent: Component {
|
|||||||
theme: environment.theme,
|
theme: environment.theme,
|
||||||
strings: environment.strings,
|
strings: environment.strings,
|
||||||
categories: totalCategories,
|
categories: totalCategories,
|
||||||
toggleCategoryExpanded: { _ in
|
toggleCategoryExpanded: nil
|
||||||
}
|
|
||||||
)),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: .greatestFiniteMagnitude)
|
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 fractionValue: Double = floor(displayValue * 100.0 * 10.0) / 10.0
|
||||||
let fractionString: String
|
let fractionString: String
|
||||||
if fractionValue == 0.0 {
|
if displayValue == 0.0 {
|
||||||
fractionString = ""
|
fractionString = ""
|
||||||
} else if fractionValue < 0.1 {
|
} else if fractionValue < 0.1 {
|
||||||
fractionString = "<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 {
|
guard let strongSelf = self else {
|
||||||
return
|
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 {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -423,7 +423,7 @@ final class EmojisChatInputContextPanelNode: ChatInputContextPanelNode {
|
|||||||
return nil
|
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 {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,8 +46,8 @@ private struct HorizontalListContextResultsChatInputContextPanelEntry: Comparabl
|
|||||||
return lhs.index < rhs.index
|
return lhs.index < rhs.index
|
||||||
}
|
}
|
||||||
|
|
||||||
func item(account: Account, resultSelected: @escaping (ChatContextResult, ASDisplayNode, CGRect) -> Bool) -> ListViewItem {
|
func item(context: AccountContext, resultSelected: @escaping (ChatContextResult, ASDisplayNode, CGRect) -> Bool) -> ListViewItem {
|
||||||
return HorizontalListContextResultsChatInputPanelItem(account: account, theme: self.theme, result: self.result, resultSelected: resultSelected)
|
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 (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
||||||
|
|
||||||
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
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 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(account: account, 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)
|
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)?
|
var selectedItemNodeAndContent: (UIView, CGRect, PeekControllerContent)?
|
||||||
|
selectedItemNodeAndContent = nil
|
||||||
strongSelf.listView.forEachItemNode { itemNode in
|
strongSelf.listView.forEachItemNode { itemNode in
|
||||||
if itemNode.frame.contains(convertedPoint), let itemNode = itemNode as? HorizontalListContextResultsChatInputPanelItemNode, let item = itemNode.item {
|
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 {
|
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 {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -230,7 +231,7 @@ final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputCont
|
|||||||
f(.default)
|
f(.default)
|
||||||
let _ = item.resultSelected(item.result, itemNode, itemNode.bounds)
|
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 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 {
|
if let strongSelf = self, let interfaceInteraction = strongSelf.interfaceInteraction {
|
||||||
return interfaceInteraction.sendContextResult(results, result, node, rect)
|
return interfaceInteraction.sendContextResult(results, result, node, rect)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -18,15 +18,15 @@ import SoftwareVideo
|
|||||||
import MultiplexedVideoNode
|
import MultiplexedVideoNode
|
||||||
|
|
||||||
final class HorizontalListContextResultsChatInputPanelItem: ListViewItem {
|
final class HorizontalListContextResultsChatInputPanelItem: ListViewItem {
|
||||||
let account: Account
|
let context: AccountContext
|
||||||
let theme: PresentationTheme
|
let theme: PresentationTheme
|
||||||
let result: ChatContextResult
|
let result: ChatContextResult
|
||||||
let resultSelected: (ChatContextResult, ASDisplayNode, CGRect) -> Bool
|
let resultSelected: (ChatContextResult, ASDisplayNode, CGRect) -> Bool
|
||||||
|
|
||||||
let selectable: Bool = true
|
let selectable: Bool = true
|
||||||
|
|
||||||
public init(account: Account, theme: PresentationTheme, result: ChatContextResult, resultSelected: @escaping (ChatContextResult, ASDisplayNode, CGRect) -> Bool) {
|
public init(context: AccountContext, theme: PresentationTheme, result: ChatContextResult, resultSelected: @escaping (ChatContextResult, ASDisplayNode, CGRect) -> Bool) {
|
||||||
self.account = account
|
self.context = context
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.result = result
|
self.result = result
|
||||||
self.resultSelected = resultSelected
|
self.resultSelected = resultSelected
|
||||||
@ -265,9 +265,9 @@ final class HorizontalListContextResultsChatInputPanelItemNode: ListViewItemNode
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let file = videoFile {
|
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 {
|
} else if let imageResource = imageResource {
|
||||||
updatedStatusSignal = item.account.postbox.mediaBox.resourceStatus(imageResource)
|
updatedStatusSignal = item.context.account.postbox.mediaBox.resourceStatus(imageResource)
|
||||||
}
|
}
|
||||||
case let .internalReference(internalReference):
|
case let .internalReference(internalReference):
|
||||||
if let image = internalReference.image {
|
if let image = internalReference.image {
|
||||||
@ -296,12 +296,12 @@ final class HorizontalListContextResultsChatInputPanelItemNode: ListViewItemNode
|
|||||||
if file.isVideo && file.isAnimated {
|
if file.isVideo && file.isAnimated {
|
||||||
videoFile = file
|
videoFile = file
|
||||||
imageResource = nil
|
imageResource = nil
|
||||||
updatedStatusSignal = item.account.postbox.mediaBox.resourceStatus(file.resource)
|
updatedStatusSignal = item.context.account.postbox.mediaBox.resourceStatus(file.resource)
|
||||||
} else if let imageResource = imageResource {
|
} 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 {
|
} 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 updatedImageResource {
|
||||||
if let imageResource = imageResource {
|
if let imageResource = imageResource {
|
||||||
if let stickerFile = stickerFile {
|
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 {
|
} 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 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: [])
|
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 {
|
} else {
|
||||||
updateImageSignal = .complete()
|
updateImageSignal = .complete()
|
||||||
@ -391,7 +391,7 @@ final class HorizontalListContextResultsChatInputPanelItemNode: ListViewItemNode
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let videoFile = videoFile {
|
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)
|
thumbnailLayer.transform = CATransform3DMakeRotation(CGFloat.pi / 2.0, 0.0, 0.0, 1.0)
|
||||||
strongSelf.addSubnode(thumbnailLayer)
|
strongSelf.addSubnode(thumbnailLayer)
|
||||||
let layerHolder = takeSampleBufferLayer()
|
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)
|
layerHolder.layer.transform = CATransform3DMakeRotation(CGFloat.pi / 2.0, 0.0, 0.0, 1.0)
|
||||||
strongSelf.layer.addSublayer(layerHolder.layer)
|
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)
|
strongSelf.videoLayer = (thumbnailLayer, manager, layerHolder)
|
||||||
thumbnailLayer.ready = { [weak thumbnailLayer, weak manager] in
|
thumbnailLayer.ready = { [weak thumbnailLayer, weak manager] in
|
||||||
if let strongSelf = self, let thumbnailLayer = thumbnailLayer, let manager = manager {
|
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 dimensions = animatedStickerFile.dimensions ?? PixelDimensions(width: 512, height: 512)
|
||||||
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))
|
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())
|
strongSelf.fetchDisposable.set(freeMediaFileResourceInteractiveFetched(account: item.context.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)
|
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 {
|
guard let strongSelf = self else {
|
||||||
return
|
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 {
|
guard let strongSelf = self, let controllerInteraction = strongSelf.getControllerInteraction?() else {
|
||||||
return
|
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 {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user