diff --git a/submodules/TelegramUI/TelegramUI/AnimatedStickerNode.swift b/submodules/TelegramUI/TelegramUI/AnimatedStickerNode.swift index cd1448d983..51d72672c7 100644 --- a/submodules/TelegramUI/TelegramUI/AnimatedStickerNode.swift +++ b/submodules/TelegramUI/TelegramUI/AnimatedStickerNode.swift @@ -306,6 +306,9 @@ final class AnimatedStickerNode: ASDisplayNode { private let fetchDisposable = MetaDisposable() private let eventsNode: AnimatedStickerNodeDisplayEvents + var shouldAutoPlay: () -> Bool = { + return true + } var started: () -> Void = {} var reportedStarted = false @@ -407,7 +410,7 @@ final class AnimatedStickerNode: ASDisplayNode { } private func updateIsPlaying() { - let isPlaying = self.visibility && self.isDisplaying + let isPlaying = self.visibility && self.isDisplaying && self.shouldAutoPlay() if self.isPlaying != isPlaying { self.isPlaying = isPlaying if isPlaying { @@ -454,6 +457,7 @@ final class AnimatedStickerNode: ASDisplayNode { return } if !strongSelf.reportedStarted { + strongSelf.reportedStarted = true strongSelf.started() } }) diff --git a/submodules/TelegramUI/TelegramUI/ChatControllerInteraction.swift b/submodules/TelegramUI/TelegramUI/ChatControllerInteraction.swift index 3fdd99985b..b68c91ae19 100644 --- a/submodules/TelegramUI/TelegramUI/ChatControllerInteraction.swift +++ b/submodules/TelegramUI/TelegramUI/ChatControllerInteraction.swift @@ -123,6 +123,7 @@ public final class ChatControllerInteraction { var pollActionState: ChatInterfacePollActionState var stickerSettings: ChatInterfaceStickerSettings var searchTextHighightState: String? + var seenOneTimeAnimatedMedia = Set() init(openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool, openPeer: @escaping (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void, openPeerMention: @escaping (String) -> Void, openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect) -> Void, navigateToMessage: @escaping (MessageId, MessageId) -> Void, clickThroughMessage: @escaping () -> Void, toggleMessagesSelection: @escaping ([MessageId], Bool) -> Void, sendCurrentMessage: @escaping (Bool) -> Void, sendMessage: @escaping (String) -> Void, sendSticker: @escaping (FileMediaReference, Bool, ASDisplayNode, CGRect) -> Bool, sendGif: @escaping (FileMediaReference, ASDisplayNode, CGRect) -> Bool, requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool) -> Void, requestMessageActionUrlAuth: @escaping (String, MessageId, Int32) -> Void, activateSwitchInline: @escaping (PeerId?, String) -> Void, openUrl: @escaping (String, Bool, Bool?) -> Void, shareCurrentLocation: @escaping () -> Void, shareAccountContact: @escaping () -> Void, sendBotCommand: @escaping (MessageId?, String) -> Void, openInstantPage: @escaping (Message, ChatMessageItemAssociatedData?) -> Void, openWallpaper: @escaping (Message) -> Void, openHashtag: @escaping (String?, String) -> Void, updateInputState: @escaping ((ChatTextInputState) -> ChatTextInputState) -> Void, updateInputMode: @escaping ((ChatInputMode) -> ChatInputMode) -> Void, openMessageShareMenu: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, callPeer: @escaping (PeerId) -> Void, longTap: @escaping (ChatControllerInteractionLongTapAction, Message?) -> Void, openCheckoutOrReceipt: @escaping (MessageId) -> Void, openSearch: @escaping () -> Void, setupReply: @escaping (MessageId) -> Void, canSetupReply: @escaping (Message) -> Bool, navigateToFirstDateMessage: @escaping(Int32) ->Void, requestRedeliveryOfFailedMessages: @escaping (MessageId) -> Void, addContact: @escaping (String) -> Void, rateCall: @escaping (Message, CallId) -> Void, requestSelectMessagePollOption: @escaping (MessageId, Data) -> Void, openAppStorePage: @escaping () -> Void, displayMessageTooltip: @escaping (MessageId, String, ASDisplayNode?, CGRect?) -> Void, seekToTimecode: @escaping (Message, Double, Bool) -> Void, requestMessageUpdate: @escaping (MessageId) -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void, automaticMediaDownloadSettings: MediaAutoDownloadSettings, pollActionState: ChatInterfacePollActionState, stickerSettings: ChatInterfaceStickerSettings) { self.openMessage = openMessage diff --git a/submodules/TelegramUI/TelegramUI/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/TelegramUI/ChatMessageAnimatedStickerItemNode.swift index 43a818c58e..82be722df1 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMessageAnimatedStickerItemNode.swift @@ -51,7 +51,26 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { super.init(layerBacked: false) self.animationNode.started = { [weak self] in - self?.imageNode.alpha = 0.0 + if let strongSelf = self { + strongSelf.imageNode.alpha = 0.0 + + if let item = strongSelf.item { + if let _ = strongSelf.emojiFile { + item.controllerInteraction.seenOneTimeAnimatedMedia.insert(item.message.id) + } + } + } + } + + self.animationNode.shouldAutoPlay = { [weak self] in + if let strongSelf = self { + if let item = strongSelf.item { + if let _ = strongSelf.emojiFile { + return !item.controllerInteraction.seenOneTimeAnimatedMedia.contains(item.message.id) + } + } + } + return true } self.imageNode.displaysAsynchronously = false @@ -171,9 +190,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { } else if let emojiFile = self.emojiFile { isEmoji = true file = emojiFile - if item.context.sharedContext.immediateExperimentalUISettings.playAnimatedEmojiOnce { - playbackMode = .once - } + playbackMode = .once } if let file = file { @@ -665,29 +682,27 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { if self.telegramFile != nil { let _ = item.controllerInteraction.openMessage(item.message, .default) } else if let _ = self.emojiFile { - if item.context.sharedContext.immediateExperimentalUISettings.playAnimatedEmojiOnce { - if self.animationNode.playIfNeeded() { - if self.item?.message.text == "❤️" { - let hapticFeedback: HapticFeedback - if let currentHapticFeedback = self.hapticFeedback { - hapticFeedback = currentHapticFeedback - } else { - hapticFeedback = HapticFeedback() - self.hapticFeedback = hapticFeedback - } - hapticFeedback.prepareImpact() - hapticFeedback.impact(.medium) - Queue.mainQueue().after(0.2) { - hapticFeedback.impact(.light) - Queue.mainQueue().after(0.78) { - hapticFeedback.impact(.medium) - Queue.mainQueue().after(0.2) { - hapticFeedback.impact(.light) - Queue.mainQueue().after(0.78) { - hapticFeedback.impact(.medium) - Queue.mainQueue().after(0.2) { - hapticFeedback.impact(.light) - } + if self.animationNode.playIfNeeded() { + if self.item?.message.text == "❤️" { + let hapticFeedback: HapticFeedback + if let currentHapticFeedback = self.hapticFeedback { + hapticFeedback = currentHapticFeedback + } else { + hapticFeedback = HapticFeedback() + self.hapticFeedback = hapticFeedback + } + hapticFeedback.prepareImpact() + hapticFeedback.impact(.medium) + Queue.mainQueue().after(0.2) { + hapticFeedback.impact(.light) + Queue.mainQueue().after(0.78) { + hapticFeedback.impact(.medium) + Queue.mainQueue().after(0.2) { + hapticFeedback.impact(.light) + Queue.mainQueue().after(0.78) { + hapticFeedback.impact(.medium) + Queue.mainQueue().after(0.2) { + hapticFeedback.impact(.light) } } } diff --git a/submodules/TelegramUI/TelegramUI/DebugController.swift b/submodules/TelegramUI/TelegramUI/DebugController.swift index c7c4a1b12a..11bed23910 100644 --- a/submodules/TelegramUI/TelegramUI/DebugController.swift +++ b/submodules/TelegramUI/TelegramUI/DebugController.swift @@ -57,7 +57,6 @@ private enum DebugControllerEntry: ItemListNodeEntry { case resetBiometricsData(PresentationTheme) case optimizeDatabase(PresentationTheme) case photoPreview(PresentationTheme, Bool) - case playAnimatedEmojiOnce(PresentationTheme, Bool) case exportTheme(PresentationTheme) case versionInfo(PresentationTheme) @@ -71,7 +70,7 @@ private enum DebugControllerEntry: ItemListNodeEntry { return DebugControllerSection.logging.rawValue case .enableRaiseToSpeak, .keepChatNavigationStack, .skipReadHistory, .crashOnSlowQueries: return DebugControllerSection.experiments.rawValue - case .clearTips, .reimport, .resetData, .resetDatabase, .resetHoles, .resetBiometricsData, .optimizeDatabase, .photoPreview, .playAnimatedEmojiOnce, .exportTheme: + case .clearTips, .reimport, .resetData, .resetDatabase, .resetHoles, .resetBiometricsData, .optimizeDatabase, .photoPreview, .exportTheme: return DebugControllerSection.experiments.rawValue case .versionInfo: return DebugControllerSection.info.rawValue @@ -120,12 +119,10 @@ private enum DebugControllerEntry: ItemListNodeEntry { return 18 case .photoPreview: return 19 - case .playAnimatedEmojiOnce: - return 20 case .exportTheme: - return 21 + return 20 case .versionInfo: - return 22 + return 21 } } @@ -472,16 +469,6 @@ private enum DebugControllerEntry: ItemListNodeEntry { }) }).start() }) - case let .playAnimatedEmojiOnce(theme, value): - return ItemListSwitchItem(theme: theme, title: "Play Emoji Once", value: value, sectionId: self.section, style: .blocks, updated: { value in - let _ = arguments.sharedContext.accountManager.transaction ({ transaction in - transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in - var settings = settings as? ExperimentalUISettings ?? ExperimentalUISettings.defaultSettings - settings.playAnimatedEmojiOnce = value - return settings - }) - }).start() - }) case let .exportTheme(theme): return ItemListActionItem(theme: theme, title: "Export Theme", kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: { guard let context = arguments.context else { @@ -549,7 +536,6 @@ private func debugControllerEntries(presentationData: PresentationData, loggingS entries.append(.resetHoles(presentationData.theme)) entries.append(.optimizeDatabase(presentationData.theme)) entries.append(.photoPreview(presentationData.theme, experimentalSettings.chatListPhotos)) - entries.append(.playAnimatedEmojiOnce(presentationData.theme, experimentalSettings.playAnimatedEmojiOnce)) entries.append(.versionInfo(presentationData.theme)) diff --git a/submodules/TelegramUIPreferences/Sources/ExperimentalUISettings.swift b/submodules/TelegramUIPreferences/Sources/ExperimentalUISettings.swift index 1ca96950e7..37d8e96724 100644 --- a/submodules/TelegramUIPreferences/Sources/ExperimentalUISettings.swift +++ b/submodules/TelegramUIPreferences/Sources/ExperimentalUISettings.swift @@ -7,18 +7,16 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry { public var skipReadHistory: Bool public var crashOnLongQueries: Bool public var chatListPhotos: Bool - public var playAnimatedEmojiOnce: Bool public static var defaultSettings: ExperimentalUISettings { - return ExperimentalUISettings(keepChatNavigationStack: false, skipReadHistory: false, crashOnLongQueries: false, chatListPhotos: false, playAnimatedEmojiOnce: true) + return ExperimentalUISettings(keepChatNavigationStack: false, skipReadHistory: false, crashOnLongQueries: false, chatListPhotos: false) } - public init(keepChatNavigationStack: Bool, skipReadHistory: Bool, crashOnLongQueries: Bool, chatListPhotos: Bool, playAnimatedEmojiOnce: Bool) { + public init(keepChatNavigationStack: Bool, skipReadHistory: Bool, crashOnLongQueries: Bool, chatListPhotos: Bool) { self.keepChatNavigationStack = keepChatNavigationStack self.skipReadHistory = skipReadHistory self.crashOnLongQueries = crashOnLongQueries self.chatListPhotos = chatListPhotos - self.playAnimatedEmojiOnce = playAnimatedEmojiOnce } public init(decoder: PostboxDecoder) { @@ -26,7 +24,6 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry { self.skipReadHistory = decoder.decodeInt32ForKey("skipReadHistory", orElse: 0) != 0 self.crashOnLongQueries = decoder.decodeInt32ForKey("crashOnLongQueries", orElse: 0) != 0 self.chatListPhotos = decoder.decodeInt32ForKey("chatListPhotos", orElse: 0) != 0 - self.playAnimatedEmojiOnce = decoder.decodeInt32ForKey("playAnimatedEmojiOnce", orElse: 1) != 0 } public func encode(_ encoder: PostboxEncoder) { @@ -34,7 +31,6 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry { encoder.encodeInt32(self.skipReadHistory ? 1 : 0, forKey: "skipReadHistory") encoder.encodeInt32(self.crashOnLongQueries ? 1 : 0, forKey: "crashOnLongQueries") encoder.encodeInt32(self.chatListPhotos ? 1 : 0, forKey: "chatListPhotos") - encoder.encodeInt32(self.playAnimatedEmojiOnce ? 1 : 0, forKey: "playAnimatedEmojiOnce") } public func isEqual(to: PreferencesEntry) -> Bool {