mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
bfb7fb0cec
@ -65,7 +65,7 @@ public final class ReactionImageNode: ASDisplayNode {
|
||||
|
||||
private let iconNode: ASImageNode
|
||||
|
||||
public init(context: AccountContext, availableReactions: AvailableReactions?, reaction: String) {
|
||||
public init(context: AccountContext, availableReactions: AvailableReactions?, reaction: String, displayPixelSize: CGSize) {
|
||||
self.iconNode = ASImageNode()
|
||||
|
||||
var file: TelegramMediaFile?
|
||||
@ -80,8 +80,8 @@ public final class ReactionImageNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
if let animationFile = animationFile {
|
||||
self.size = animationFile.dimensions?.cgSize ?? CGSize(width: 32.0, height: 32.0)
|
||||
var displaySize = self.size.aspectFitted(CGSize(width: 20.0, height: 20.0))
|
||||
self.size = animationFile.dimensions?.cgSize ?? displayPixelSize
|
||||
var displaySize = self.size.aspectFitted(displayPixelSize)
|
||||
displaySize.width = floor(displaySize.width * 2.0)
|
||||
displaySize.height = floor(displaySize.height * 2.0)
|
||||
self.isAnimation = true
|
||||
@ -101,7 +101,7 @@ public final class ReactionImageNode: ASDisplayNode {
|
||||
}
|
||||
})
|
||||
} else if let file = file {
|
||||
self.size = file.dimensions?.cgSize ?? CGSize(width: 32.0, height: 32.0)
|
||||
self.size = file.dimensions?.cgSize ?? displayPixelSize
|
||||
self.isAnimation = false
|
||||
|
||||
super.init()
|
||||
@ -119,7 +119,7 @@ public final class ReactionImageNode: ASDisplayNode {
|
||||
}
|
||||
})
|
||||
} else {
|
||||
self.size = CGSize(width: 32.0, height: 32.0)
|
||||
self.size = displayPixelSize
|
||||
self.isAnimation = false
|
||||
super.init()
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent
|
||||
self.titleLabelNode.isUserInteractionEnabled = false
|
||||
|
||||
if let reaction = reaction {
|
||||
self.reactionIconNode = ReactionImageNode(context: context, availableReactions: availableReactions, reaction: reaction)
|
||||
self.reactionIconNode = ReactionImageNode(context: context, availableReactions: availableReactions, reaction: reaction, displayPixelSize: CGSize(width: 30.0 * UIScreenScale, height: 30.0 * UIScreenScale))
|
||||
self.reactionIconNode?.isUserInteractionEnabled = false
|
||||
self.iconNode = nil
|
||||
} else {
|
||||
@ -354,7 +354,7 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent
|
||||
let reaction: String? = item.reaction
|
||||
if let reaction = reaction {
|
||||
if self.reactionIconNode == nil {
|
||||
let reactionIconNode = ReactionImageNode(context: self.context, availableReactions: self.availableReactions, reaction: reaction)
|
||||
let reactionIconNode = ReactionImageNode(context: self.context, availableReactions: self.availableReactions, reaction: reaction, displayPixelSize: CGSize(width: 30.0 * UIScreenScale, height: 30.0 * UIScreenScale))
|
||||
self.reactionIconNode = reactionIconNode
|
||||
self.addSubnode(reactionIconNode)
|
||||
}
|
||||
|
@ -504,6 +504,17 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
|
||||
)
|
||||
|
||||
if let reactionContextNode = self.reactionContextNode {
|
||||
let reactionsPositionDeltaYDistance = -animationInContentDistance
|
||||
reactionContextNode.layer.animateSpring(
|
||||
from: NSValue(cgPoint: CGPoint(x: 0.0, y: reactionsPositionDeltaYDistance)),
|
||||
to: NSValue(cgPoint: CGPoint()),
|
||||
keyPath: "position",
|
||||
duration: duration,
|
||||
delay: 0.0,
|
||||
initialVelocity: 0.0,
|
||||
damping: springDamping,
|
||||
additive: true
|
||||
)
|
||||
reactionContextNode.animateIn(from: currentContentScreenFrame)
|
||||
}
|
||||
|
||||
|
@ -359,7 +359,7 @@ public class ItemListReactionItemNode: ListViewItemNode, ItemListItemNode {
|
||||
}
|
||||
|
||||
if strongSelf.imageNode == nil, let availableReactions = item.availableReactions {
|
||||
let imageNode = ReactionImageNode(context: item.context, availableReactions: availableReactions, reaction: item.reaction)
|
||||
let imageNode = ReactionImageNode(context: item.context, availableReactions: availableReactions, reaction: item.reaction, displayPixelSize: CGSize(width: 30.0 * UIScreenScale, height: 30.0 * UIScreenScale))
|
||||
strongSelf.imageNode = imageNode
|
||||
strongSelf.addSubnode(imageNode)
|
||||
}
|
||||
|
@ -606,7 +606,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
intermediateCompletion()
|
||||
}
|
||||
|
||||
transition.animatePositionWithKeyframes(node: itemNode, keyframes: generateParabollicMotionKeyframes(from: selfSourceRect.center, to: expandedFrame.center, elevation: 30.0), completion: { [weak self, weak itemNode, weak targetView] _ in
|
||||
transition.animatePositionWithKeyframes(node: itemNode, keyframes: generateParabollicMotionKeyframes(from: selfSourceRect.center, to: expandedFrame.center, elevation: 30.0), completion: { [weak self, weak itemNode, weak targetView, weak animateTargetContainer] _ in
|
||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1, execute: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -620,7 +620,11 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
guard let targetView = targetView as? ReactionIconView else {
|
||||
return
|
||||
}
|
||||
if let animateTargetContainer = animateTargetContainer {
|
||||
animateTargetContainer.isHidden = false
|
||||
}
|
||||
targetView.isHidden = false
|
||||
targetView.alpha = 1.0
|
||||
targetView.imageView.alpha = 0.0
|
||||
targetView.addSubnode(itemNode)
|
||||
itemNode.frame = targetView.bounds
|
||||
|
@ -11,6 +11,7 @@ import ItemListUI
|
||||
import PresentationDataUtils
|
||||
import AccountContext
|
||||
import ReactionImageComponent
|
||||
import WebPBinding
|
||||
|
||||
private final class QuickReactionSetupControllerArguments {
|
||||
let context: AccountContext
|
||||
@ -46,7 +47,7 @@ private enum QuickReactionSetupControllerEntry: ItemListNodeEntry {
|
||||
case demoMessage(wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, bubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, availableReactions: AvailableReactions?, reaction: String?)
|
||||
case demoDescription(String)
|
||||
case itemsHeader(String)
|
||||
case item(index: Int, value: String, image: UIImage?, text: String, isSelected: Bool)
|
||||
case item(index: Int, value: String, image: UIImage?, imageIsAnimation: Bool, text: String, isSelected: Bool)
|
||||
|
||||
var section: ItemListSectionId {
|
||||
switch self {
|
||||
@ -67,7 +68,7 @@ private enum QuickReactionSetupControllerEntry: ItemListNodeEntry {
|
||||
return .demoDescription
|
||||
case .itemsHeader:
|
||||
return .itemsHeader
|
||||
case let .item(_, value, _, _, _):
|
||||
case let .item(_, value, _, _, _, _):
|
||||
return .item(value)
|
||||
}
|
||||
}
|
||||
@ -82,7 +83,7 @@ private enum QuickReactionSetupControllerEntry: ItemListNodeEntry {
|
||||
return 2
|
||||
case .itemsHeader:
|
||||
return 3
|
||||
case let .item(index, _, _, _, _):
|
||||
case let .item(index, _, _, _, _, _):
|
||||
return 100 + index
|
||||
}
|
||||
}
|
||||
@ -113,8 +114,8 @@ private enum QuickReactionSetupControllerEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .item(index, value, file, text, isEnabled):
|
||||
if case .item(index, value, file, text, isEnabled) = rhs {
|
||||
case let .item(index, value, file, imageIsAnimation, text, isEnabled):
|
||||
if case .item(index, value, file, imageIsAnimation, text, isEnabled) = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -152,11 +153,16 @@ private enum QuickReactionSetupControllerEntry: ItemListNodeEntry {
|
||||
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
|
||||
case let .itemsHeader(text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .item(_, value, image, text, isSelected):
|
||||
case let .item(_, value, image, imageIsAnimation, text, isSelected):
|
||||
var imageFitSize = CGSize(width: 30.0, height: 30.0)
|
||||
if imageIsAnimation {
|
||||
imageFitSize.width = floor(imageFitSize.width * 2.0)
|
||||
imageFitSize.height = floor(imageFitSize.height * 2.0)
|
||||
}
|
||||
return ItemListCheckboxItem(
|
||||
presentationData: presentationData,
|
||||
icon: image,
|
||||
iconSize: image?.size.aspectFitted(CGSize(width: 30.0, height: 30.0)),
|
||||
iconSize: image?.size.aspectFitted(imageFitSize),
|
||||
title: text,
|
||||
style: .right,
|
||||
color: .accent,
|
||||
@ -178,7 +184,7 @@ private struct QuickReactionSetupControllerState: Equatable {
|
||||
private func quickReactionSetupControllerEntries(
|
||||
presentationData: PresentationData,
|
||||
availableReactions: AvailableReactions?,
|
||||
images: [String: UIImage],
|
||||
images: [String: (image: UIImage, isAnimation: Bool)],
|
||||
reactionSettings: ReactionSettings,
|
||||
state: QuickReactionSetupControllerState
|
||||
) -> [QuickReactionSetupControllerEntry] {
|
||||
@ -207,7 +213,8 @@ private func quickReactionSetupControllerEntries(
|
||||
entries.append(.item(
|
||||
index: index,
|
||||
value: availableReaction.value,
|
||||
image: images[availableReaction.value],
|
||||
image: images[availableReaction.value]?.image,
|
||||
imageIsAnimation: images[availableReaction.value]?.isAnimation ?? false,
|
||||
text: availableReaction.title,
|
||||
isSelected: reactionSettings.quickReaction == availableReaction.value
|
||||
))
|
||||
@ -263,39 +270,53 @@ public func quickReactionSetupController(
|
||||
return reactionSettings
|
||||
}
|
||||
|
||||
let images: Signal<[String: UIImage], NoError> = context.engine.stickers.availableReactions()
|
||||
|> mapToSignal { availableReactions -> Signal<[String: UIImage], NoError> in
|
||||
var signals: [Signal<(String, UIImage?), NoError>] = []
|
||||
let images: Signal<[String: (image: UIImage, isAnimation: Bool)], NoError> = context.engine.stickers.availableReactions()
|
||||
|> mapToSignal { availableReactions -> Signal<[String: (image: UIImage, isAnimation: Bool)], NoError> in
|
||||
var signals: [Signal<(String, (image: UIImage, isAnimation: Bool)?), NoError>] = []
|
||||
|
||||
if let availableReactions = availableReactions {
|
||||
for availableReaction in availableReactions.reactions {
|
||||
if !availableReaction.isEnabled {
|
||||
continue
|
||||
}
|
||||
guard let centerAnimation = availableReaction.centerAnimation else {
|
||||
continue
|
||||
if let centerAnimation = availableReaction.centerAnimation {
|
||||
let signal: Signal<(String, (image: UIImage, isAnimation: Bool)?), NoError> = reactionStaticImage(context: context, animation: centerAnimation, pixelSize: CGSize(width: 72.0 * 2.0, height: 72.0 * 2.0))
|
||||
|> map { data -> (String, (image: UIImage, isAnimation: Bool)?) in
|
||||
guard data.isComplete else {
|
||||
return (availableReaction.value, nil)
|
||||
}
|
||||
guard let dataValue = try? Data(contentsOf: URL(fileURLWithPath: data.path)) else {
|
||||
return (availableReaction.value, nil)
|
||||
}
|
||||
guard let image = UIImage(data: dataValue) else {
|
||||
return (availableReaction.value, nil)
|
||||
}
|
||||
return (availableReaction.value, (image, true))
|
||||
}
|
||||
signals.append(signal)
|
||||
} else {
|
||||
let signal: Signal<(String, (image: UIImage, isAnimation: Bool)?), NoError> = context.account.postbox.mediaBox.resourceData(availableReaction.staticIcon.resource)
|
||||
|> map { data -> (String, (image: UIImage, isAnimation: Bool)?) in
|
||||
guard data.complete else {
|
||||
return (availableReaction.value, nil)
|
||||
}
|
||||
guard let dataValue = try? Data(contentsOf: URL(fileURLWithPath: data.path)) else {
|
||||
return (availableReaction.value, nil)
|
||||
}
|
||||
guard let image = WebP.convert(fromWebP: dataValue) else {
|
||||
return (availableReaction.value, nil)
|
||||
}
|
||||
|
||||
return (availableReaction.value, (image, false))
|
||||
}
|
||||
signals.append(signal)
|
||||
}
|
||||
|
||||
let signal: Signal<(String, UIImage?), NoError> = reactionStaticImage(context: context, animation: centerAnimation, pixelSize: CGSize(width: 72.0, height: 72.0))
|
||||
|> map { data -> (String, UIImage?) in
|
||||
guard data.isComplete else {
|
||||
return (availableReaction.value, nil)
|
||||
}
|
||||
guard let dataValue = try? Data(contentsOf: URL(fileURLWithPath: data.path)) else {
|
||||
return (availableReaction.value, nil)
|
||||
}
|
||||
guard let image = UIImage(data: dataValue) else {
|
||||
return (availableReaction.value, nil)
|
||||
}
|
||||
return (availableReaction.value, image)
|
||||
}
|
||||
signals.append(signal)
|
||||
}
|
||||
}
|
||||
|
||||
return combineLatest(queue: .mainQueue(), signals)
|
||||
|> map { values -> [String: UIImage] in
|
||||
var dict: [String: UIImage] = [:]
|
||||
|> map { values -> [String: (image: UIImage, isAnimation: Bool)] in
|
||||
var dict: [String: (image: UIImage, isAnimation: Bool)] = [:]
|
||||
for (key, image) in values {
|
||||
if let image = image {
|
||||
dict[key] = image
|
||||
|
@ -2097,7 +2097,13 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
||||
case .center:
|
||||
let availableWidth = params.width - params.leftInset - params.rightInset
|
||||
backgroundFrame = CGRect(origin: CGPoint(x: params.leftInset + floor((availableWidth - layoutBubbleSize.width) / 2.0), y: 0.0), size: layoutBubbleSize)
|
||||
contentOrigin = CGPoint(x: backgroundFrame.minX + floor(layoutConstants.bubble.contentInsets.right + layoutConstants.bubble.contentInsets.left) / 2.0, y: backgroundFrame.minY + layoutConstants.bubble.contentInsets.top + headerSize.height + contentVerticalOffset)
|
||||
let contentOriginX: CGFloat
|
||||
if !hideBackground {
|
||||
contentOriginX = (incoming ? layoutConstants.bubble.contentInsets.left : layoutConstants.bubble.contentInsets.right)
|
||||
} else {
|
||||
contentOriginX = floor(layoutConstants.bubble.contentInsets.right + layoutConstants.bubble.contentInsets.left) / 2.0
|
||||
}
|
||||
contentOrigin = CGPoint(x: backgroundFrame.minX + contentOriginX, y: backgroundFrame.minY + layoutConstants.bubble.contentInsets.top + headerSize.height + contentVerticalOffset)
|
||||
contentUpperRightCorner = CGPoint(x: backgroundFrame.maxX - (incoming ? layoutConstants.bubble.contentInsets.right : layoutConstants.bubble.contentInsets.left), y: backgroundFrame.origin.y + layoutConstants.bubble.contentInsets.top + headerSize.height)
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user