diff --git a/submodules/Components/ReactionImageComponent/Sources/ReactionImageComponent.swift b/submodules/Components/ReactionImageComponent/Sources/ReactionImageComponent.swift index ec616175cb..9e243dfc6f 100644 --- a/submodules/Components/ReactionImageComponent/Sources/ReactionImageComponent.swift +++ b/submodules/Components/ReactionImageComponent/Sources/ReactionImageComponent.swift @@ -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() } diff --git a/submodules/Components/ReactionListContextMenuContent/Sources/ReactionListContextMenuContent.swift b/submodules/Components/ReactionListContextMenuContent/Sources/ReactionListContextMenuContent.swift index 7e57f68429..9a518fb453 100644 --- a/submodules/Components/ReactionListContextMenuContent/Sources/ReactionListContextMenuContent.swift +++ b/submodules/Components/ReactionListContextMenuContent/Sources/ReactionListContextMenuContent.swift @@ -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) } diff --git a/submodules/PeerInfoUI/Sources/ItemListReactionItem.swift b/submodules/PeerInfoUI/Sources/ItemListReactionItem.swift index a0a88cea78..75d8a7f12a 100644 --- a/submodules/PeerInfoUI/Sources/ItemListReactionItem.swift +++ b/submodules/PeerInfoUI/Sources/ItemListReactionItem.swift @@ -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) } diff --git a/submodules/SettingsUI/Sources/Reactions/QuickReactionSetupController.swift b/submodules/SettingsUI/Sources/Reactions/QuickReactionSetupController.swift index 9b5258a10b..dde966f0e8 100644 --- a/submodules/SettingsUI/Sources/Reactions/QuickReactionSetupController.swift +++ b/submodules/SettingsUI/Sources/Reactions/QuickReactionSetupController.swift @@ -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 diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift index b37277561d..31a1ef3a33 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift @@ -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) }