diff --git a/submodules/TelegramCallsUI/Sources/Components/MediaStreamComponent.swift b/submodules/TelegramCallsUI/Sources/Components/MediaStreamComponent.swift index e9992927ac..87fc1f206a 100644 --- a/submodules/TelegramCallsUI/Sources/Components/MediaStreamComponent.swift +++ b/submodules/TelegramCallsUI/Sources/Components/MediaStreamComponent.swift @@ -1197,7 +1197,7 @@ public final class MediaStreamComponentController: ViewControllerComponentContai self.view.layer.cornerCurve = .continuous } - self.view.layer.animatePosition(from: CGPoint(x: 353.0, y: 117.0), to: self.view.center, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, completion: { [weak self] _ in + self.view.layer.animatePosition(from: CGPoint(x: self.view.frame.width * 0.9, y: 117.0), to: self.view.center, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, completion: { [weak self] _ in self?.view.layer.cornerRadius = 0.0 }) self.view.layer.animateScale(from: 0.001, to: 1.0, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring) @@ -1247,7 +1247,7 @@ public final class MediaStreamComponentController: ViewControllerComponentContai self.view.layer.cornerCurve = .continuous } - self.view.layer.animatePosition(from: self.view.center, to: CGPoint(x: 353.0, y: 117.0), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, completion: { _ in + self.view.layer.animatePosition(from: self.view.center, to: CGPoint(x: self.view.frame.width * 0.9, y: 117.0), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, completion: { _ in }) self.view.layer.animateScale(from: 1.0, to: 0.001, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring) } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index a05f8bdb55..6a2b9fa3d9 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -3139,15 +3139,17 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self?.displayPsa(type: type, sourceNode: sourceNode, isAutomatic: false) }, displayDiceTooltip: { [weak self] dice in self?.displayDiceTooltip(dice: dice) - }, animateDiceSuccess: { [weak self] onlyHaptic in + }, animateDiceSuccess: { [weak self] haptic, confetti in guard let strongSelf = self else { return } if strongSelf.selectPollOptionFeedback == nil { strongSelf.selectPollOptionFeedback = HapticFeedback() } - strongSelf.selectPollOptionFeedback?.success() - if !onlyHaptic { + if haptic { + strongSelf.selectPollOptionFeedback?.success() + } + if confetti { strongSelf.chatDisplayNode.animateQuizCorrectOptionSelected() } }, displayPremiumStickerTooltip: { [weak self] file, message in diff --git a/submodules/TelegramUI/Sources/ChatControllerInteraction.swift b/submodules/TelegramUI/Sources/ChatControllerInteraction.swift index 6beeb74fd9..36261570fc 100644 --- a/submodules/TelegramUI/Sources/ChatControllerInteraction.swift +++ b/submodules/TelegramUI/Sources/ChatControllerInteraction.swift @@ -122,7 +122,7 @@ public final class ChatControllerInteraction { let displayPollSolution: (TelegramMediaPollResults.Solution, ASDisplayNode) -> Void let displayPsa: (String, ASDisplayNode) -> Void let displayDiceTooltip: (TelegramMediaDice) -> Void - let animateDiceSuccess: (Bool) -> Void + let animateDiceSuccess: (Bool, Bool) -> Void let displayPremiumStickerTooltip: (TelegramMediaFile, Message) -> Void let openPeerContextMenu: (Peer, MessageId?, ASDisplayNode, CGRect, ContextGesture?) -> Void let openMessageReplies: (MessageId, Bool, Bool) -> Void @@ -225,7 +225,7 @@ public final class ChatControllerInteraction { displayPollSolution: @escaping (TelegramMediaPollResults.Solution, ASDisplayNode) -> Void, displayPsa: @escaping (String, ASDisplayNode) -> Void, displayDiceTooltip: @escaping (TelegramMediaDice) -> Void, - animateDiceSuccess: @escaping (Bool) -> Void, + animateDiceSuccess: @escaping (Bool, Bool) -> Void, displayPremiumStickerTooltip: @escaping (TelegramMediaFile, Message) -> Void, openPeerContextMenu: @escaping (Peer, MessageId?, ASDisplayNode, CGRect, ContextGesture?) -> Void, openMessageReplies: @escaping (MessageId, Bool, Bool) -> Void, diff --git a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift index 240adba31b..efefbb0e54 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -423,7 +423,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { if !item.message.effectivelyIncoming(item.context.account.peerId) { animationNode.success = { [weak self] onlyHaptic in if let strongSelf = self, let item = strongSelf.item { - item.controllerInteraction.animateDiceSuccess(onlyHaptic) + item.controllerInteraction.animateDiceSuccess(true, !onlyHaptic) } } } @@ -433,7 +433,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { if !item.message.effectivelyIncoming(item.context.account.peerId) { animationNode.success = { [weak self] in if let strongSelf = self, let item = strongSelf.item { - item.controllerInteraction.animateDiceSuccess(false) + item.controllerInteraction.animateDiceSuccess(true, true) } } } diff --git a/submodules/TelegramUI/Sources/ChatMessageGiftItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageGiftItemNode.swift index 9a9abbc3ed..937e1b1fdc 100644 --- a/submodules/TelegramUI/Sources/ChatMessageGiftItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageGiftItemNode.swift @@ -40,6 +40,29 @@ class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode { private var cachedMaskBackgroundImage: (CGPoint, UIImage, [CGRect])? private var absoluteRect: (CGRect, CGSize)? + private var isPlaying: Bool = false + private var wasPending: Bool = false + private var didChangeFromPendingToSent: Bool = false + + override var visibility: ListViewItemNodeVisibility { + didSet { + let wasVisible = oldValue != .none + let isVisible = self.visibility != .none + + if wasVisible != isVisible { + self.visibilityStatus = isVisible + } + } + } + + private var visibilityStatus: Bool? { + didSet { + if self.visibilityStatus != oldValue { + self.updateVisibility() + } + } + } + required init() { self.labelNode = TextNode() self.labelNode.isUserInteractionEnabled = false @@ -200,11 +223,19 @@ class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode { return (backgroundSize, { [weak self] animation, synchronousLoads, _ in if let strongSelf = self { if strongSelf.item == nil { - strongSelf.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: animationName), width: 384, height: 384, playbackMode: .once, mode: .direct(cachePathPrefix: nil)) - strongSelf.animationNode.visibility = true + strongSelf.animationNode.autoplay = true + strongSelf.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: animationName), width: 384, height: 384, playbackMode: .still(.end), mode: .direct(cachePathPrefix: nil)) } strongSelf.item = item + if item.message.id.namespace == Namespaces.Message.Local || item.message.id.namespace == Namespaces.Message.ScheduledLocal { + strongSelf.wasPending = true + } + if strongSelf.wasPending && (item.message.id.namespace != Namespaces.Message.Local && item.message.id.namespace != Namespaces.Message.ScheduledLocal) { + strongSelf.didChangeFromPendingToSent = true + } + strongSelf.updateVisibility() + strongSelf.backgroundColorNode.backgroundColor = selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper) let imageFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((backgroundSize.width - giftSize.width) / 2.0), y: labelLayout.size.height + 16.0), size: giftSize) @@ -384,4 +415,37 @@ class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode { return .none } } + + private func updateVisibility() { + guard let item = self.item else { + return + } + + let isPlaying = self.visibilityStatus == true + if self.isPlaying != isPlaying { + self.isPlaying = isPlaying + self.animationNode.visibility = isPlaying + } + + if isPlaying { + var alreadySeen = true + + if let unreadRange = item.controllerInteraction.unreadMessageRange[UnreadMessageRangeKey(peerId: item.message.id.peerId, namespace: item.message.id.namespace)] { + if unreadRange.contains(item.message.id.id) { + if !item.controllerInteraction.seenOneTimeAnimatedMedia.contains(item.message.id) { + alreadySeen = false + } + } + } + + if !item.controllerInteraction.seenOneTimeAnimatedMedia.contains(item.message.id) { + item.controllerInteraction.seenOneTimeAnimatedMedia.insert(item.message.id) + self.animationNode.playOnce() + } + + if !alreadySeen { + item.controllerInteraction.animateDiceSuccess(false, true) + } + } + } } diff --git a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift index 936cb29704..a81534c233 100644 --- a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift @@ -517,7 +517,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { }, displayPollSolution: { _, _ in }, displayPsa: { _, _ in }, displayDiceTooltip: { _ in - }, animateDiceSuccess: { _ in + }, animateDiceSuccess: { _, _ in }, displayPremiumStickerTooltip: { _, _ in }, openPeerContextMenu: { _, _, _, _, _ in }, openMessageReplies: { _, _, _ in diff --git a/submodules/TelegramUI/Sources/DrawingStickersScreen.swift b/submodules/TelegramUI/Sources/DrawingStickersScreen.swift index 13daf942a7..0e8743ef92 100644 --- a/submodules/TelegramUI/Sources/DrawingStickersScreen.swift +++ b/submodules/TelegramUI/Sources/DrawingStickersScreen.swift @@ -143,7 +143,7 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode { }, displayPollSolution: { _, _ in }, displayPsa: { _, _ in }, displayDiceTooltip: { _ in - }, animateDiceSuccess: { _ in + }, animateDiceSuccess: { _, _ in }, displayPremiumStickerTooltip: { _, _ in }, openPeerContextMenu: { _, _, _, _, _ in }, openMessageReplies: { _, _, _ in diff --git a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift index 5c6dd1e3b0..7918d25600 100644 --- a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift +++ b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift @@ -135,7 +135,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu }, displayPollSolution: { _, _ in }, displayPsa: { _, _ in }, displayDiceTooltip: { _ in - }, animateDiceSuccess: { _ in + }, animateDiceSuccess: { _, _ in }, displayPremiumStickerTooltip: { _, _ in }, openPeerContextMenu: { _, _, _, _, _ in }, openMessageReplies: { _, _, _ in diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 8dc1c40b17..94ba363f8b 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -2336,7 +2336,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate }, displayPollSolution: { _, _ in }, displayPsa: { _, _ in }, displayDiceTooltip: { _ in - }, animateDiceSuccess: { _ in + }, animateDiceSuccess: { _, _ in }, displayPremiumStickerTooltip: { _, _ in }, openPeerContextMenu: { _, _, _, _, _ in }, openMessageReplies: { _, _, _ in diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index 7f8e089a21..1d07912800 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -1313,7 +1313,7 @@ public final class SharedAccountContextImpl: SharedAccountContext { }, displayPollSolution: { _, _ in }, displayPsa: { _, _ in }, displayDiceTooltip: { _ in - }, animateDiceSuccess: { _ in + }, animateDiceSuccess: { _, _ in }, displayPremiumStickerTooltip: { _, _ in }, openPeerContextMenu: { _, _, _, _, _ in }, openMessageReplies: { _, _, _ in