diff --git a/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift b/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift index 73d9d2f377..ed61cd02ab 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift @@ -160,6 +160,8 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: } case let poll as TelegramMediaPoll: messageText = "📊 \(poll.text)" + case _ as TelegramMediaDice: + messageText = "🎲" default: break } diff --git a/submodules/GraphCore/Sources/Charts/Controllers/Lines/BaseLinesChartController.swift b/submodules/GraphCore/Sources/Charts/Controllers/Lines/BaseLinesChartController.swift index 39f9a4f31d..659acd35bb 100644 --- a/submodules/GraphCore/Sources/Charts/Controllers/Lines/BaseLinesChartController.swift +++ b/submodules/GraphCore/Sources/Charts/Controllers/Lines/BaseLinesChartController.swift @@ -30,9 +30,9 @@ public class BaseLinesChartController: BaseChartController { func setupChartCollection(chartsCollection: ChartsCollection, animated: Bool, isZoomed: Bool) { if animated { - TimeInterval.setDefaultSuration(.expandAnimationDuration) + TimeInterval.setDefaultDuration(.expandAnimationDuration) DispatchQueue.main.asyncAfter(deadline: .now() + .expandAnimationDuration) { - TimeInterval.setDefaultSuration(.osXDuration) + TimeInterval.setDefaultDuration(.osXDuration) } } diff --git a/submodules/GraphCore/Sources/Charts/Controllers/Percent And Pie/PercentPieChartController.swift b/submodules/GraphCore/Sources/Charts/Controllers/Percent And Pie/PercentPieChartController.swift index 8630c9b23b..ba15c7dc2b 100644 --- a/submodules/GraphCore/Sources/Charts/Controllers/Percent And Pie/PercentPieChartController.swift +++ b/submodules/GraphCore/Sources/Charts/Controllers/Percent And Pie/PercentPieChartController.swift @@ -104,9 +104,9 @@ public class PercentPieChartController: BaseChartController { func switchToChart(chartsCollection: ChartsCollection, isZoomed: Bool, animated: Bool) { if animated { - TimeInterval.setDefaultSuration(.expandAnimationDuration) + TimeInterval.setDefaultDuration(.expandAnimationDuration) DispatchQueue.main.asyncAfter(deadline: .now() + .expandAnimationDuration) { - TimeInterval.setDefaultSuration(.osXDuration) + TimeInterval.setDefaultDuration(.osXDuration) } } diff --git a/submodules/GraphCore/Sources/Charts/Controllers/Percent And Pie/PieChartComponentController.swift b/submodules/GraphCore/Sources/Charts/Controllers/Percent And Pie/PieChartComponentController.swift index 043c39a4bd..1cd7aa4ce4 100644 --- a/submodules/GraphCore/Sources/Charts/Controllers/Percent And Pie/PieChartComponentController.swift +++ b/submodules/GraphCore/Sources/Charts/Controllers/Percent And Pie/PieChartComponentController.swift @@ -168,19 +168,10 @@ class PieChartComponentController: GeneralChartComponentController { override var currentPreviewRangeRenderer: BaseChartRenderer { return previewBarChartRenderer } - - var lastInteractionPoint: CGPoint = .zero + public override func chartInteractionDidBegin(point: CGPoint) { - lastInteractionPoint = point - } - - public override func chartInteractionDidEnd() { - if let segment = pieChartRenderer.selectedItemIndex(at: lastInteractionPoint) { - if pieChartRenderer.selectedSegment == segment { - pieChartRenderer.selectSegmentAt(at: nil, animated: true) - } else { - pieChartRenderer.selectSegmentAt(at: segment, animated: true) - } + if let segment = pieChartRenderer.selectedItemIndex(at: point) { + pieChartRenderer.selectSegmentAt(at: segment, animated: true) updateSelectedDataLabelIfNeeded() } } diff --git a/submodules/GraphCore/Sources/Charts/Controllers/Stacked Bars/DailyBarsChartController.swift b/submodules/GraphCore/Sources/Charts/Controllers/Stacked Bars/DailyBarsChartController.swift index eab355c820..a2a66b00f5 100644 --- a/submodules/GraphCore/Sources/Charts/Controllers/Stacked Bars/DailyBarsChartController.swift +++ b/submodules/GraphCore/Sources/Charts/Controllers/Stacked Bars/DailyBarsChartController.swift @@ -89,9 +89,9 @@ public class DailyBarsChartController: BaseChartController { func switchToChart(chartsCollection: ChartsCollection, isZoomed: Bool, animated: Bool) { if animated { - TimeInterval.setDefaultSuration(.expandAnimationDuration) + TimeInterval.setDefaultDuration(.expandAnimationDuration) DispatchQueue.main.asyncAfter(deadline: .now() + .expandAnimationDuration) { - TimeInterval.setDefaultSuration(.osXDuration) + TimeInterval.setDefaultDuration(.osXDuration) } } diff --git a/submodules/GraphCore/Sources/Charts/Controllers/Stacked Bars/StackedBarsChartController.swift b/submodules/GraphCore/Sources/Charts/Controllers/Stacked Bars/StackedBarsChartController.swift index 5072728098..ef9784db36 100644 --- a/submodules/GraphCore/Sources/Charts/Controllers/Stacked Bars/StackedBarsChartController.swift +++ b/submodules/GraphCore/Sources/Charts/Controllers/Stacked Bars/StackedBarsChartController.swift @@ -90,9 +90,9 @@ public class StackedBarsChartController: BaseChartController { func switchToChart(chartsCollection: ChartsCollection, isZoomed: Bool, animated: Bool) { if animated { - TimeInterval.setDefaultSuration(.expandAnimationDuration) + TimeInterval.setDefaultDuration(.expandAnimationDuration) DispatchQueue.main.asyncAfter(deadline: .now() + .expandAnimationDuration) { - TimeInterval.setDefaultSuration(.osXDuration) + TimeInterval.setDefaultDuration(.osXDuration) } } @@ -119,8 +119,8 @@ public class StackedBarsChartController: BaseChartController { barsController.willDisappear(animated: animated) zoomedBarsController.updateChartsVisibility(visibility: barsController.chartVisibility, animated: false) - zoomedBarsController.mainBarsRenderer.setup(verticalRange: zoomedBarsController.currentVerticalMainChartRange, animated: animated, timeFunction: .easeOut) - zoomedBarsController.previewBarsChartRenderer.setup(verticalRange: zoomedBarsController.currentPreviewVerticalRange, animated: animated, timeFunction: .easeOut) + zoomedBarsController.mainBarsRenderer.setup(verticalRange: zoomedBarsController.currentVerticalMainChartRange, animated: animated, timeFunction: .easeInOut) + zoomedBarsController.previewBarsChartRenderer.setup(verticalRange: zoomedBarsController.currentPreviewVerticalRange, animated: animated, timeFunction: .easeInOut) } else { if !zoomedBarsController.chartsCollection.isBlank { barsController.hideDetailsView(animated: false) @@ -135,8 +135,8 @@ public class StackedBarsChartController: BaseChartController { let targetVerticalRange = verticalVisibleRange.lowerBound...(verticalVisibleRange.upperBound + verticalVisibleRange.distance * 10) zoomedBarsController.setupMainChart(horizontalRange: toHorizontalRange, animated: animated) - zoomedBarsController.mainBarsRenderer.setup(verticalRange: targetVerticalRange, animated: animated, timeFunction: .easeIn) - zoomedBarsController.previewBarsChartRenderer.setup(verticalRange: targetVerticalRange, animated: animated, timeFunction: .easeIn) + zoomedBarsController.mainBarsRenderer.setup(verticalRange: targetVerticalRange, animated: animated, timeFunction: .easeInOut) + zoomedBarsController.previewBarsChartRenderer.setup(verticalRange: targetVerticalRange, animated: animated, timeFunction: .easeInOut) zoomedBarsController.previewBarsChartRenderer.setup(horizontalRange: barsController.totalHorizontalRange, animated: animated) DispatchQueue.main.asyncAfter(deadline: .now() + .defaultDuration) { [weak self] in self?.zoomedBarsController.mainBarsRenderer.setVisible(false, animated: false) diff --git a/submodules/GraphCore/Sources/Charts/Controllers/Stacked Bars/StepBarsChartController.swift b/submodules/GraphCore/Sources/Charts/Controllers/Stacked Bars/StepBarsChartController.swift index 6dce06be66..3780448886 100644 --- a/submodules/GraphCore/Sources/Charts/Controllers/Stacked Bars/StepBarsChartController.swift +++ b/submodules/GraphCore/Sources/Charts/Controllers/Stacked Bars/StepBarsChartController.swift @@ -97,9 +97,9 @@ public class StepBarsChartController: BaseChartController { func switchToChart(chartsCollection: ChartsCollection, isZoomed: Bool, animated: Bool) { if animated { - TimeInterval.setDefaultSuration(.expandAnimationDuration) + TimeInterval.setDefaultDuration(.expandAnimationDuration) DispatchQueue.main.asyncAfter(deadline: .now() + .expandAnimationDuration) { - TimeInterval.setDefaultSuration(.osXDuration) + TimeInterval.setDefaultDuration(.osXDuration) } } @@ -126,8 +126,8 @@ public class StepBarsChartController: BaseChartController { barsController.willDisappear(animated: animated) zoomedBarsController.updateChartsVisibility(visibility: barsController.chartVisibility, animated: false) - zoomedBarsController.mainBarsRenderer.setup(verticalRange: zoomedBarsController.currentVerticalMainChartRange, animated: animated, timeFunction: .easeOut) - zoomedBarsController.previewBarsChartRenderer.setup(verticalRange: zoomedBarsController.currentPreviewVerticalRange, animated: animated, timeFunction: .easeOut) + zoomedBarsController.mainBarsRenderer.setup(verticalRange: zoomedBarsController.currentVerticalMainChartRange, animated: animated, timeFunction: .easeInOut) + zoomedBarsController.previewBarsChartRenderer.setup(verticalRange: zoomedBarsController.currentPreviewVerticalRange, animated: animated, timeFunction: .easeInOut) } else { if !zoomedBarsController.chartsCollection.isBlank { barsController.hideDetailsView(animated: false) @@ -143,8 +143,8 @@ public class StepBarsChartController: BaseChartController { let targetVerticalRange = verticalVisibleRange.lowerBound...(verticalVisibleRange.upperBound + verticalVisibleRange.distance * 10) zoomedBarsController.setupMainChart(horizontalRange: toHorizontalRange, animated: animated) - zoomedBarsController.mainBarsRenderer.setup(verticalRange: targetVerticalRange, animated: animated, timeFunction: .easeIn) - zoomedBarsController.previewBarsChartRenderer.setup(verticalRange: targetVerticalRange, animated: animated, timeFunction: .easeIn) + zoomedBarsController.mainBarsRenderer.setup(verticalRange: targetVerticalRange, animated: animated, timeFunction: .easeInOut) + zoomedBarsController.previewBarsChartRenderer.setup(verticalRange: targetVerticalRange, animated: animated, timeFunction: .easeInOut) zoomedBarsController.previewBarsChartRenderer.setup(horizontalRange: barsController.totalHorizontalRange, animated: animated) DispatchQueue.main.asyncAfter(deadline: .now() + .defaultDuration) { [weak self] in self?.zoomedBarsController.mainBarsRenderer.setVisible(false, animated: false) diff --git a/submodules/GraphCore/Sources/Charts/Controllers/Stacked Bars/TwoAxisStepBarsChartController.swift b/submodules/GraphCore/Sources/Charts/Controllers/Stacked Bars/TwoAxisStepBarsChartController.swift index 075c1bf4a2..a1483a51ab 100644 --- a/submodules/GraphCore/Sources/Charts/Controllers/Stacked Bars/TwoAxisStepBarsChartController.swift +++ b/submodules/GraphCore/Sources/Charts/Controllers/Stacked Bars/TwoAxisStepBarsChartController.swift @@ -87,8 +87,11 @@ public class TwoAxisStepBarsChartController: BaseLinesChartController { controller.verticalScalesRenderer.isRightAligned = (index != 0) controller.verticalScalesRenderer.isEnabled = true } else { - controller.mainBarsRenderer.bars = BarChartRenderer.BarsData(barWidth: 0.0, locations: [], components: []) - controller.previewBarsRenderer.bars = BarChartRenderer.BarsData(barWidth: 0.0, locations: [], components: []) + let emptyBars = BarChartRenderer.BarsData(barWidth: 0.0, locations: [], components: []) + controller.chartBars = emptyBars + controller.barsWidth = emptyBars.barWidth + controller.mainBarsRenderer.bars = emptyBars + controller.previewBarsRenderer.bars = emptyBars } } @@ -119,9 +122,7 @@ public class TwoAxisStepBarsChartController: BaseLinesChartController { public override var mainChartRenderers: [ChartViewRenderer] { return graphControllers.map { $0.mainBarsRenderer } + graphControllers.flatMap { [$0.verticalScalesRenderer, $0.lineBulletsRenderer] } + - [horizontalScalesRenderer, verticalLineRenderer, -// performanceRenderer - ] + [horizontalScalesRenderer, verticalLineRenderer] } public override var navigationRenderers: [ChartViewRenderer] { diff --git a/submodules/GraphCore/Sources/Charts/Renderes/LineBulletsRenerer.swift b/submodules/GraphCore/Sources/Charts/Renderes/LineBulletsRenderer.swift similarity index 94% rename from submodules/GraphCore/Sources/Charts/Renderes/LineBulletsRenerer.swift rename to submodules/GraphCore/Sources/Charts/Renderes/LineBulletsRenderer.swift index 8e42ef7e8b..1fb94be416 100644 --- a/submodules/GraphCore/Sources/Charts/Renderes/LineBulletsRenerer.swift +++ b/submodules/GraphCore/Sources/Charts/Renderes/LineBulletsRenderer.swift @@ -45,7 +45,9 @@ class LineBulletsRenderer: BaseChartRenderer { var bulletRadius: CGFloat = 6 func setLineVisible(_ isVisible: Bool, at index: Int, animated: Bool) { - alphaAnimators[index].animate(to: isVisible ? 1 : 0, duration: animated ? .defaultDuration : 0) + if alphaAnimators.count > index { + alphaAnimators[index].animate(to: isVisible ? 1 : 0, duration: animated ? .defaultDuration : 0) + } } override func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) { diff --git a/submodules/GraphCore/Sources/Charts/Renderes/LinesChartRenderer.swift b/submodules/GraphCore/Sources/Charts/Renderes/LinesChartRenderer.swift index 1419af9676..b974f7ae51 100644 --- a/submodules/GraphCore/Sources/Charts/Renderes/LinesChartRenderer.swift +++ b/submodules/GraphCore/Sources/Charts/Renderes/LinesChartRenderer.swift @@ -50,7 +50,9 @@ class LinesChartRenderer: BaseChartRenderer { } func setLineVisible(_ isVisible: Bool, at index: Int, animated: Bool) { - linesAlphaAnimators[index].animate(to: isVisible ? 1 : 0, duration: animated ? .defaultDuration : 0) + if linesAlphaAnimators.count > index { + linesAlphaAnimators[index].animate(to: isVisible ? 1 : 0, duration: animated ? .defaultDuration : 0) + } } override func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) { diff --git a/submodules/GraphCore/Sources/Charts/Renderes/VerticalLinesRenderer.swift b/submodules/GraphCore/Sources/Charts/Renderes/VerticalLinesRenderer.swift index f1c1a08cfa..805cb917c4 100644 --- a/submodules/GraphCore/Sources/Charts/Renderes/VerticalLinesRenderer.swift +++ b/submodules/GraphCore/Sources/Charts/Renderes/VerticalLinesRenderer.swift @@ -27,7 +27,9 @@ class VerticalLinesRenderer: BaseChartRenderer { var linesWidth: CGFloat = GView.oneDevicePixel func setLineVisible(_ isVisible: Bool, at index: Int, animated: Bool) { - alphaAnimators[index].animate(to: isVisible ? 1 : 0, duration: animated ? .defaultDuration : 0) + if alphaAnimators.count > index { + alphaAnimators[index].animate(to: isVisible ? 1 : 0, duration: animated ? .defaultDuration : 0) + } } override func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) { diff --git a/submodules/GraphCore/Sources/Helpers/AnimationController.swift b/submodules/GraphCore/Sources/Helpers/AnimationController.swift index 3b5b25a5f2..08a9970137 100644 --- a/submodules/GraphCore/Sources/Helpers/AnimationController.swift +++ b/submodules/GraphCore/Sources/Helpers/AnimationController.swift @@ -21,6 +21,7 @@ enum TimeFunction { case linear case easeOut case easeIn + case easeInOut func profress(time: TimeInterval, duration: TimeInterval) -> TimeInterval { switch self { @@ -30,12 +31,19 @@ enum TimeFunction { return (pow(2, 10 * (time / duration - 1)) - 0.0009765625) * 1.0009775171065499 case .easeOut: return (-pow(2, -10 * time / duration)) + 1 * 1.0009775171065499 + case .easeInOut: + let x = time / duration + if x < 1 / 2 { + return 4 * x * x * x + } else { + let f = 2 * x - 2 + return 1 / 2 * f * f * f + 1 + } } } } class AnimationController { - private(set) var isAnimating: Bool = false private(set) var animationDuration: TimeInterval = 0.0 private(set) var currentTime: TimeInterval = 0.0 @@ -44,7 +52,7 @@ class AnimationController { private(set) var end: AnimatableObject private(set) var current: AnimatableObject - var timeFunction: TimeFunction = .linear + var timeFunction: TimeFunction = .easeInOut var refreshClosure: (() -> Void)? // var updateClosure: ((AnimatableObject) -> Void)? @@ -57,7 +65,7 @@ class AnimationController { self.refreshClosure = refreshClosure } - func animate(to: AnimatableObject, duration: TimeInterval, timeFunction: TimeFunction = .linear) { + func animate(to: AnimatableObject, duration: TimeInterval, timeFunction: TimeFunction = .easeInOut) { self.timeFunction = timeFunction currentTime = 0 animationDuration = duration diff --git a/submodules/GraphCore/Sources/Helpers/TimeInterval+Utils.swift b/submodules/GraphCore/Sources/Helpers/TimeInterval+Utils.swift index 2daddaef56..5304cae2e8 100644 --- a/submodules/GraphCore/Sources/Helpers/TimeInterval+Utils.swift +++ b/submodules/GraphCore/Sources/Helpers/TimeInterval+Utils.swift @@ -26,7 +26,7 @@ public extension TimeInterval { } private static var innerDefaultDuration: TimeInterval = osXDuration - static func setDefaultSuration(_ duration: TimeInterval) { + static func setDefaultDuration(_ duration: TimeInterval) { innerDefaultDuration = duration } } diff --git a/submodules/StatisticsUI/Sources/StatsController.swift b/submodules/StatisticsUI/Sources/StatsController.swift index f9b61a11af..8c8c6d2f76 100644 --- a/submodules/StatisticsUI/Sources/StatsController.swift +++ b/submodules/StatisticsUI/Sources/StatsController.swift @@ -412,7 +412,7 @@ private func statsControllerEntries(data: ChannelStats?, messages: [Message]?, i if !data.instantPageInteractionsGraph.isEmpty { entries.append(.instantPageInteractionsTitle(presentationData.theme, presentationData.strings.Stats_InstantViewInteractionsTitle)) - entries.append(.instantPageInteractionsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.instantPageInteractionsGraph, .step)) + entries.append(.instantPageInteractionsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.instantPageInteractionsGraph, .twoAxisStep)) } } diff --git a/submodules/StatisticsUI/Sources/StatsMessageItem.swift b/submodules/StatisticsUI/Sources/StatsMessageItem.swift index 521162c7aa..4d5c8fde37 100644 --- a/submodules/StatisticsUI/Sources/StatsMessageItem.swift +++ b/submodules/StatisticsUI/Sources/StatsMessageItem.swift @@ -178,7 +178,7 @@ public class StatsMessageItemNode: ListViewItemNode, ItemListItemNode { let titleFont = Font.regular(item.presentationData.fontSize.itemListBaseFontSize) let contentKind = messageContentKind(contentSettings: item.context.currentContentSettings.with { $0 }, message: item.message, strings: item.presentationData.strings, nameDisplayOrder: .firstLast, accountPeerId: item.context.account.peerId) - var text = stringForMediaKind(contentKind, strings: item.presentationData.strings).0 + var text = !item.message.text.isEmpty ? item.message.text : stringForMediaKind(contentKind, strings: item.presentationData.strings).0 text = foldLineBreaks(text) var contentImageMedia: Media? diff --git a/submodules/TelegramCore/Sources/CachedStickerPack.swift b/submodules/TelegramCore/Sources/CachedStickerPack.swift index 4582c64171..2355a47376 100644 --- a/submodules/TelegramCore/Sources/CachedStickerPack.swift +++ b/submodules/TelegramCore/Sources/CachedStickerPack.swift @@ -16,8 +16,19 @@ func cacheStickerPack(transaction: Transaction, info: StickerPackCollectionInfo, transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(info.id)), entry: CachedStickerPack(info: info, items: items.map { $0 as! StickerPackItem }, hash: info.hash), collectionSpec: collectionSpec) transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(shortName: info.shortName)), entry: CachedStickerPack(info: info, items: items.map { $0 as! StickerPackItem }, hash: info.hash), collectionSpec: collectionSpec) - if let reference = reference, case .animatedEmoji = reference { - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: Namespaces.ItemCollection.CloudAnimatedEmoji, id: 0))), entry: CachedStickerPack(info: info, items: items.map { $0 as! StickerPackItem }, hash: info.hash), collectionSpec: collectionSpec) + if let reference = reference { + var namespace: Int32? + switch reference { + case .animatedEmoji: + namespace = Namespaces.ItemCollection.CloudAnimatedEmoji + case .dice: + namespace = Namespaces.ItemCollection.CloudDice + default: + break + } + if let namespace = namespace { + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: 0))), entry: CachedStickerPack(info: info, items: items.map { $0 as! StickerPackItem }, hash: info.hash), collectionSpec: collectionSpec) + } } } diff --git a/submodules/TelegramStringFormatting/Sources/MessageContentKind.swift b/submodules/TelegramStringFormatting/Sources/MessageContentKind.swift index af4d03fac0..eec223548a 100644 --- a/submodules/TelegramStringFormatting/Sources/MessageContentKind.swift +++ b/submodules/TelegramStringFormatting/Sources/MessageContentKind.swift @@ -23,6 +23,7 @@ public enum MessageContentKindKey { case expiredVideo case poll case restricted + case dice } public enum MessageContentKind: Equatable { @@ -42,6 +43,7 @@ public enum MessageContentKind: Equatable { case expiredVideo case poll(String) case restricted(String) + case dice public var key: MessageContentKindKey { switch self { @@ -77,6 +79,8 @@ public enum MessageContentKind: Equatable { return .poll case .restricted: return .restricted + case .dice: + return .dice } } } @@ -165,6 +169,8 @@ public func mediaContentKind(_ media: Media, message: Message? = nil, strings: P } case let poll as TelegramMediaPoll: return .poll(poll.text) + case _ as TelegramMediaDice: + return .dice default: return nil } @@ -212,6 +218,8 @@ public func stringForMediaKind(_ kind: MessageContentKind, strings: Presentation return ("📊 \(text)", false) case let .restricted(text): return (text, false) + case .dice: + return ("🎲", true) } } diff --git a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift index e7fe454efd..3641f1b203 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -51,6 +51,9 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { var telegramDice: TelegramMediaDice? private let disposable = MetaDisposable() + private var forwardInfoNode: ChatMessageForwardInfoNode? + private var forwardBackgroundNode: ASImageNode? + private var viaBotNode: TextNode? private let dateAndStatusNode: ChatMessageDateAndStatusNode private var replyInfoNode: ChatMessageReplyInfoNode? @@ -64,6 +67,8 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { private var currentSwipeToReplyTranslation: CGFloat = 0.0 + private var appliedForwardInfo: (Peer?, String?)? + required init() { self.contextSourceNode = ContextExtractedContentContainingNode() self.imageNode = TransformImageNode() @@ -153,9 +158,10 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { } if let _ = self.telegramDice { - let diceEmojis = item.associatedData.animatedEmojiStickers["🎲"] ?? [] - let animationNode = ManagedDiceAnimationNode(context: item.context, emojis: diceEmojis.map { $0.file }) - self.animationNode = animationNode + if let diceEmojis = item.associatedData.animatedEmojiStickers["🎲"] { + let animationNode = ManagedDiceAnimationNode(context: item.context, emojis: diceEmojis.map { $0.file }) + self.animationNode = animationNode + } } else { let animationNode = AnimatedStickerNode() animationNode.started = { [weak self] in @@ -203,7 +209,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { } else { diceNode.setState(.rolling) } - } else if self.telegramFile == nil { + } else if self.telegramFile == nil && self.telegramDice == nil { let (emoji, fitz) = item.message.text.basicEmoji var emojiFile: TelegramMediaFile? @@ -295,7 +301,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { } } } else if let animationNode = self.animationNode as? ManagedDiceAnimationNode { - + } } @@ -307,23 +313,30 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { let displaySize = CGSize(width: 184.0, height: 184.0) let telegramFile = self.telegramFile let emojiFile = self.emojiFile + let telegramDice = self.telegramDice let layoutConstants = self.layoutConstants let imageLayout = self.imageNode.asyncLayout() let makeDateAndStatusLayout = self.dateAndStatusNode.asyncLayout() let actionButtonsLayout = ChatMessageActionButtonsNode.asyncLayout(self.actionButtonsNode) + let makeForwardInfoLayout = ChatMessageForwardInfoNode.asyncLayout(self.forwardInfoNode) + let currentForwardBackgroundNode = self.forwardBackgroundNode + let viaBotLayout = TextNode.asyncLayout(self.viaBotNode) let makeReplyInfoLayout = ChatMessageReplyInfoNode.asyncLayout(self.replyInfoNode) let currentReplyBackgroundNode = self.replyBackgroundNode let currentShareButtonNode = self.shareButtonNode let currentItem = self.item + let currentForwardInfo = self.appliedForwardInfo return { item, params, mergedTop, mergedBottom, dateHeaderAtBottom in let layoutConstants = chatMessageItemLayoutConstants(layoutConstants, params: params, presentationData: item.presentationData) let incoming = item.message.effectivelyIncoming(item.context.account.peerId) var imageSize: CGSize = CGSize(width: 200.0, height: 200.0) var isEmoji = false - if let telegramFile = telegramFile { + if let _ = telegramDice { + imageSize = displaySize + } else if let telegramFile = telegramFile { if let dimensions = telegramFile.dimensions { imageSize = dimensions.cgSize.aspectFitted(displaySize) } else if let thumbnailSize = telegramFile.previewRepresentations.first?.dimensions { @@ -482,7 +495,25 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { var replyBackgroundImage: UIImage? var replyMarkup: ReplyMarkupMessageAttribute? - let availableWidth = max(60.0, params.width - params.leftInset - params.rightInset - max(imageSize.width, 160.0) - 20.0 - layoutConstants.bubble.edgeInset * 2.0 - avatarInset - layoutConstants.bubble.contentInsets.left) + var ignoreForward = self.telegramDice == nil + var ignoreSource = false + + let availableContentWidth = max(60.0, params.width - params.leftInset - params.rightInset - max(imageSize.width, 160.0) - 20.0 - layoutConstants.bubble.edgeInset * 2.0 - avatarInset - layoutConstants.bubble.contentInsets.left) + + if let forwardInfo = item.message.forwardInfo { + if item.message.id.peerId != item.context.account.peerId { + for attribute in item.message.attributes { + if let attribute = attribute as? SourceReferenceMessageAttribute { + if attribute.messageId.peerId == forwardInfo.author?.id { + ignoreForward = true + } else { + ignoreSource = true + } + break + } + } + } + } for attribute in item.message.attributes { if let attribute = attribute as? InlineBotMessageAttribute { @@ -500,11 +531,11 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { let boldAttributes = MarkdownAttributeSet(font: inlineBotPrefixFont, textColor: inlineBotNameColor) let botString = addAttributesToStringWithRanges(item.presentationData.strings.Conversation_MessageViaUser("@\(inlineBotNameString)"), body: bodyAttributes, argumentAttributes: [0: boldAttributes]) - viaBotApply = viaBotLayout(TextNodeLayoutArguments(attributedString: botString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: max(0, availableWidth), height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + viaBotApply = viaBotLayout(TextNodeLayoutArguments(attributedString: botString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: max(0, availableContentWidth), height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) } } if let replyAttribute = attribute as? ReplyMessageAttribute, let replyMessage = item.message.associatedMessages[replyAttribute.messageId] { - replyInfoApply = makeReplyInfoLayout(item.presentationData, item.presentationData.strings, item.context, .standalone, replyMessage, CGSize(width: availableWidth, height: CGFloat.greatestFiniteMagnitude)) + replyInfoApply = makeReplyInfoLayout(item.presentationData, item.presentationData.strings, item.context, .standalone, replyMessage, CGSize(width: availableContentWidth, height: CGFloat.greatestFiniteMagnitude)) } else if let attribute = attribute as? ReplyMarkupMessageAttribute, attribute.flags.contains(.inline), !attribute.rows.isEmpty { replyMarkup = attribute } @@ -517,7 +548,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { let inlineBotNameColor = serviceMessageColorComponents(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper).primaryText let nameString = NSAttributedString(string: sourcePeer.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder), font: inlineBotPrefixFont, textColor: inlineBotNameColor) - viaBotApply = viaBotLayout(TextNodeLayoutArguments(attributedString: nameString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: max(0, availableWidth), height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + viaBotApply = viaBotLayout(TextNodeLayoutArguments(attributedString: nameString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: max(0, availableContentWidth), height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) } } } @@ -563,6 +594,47 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { } let contentHeight = max(imageSize.height, layoutConstants.image.minDimensions.height) + + + var forwardSource: Peer? + var forwardAuthorSignature: String? + + var forwardInfoSizeApply: (CGSize, () -> ChatMessageForwardInfoNode)? + var updatedForwardBackgroundNode: ASImageNode? + var forwardBackgroundImage: UIImage? + + if !ignoreForward, let forwardInfo = item.message.forwardInfo { + if let source = forwardInfo.source { + forwardSource = source + if let authorSignature = forwardInfo.authorSignature { + forwardAuthorSignature = authorSignature + } else if let forwardInfoAuthor = forwardInfo.author, forwardInfoAuthor.id != source.id { + forwardAuthorSignature = forwardInfoAuthor.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) + } else { + forwardAuthorSignature = nil + } + } else { + if let currentForwardInfo = currentForwardInfo, forwardInfo.author == nil && currentForwardInfo.0 != nil { + forwardSource = nil + forwardAuthorSignature = currentForwardInfo.0?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) + } else { + forwardSource = forwardInfo.author + forwardAuthorSignature = forwardInfo.authorSignature + } + } + let availableWidth = max(60.0, availableContentWidth + 6.0) + forwardInfoSizeApply = makeForwardInfoLayout(item.presentationData, item.presentationData.strings, .standalone, forwardSource, forwardAuthorSignature, CGSize(width: availableWidth, height: CGFloat.greatestFiniteMagnitude)) + + if let currentForwardBackgroundNode = currentForwardBackgroundNode { + updatedForwardBackgroundNode = currentForwardBackgroundNode + } else { + updatedForwardBackgroundNode = ASImageNode() + } + + let graphics = PresentationResourcesChat.additionalGraphics(item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper, bubbleCorners: item.presentationData.chatBubbleCorners) + forwardBackgroundImage = graphics.chatServiceBubbleFillImage + } + var maxContentWidth = imageSize.width var actionButtonsFinalize: ((CGFloat) -> (CGSize, (_ animated: Bool) -> ChatMessageActionButtonsNode))? if let replyMarkup = replyMarkup { @@ -583,6 +655,8 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { return (ListViewItemNodeLayout(contentSize: layoutSize, insets: layoutInsets), { [weak self] animation, _ in if let strongSelf = self { + strongSelf.appliedForwardInfo = (forwardSource, forwardAuthorSignature) + strongSelf.contextSourceNode.frame = CGRect(origin: CGPoint(), size: layoutSize) strongSelf.contextSourceNode.contentNode.frame = CGRect(origin: CGPoint(), size: layoutSize) @@ -716,6 +790,31 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { }) } + if let updatedForwardBackgroundNode = updatedForwardBackgroundNode { + if strongSelf.forwardBackgroundNode == nil { + strongSelf.forwardBackgroundNode = updatedForwardBackgroundNode + strongSelf.addSubnode(updatedForwardBackgroundNode) + updatedForwardBackgroundNode.image = forwardBackgroundImage + } + } else if let forwardBackgroundNode = strongSelf.forwardBackgroundNode { + forwardBackgroundNode.removeFromSupernode() + strongSelf.forwardBackgroundNode = nil + } + + if let (forwardInfoSize, forwardInfoApply) = forwardInfoSizeApply { + let forwardInfoNode = forwardInfoApply() + if strongSelf.forwardInfoNode == nil { + strongSelf.forwardInfoNode = forwardInfoNode + strongSelf.addSubnode(forwardInfoNode) + } + let forwardInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 12.0) : (params.width - params.rightInset - forwardInfoSize.width - layoutConstants.bubble.edgeInset - 12.0)), y: 8.0), size: forwardInfoSize) + forwardInfoNode.frame = forwardInfoFrame + strongSelf.forwardBackgroundNode?.frame = CGRect(origin: CGPoint(x: forwardInfoFrame.minX - 6.0, y: forwardInfoFrame.minY - 2.0), size: CGSize(width: forwardInfoFrame.size.width + 10.0, height: forwardInfoFrame.size.height + 4.0)) + } else if let forwardInfoNode = strongSelf.forwardInfoNode { + forwardInfoNode.removeFromSupernode() + strongSelf.forwardInfoNode = nil + } + if let actionButtonsSizeAndApply = actionButtonsSizeAndApply { var animated = false if let _ = strongSelf.actionButtonsNode { @@ -842,7 +941,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { if let _ = self.telegramFile { let _ = item.controllerInteraction.openMessage(item.message, .default) } else if let _ = self.telegramDice { - item.controllerInteraction.displayMessageTooltip(item.content.firstMessage.id, item.presentationData.strings.Conversation_Dice, self, self.imageNode.frame) + item.controllerInteraction.displayMessageTooltip(item.content.firstMessage.id, item.presentationData.strings.Conversation_Dice, self, self.imageNode.frame.offsetBy(dx: 0.0, dy: self.imageNode.frame.height / 3.0)) } else if let _ = self.emojiFile { if let animationNode = self.animationNode as? AnimatedStickerNode { var startTime: Signal diff --git a/submodules/TelegramUI/Sources/ManagedDiceAnimationNode.swift b/submodules/TelegramUI/Sources/ManagedDiceAnimationNode.swift index 969a7d0a84..3d7d6f4915 100644 --- a/submodules/TelegramUI/Sources/ManagedDiceAnimationNode.swift +++ b/submodules/TelegramUI/Sources/ManagedDiceAnimationNode.swift @@ -24,7 +24,7 @@ final class ManagedDiceAnimationNode: ManagedAnimationNode, GenericAnimatedStick self.context = context self.emojis = emojis - super.init(size: CGSize(width: 136.0, height: 136.0)) + super.init(size: CGSize(width: 184.0, height: 184.0)) self.trackTo(item: ManagedAnimationItem(source: .local("Dice_Rolling"), frames: ManagedAnimationFrameRange(startFrame: 0, endFrame: 60), duration: 1.0, loop: true)) }