Merge commit 'a6292e752a7de0c7fd28f07b0a24c215d227e593'

This commit is contained in:
Ilya Laktyushin 2022-06-08 03:37:14 +04:00
commit f17f51b5a0
9 changed files with 309 additions and 19 deletions

View File

@ -588,6 +588,7 @@ public final class AnimatedStickerDirectFrameSource: AnimatedStickerFrameSource
let decompressedData = TGGUnzipData(data, 8 * 1024 * 1024) ?? data
guard let animation = LottieInstance(data: decompressedData, fitzModifier: fitzModifier?.lottieFitzModifier ?? .none, colorReplacements: nil, cacheKey: "") else {
print("Could not load sticker data")
return nil
}
self.animation = animation

View File

@ -2197,12 +2197,14 @@ public final class ContextController: ViewController, StandalonePresentableContr
public var content: Content
public var context: AccountContext?
public var reactionItems: [ReactionContextItem]
public var disablePositionLock: Bool
public var tip: Tip?
public init(content: Content, context: AccountContext? = nil, reactionItems: [ReactionContextItem] = [], tip: Tip? = nil) {
public init(content: Content, context: AccountContext? = nil, reactionItems: [ReactionContextItem] = [], disablePositionLock: Bool = false, tip: Tip? = nil) {
self.content = content
self.context = context
self.reactionItems = reactionItems
self.disablePositionLock = disablePositionLock
self.tip = tip
}
@ -2210,6 +2212,7 @@ public final class ContextController: ViewController, StandalonePresentableContr
self.content = .list([])
self.context = nil
self.reactionItems = []
self.disablePositionLock = false
self.tip = nil
}
}

View File

@ -320,7 +320,10 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
func pushItems(items: ContextController.Items) {
let currentScrollingState = self.getCurrentScrollingState()
let positionLock = self.getActionsStackPositionLock()
var positionLock: CGFloat?
if !items.disablePositionLock {
positionLock = self.getActionsStackPositionLock()
}
self.actionsStackNode.push(item: makeContextControllerActionsStackItem(items: items), currentScrollingState: currentScrollingState, positionLock: positionLock, animated: true)
}

View File

@ -87,6 +87,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
case experimentalBackground(Bool)
case inlineStickers(Bool)
case localTranscription(Bool)
case enableReactionOverrides(Bool)
case playerEmbedding(Bool)
case playlistPlayback(Bool)
case voiceConference
@ -109,7 +110,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
return DebugControllerSection.logging.rawValue
case .enableRaiseToSpeak, .keepChatNavigationStack, .skipReadHistory, .crashOnSlowQueries:
return DebugControllerSection.experiments.rawValue
case .clearTips, .crash, .resetData, .resetDatabase, .resetDatabaseAndCache, .resetHoles, .reindexUnread, .resetBiometricsData, .resetWebViewCache, .optimizeDatabase, .photoPreview, .knockoutWallpaper, .playerEmbedding, .playlistPlayback, .voiceConference, .experimentalCompatibility, .enableDebugDataDisplay, .acceleratedStickers, .experimentalBackground, .inlineStickers, .localTranscription, .resetInAppPurchases:
case .clearTips, .crash, .resetData, .resetDatabase, .resetDatabaseAndCache, .resetHoles, .reindexUnread, .resetBiometricsData, .resetWebViewCache, .optimizeDatabase, .photoPreview, .knockoutWallpaper, .playerEmbedding, .playlistPlayback, .voiceConference, .experimentalCompatibility, .enableDebugDataDisplay, .acceleratedStickers, .experimentalBackground, .inlineStickers, .localTranscription, . enableReactionOverrides, .resetInAppPurchases:
return DebugControllerSection.experiments.rawValue
case .preferredVideoCodec:
return DebugControllerSection.videoExperiments.rawValue
@ -188,16 +189,18 @@ private enum DebugControllerEntry: ItemListNodeEntry {
return 31
case .localTranscription:
return 32
case .resetInAppPurchases:
case .enableReactionOverrides:
return 33
case .playerEmbedding:
case .resetInAppPurchases:
return 34
case .playlistPlayback:
case .playerEmbedding:
return 35
case .voiceConference:
case .playlistPlayback:
return 36
case .voiceConference:
return 37
case let .preferredVideoCodec(index, _, _, _):
return 37 + index
return 38 + index
case .disableVideoAspectScaling:
return 100
case .enableVoipTcp:
@ -970,6 +973,20 @@ private enum DebugControllerEntry: ItemListNodeEntry {
})
}).start()
})
case let .enableReactionOverrides(value):
return ItemListSwitchItem(presentationData: presentationData, title: "Effect Overrides", 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?.get(ExperimentalUISettings.self) ?? ExperimentalUISettings.defaultSettings
settings.enableReactionOverrides = value
if !value {
settings.accountReactionEffectOverrides.removeAll()
settings.accountStickerEffectOverrides.removeAll()
}
return PreferencesEntry(settings)
})
}).start()
})
case let .playerEmbedding(value):
return ItemListSwitchItem(presentationData: presentationData, title: "Player Embedding", value: value, sectionId: self.section, style: .blocks, updated: { value in
let _ = arguments.sharedContext.accountManager.transaction ({ transaction in
@ -1091,6 +1108,9 @@ private func debugControllerEntries(sharedContext: SharedAccountContext, present
entries.append(.experimentalBackground(experimentalSettings.experimentalBackground))
entries.append(.inlineStickers(experimentalSettings.inlineStickers))
entries.append(.localTranscription(experimentalSettings.localTranscription))
if case .internal = sharedContext.applicationBindings.appBuildType {
entries.append(.enableReactionOverrides(experimentalSettings.enableReactionOverrides))
}
entries.append(.resetInAppPurchases(presentationData.theme))
entries.append(.playerEmbedding(experimentalSettings.playerEmbedding))
entries.append(.playlistPlayback(experimentalSettings.playlistPlayback))

View File

@ -15,6 +15,7 @@ import MultilineTextComponent
import BundleIconComponent
import SolidRoundedButtonComponent
import Markdown
import TelegramUIPreferences
private final class GradientBackgroundComponent: Component {
public let colors: [UIColor]
@ -523,6 +524,27 @@ private final class DemoSheetContent: CombinedComponent {
super.init()
let accountSpecificReactionOverrides: [ExperimentalUISettings.AccountReactionOverrides.Item]
if self.context.sharedContext.immediateExperimentalUISettings.enableReactionOverrides, let value = self.context.sharedContext.immediateExperimentalUISettings.accountReactionEffectOverrides.first(where: { $0.accountId == self.context.account.id.int64 }) {
accountSpecificReactionOverrides = value.items
} else {
accountSpecificReactionOverrides = []
}
let reactionOverrideMessages = self.context.engine.data.get(
EngineDataMap(accountSpecificReactionOverrides.map(\.messageId).map(TelegramEngine.EngineData.Item.Messages.Message.init))
)
let accountSpecificStickerOverrides: [ExperimentalUISettings.AccountReactionOverrides.Item]
if self.context.sharedContext.immediateExperimentalUISettings.enableReactionOverrides, let value = self.context.sharedContext.immediateExperimentalUISettings.accountStickerEffectOverrides.first(where: { $0.accountId == self.context.account.id.int64 }) {
accountSpecificStickerOverrides = value.items
} else {
accountSpecificStickerOverrides = []
}
let stickerOverrideMessages = self.context.engine.data.get(
EngineDataMap(accountSpecificStickerOverrides.map(\.messageId).map(TelegramEngine.EngineData.Item.Messages.Message.init))
)
let stickersKey: PostboxViewKey = .orderedItemList(id: Namespaces.OrderedItemList.CloudPremiumStickers)
self.disposable = (combineLatest(
queue: Queue.mainQueue(),
@ -542,9 +564,33 @@ private final class DemoSheetContent: CombinedComponent {
self.context.engine.data.get(
TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId),
TelegramEngine.EngineData.Item.Configuration.PremiumPromo()
)
),
reactionOverrideMessages,
stickerOverrideMessages
)
|> map { reactions, items, data -> ([AvailableReactions.Reaction], [TelegramMediaFile], Bool?, PremiumPromoConfiguration?) in
|> map { reactions, items, data, reactionOverrideMessages, stickerOverrideMessages -> ([AvailableReactions.Reaction], [TelegramMediaFile], Bool?, PremiumPromoConfiguration?) in
var reactionOverrides: [String: TelegramMediaFile] = [:]
for item in accountSpecificReactionOverrides {
if let maybeMessage = reactionOverrideMessages[item.messageId], let message = maybeMessage {
for media in message.media {
if let file = media as? TelegramMediaFile, file.fileId == item.mediaId {
reactionOverrides[item.key] = file
}
}
}
}
var stickerOverrides: [String: TelegramMediaFile] = [:]
for item in accountSpecificStickerOverrides {
if let maybeMessage = stickerOverrideMessages[item.messageId], let message = maybeMessage {
for media in message.media {
if let file = media as? TelegramMediaFile, file.fileId == item.mediaId {
stickerOverrides[item.key] = file
}
}
}
}
if let reactions = reactions {
var result: [TelegramMediaFile] = []
if let items = items {
@ -554,7 +600,49 @@ private final class DemoSheetContent: CombinedComponent {
}
}
}
return (reactions.reactions.filter({ $0.isPremium }), result, data.0?.isPremium ?? false, data.1)
return (reactions.reactions.filter({ $0.isPremium }).map { reaction -> AvailableReactions.Reaction in
var aroundAnimation = reaction.aroundAnimation
if let replacementFile = reactionOverrides[reaction.value] {
aroundAnimation = replacementFile
}
return AvailableReactions.Reaction(
isEnabled: reaction.isEnabled,
isPremium: reaction.isPremium,
value: reaction.value,
title: reaction.title,
staticIcon: reaction.staticIcon,
appearAnimation: reaction.appearAnimation,
selectAnimation: reaction.selectAnimation,
activateAnimation: reaction.activateAnimation,
effectAnimation: reaction.effectAnimation,
aroundAnimation: aroundAnimation,
centerAnimation: reaction.centerAnimation
)
}, result.map { file -> TelegramMediaFile in
for attribute in file.attributes {
switch attribute {
case let .Sticker(displayText, _, _):
if let replacementFile = stickerOverrides[displayText], let dimensions = replacementFile.dimensions {
let _ = dimensions
return TelegramMediaFile(
fileId: file.fileId,
partialReference: file.partialReference,
resource: file.resource,
previewRepresentations: file.previewRepresentations,
videoThumbnails: [TelegramMediaFile.VideoThumbnail(dimensions: dimensions, resource: replacementFile.resource)],
immediateThumbnailData: file.immediateThumbnailData,
mimeType: file.mimeType,
size: file.size,
attributes: file.attributes
)
}
default:
break
}
}
return file
}, data.0?.isPremium ?? false, data.1)
} else {
return ([], [], nil, nil)
}

View File

@ -97,13 +97,13 @@ private class StickerNode: ASDisplayNode {
private var setupTimestamp: Double?
init(context: AccountContext, file: TelegramMediaFile) {
init(context: AccountContext, file: TelegramMediaFile, forceIsPremium: Bool) {
self.context = context
self.file = file
self.imageNode = TransformImageNode()
if file.isPremiumSticker {
if file.isPremiumSticker || forceIsPremium {
let animationNode = AnimatedStickerNode()
animationNode.automaticallyLoadFirstFrame = true
self.animationNode = animationNode
@ -124,8 +124,11 @@ private class StickerNode: ASDisplayNode {
let source = AnimatedStickerResourceSource(account: self.context.account, resource: effect.resource, fitzModifier: nil)
let additionalAnimationNode = AnimatedStickerNode()
let pathPrefix = context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(effect.resource.id)
additionalAnimationNode.setup(source: source, width: Int(fittedDimensions.width * 1.4), height: Int(fittedDimensions.height * 1.4), playbackMode: .loop, mode: .direct(cachePathPrefix: pathPrefix))
var pathPrefix: String?
pathPrefix = context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(effect.resource.id)
pathPrefix = nil
additionalAnimationNode.setup(source: source, width: Int(fittedDimensions.width * 1.33), height: Int(fittedDimensions.height * 1.33), playbackMode: .loop, mode: .direct(cachePathPrefix: pathPrefix))
self.additionalAnimationNode = additionalAnimationNode
}
} else {
@ -592,7 +595,7 @@ private class StickersCarouselNode: ASDisplayNode, UIScrollViewDelegate {
if let current = self.itemNodes[i] {
itemNode = current
} else {
itemNode = StickerNode(context: self.context, file: self.stickers[i])
itemNode = StickerNode(context: self.context, file: self.stickers[i], forceIsPremium: true)
containerNode.addSubnode(itemNode)
self.itemNodes[i] = itemNode
}

View File

@ -1076,7 +1076,13 @@ public final class StandaloneReactionAnimation: ASDisplayNode {
additionalAnimation = itemNode.item.applicationAnimation
}
additionalAnimationNode.setup(source: AnimatedStickerResourceSource(account: itemNode.context.account, resource: additionalAnimation.resource), width: Int(effectFrame.width * 2.0), height: Int(effectFrame.height * 2.0), playbackMode: .once, mode: .direct(cachePathPrefix: itemNode.context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(additionalAnimation.resource.id)))
var additionalCachePathPrefix: String?
additionalCachePathPrefix = itemNode.context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(additionalAnimation.resource.id)
//#if DEBUG
additionalCachePathPrefix = nil
//#endif
additionalAnimationNode.setup(source: AnimatedStickerResourceSource(account: itemNode.context.account, resource: additionalAnimation.resource), width: Int(effectFrame.width * 1.33), height: Int(effectFrame.height * 1.33), playbackMode: .once, mode: .direct(cachePathPrefix: additionalCachePathPrefix))
additionalAnimationNode.frame = effectFrame
additionalAnimationNode.updateLayout(size: effectFrame.size)
self.addSubnode(additionalAnimationNode)

View File

@ -777,6 +777,132 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
}
}
}
if context.sharedContext.immediateExperimentalUISettings.enableReactionOverrides {
for media in message.media {
if let file = media as? TelegramMediaFile, file.isAnimatedSticker {
actions.append(.action(ContextMenuActionItem(text: "Set as Reaction Effect", icon: { _ in
return nil
}, action: { c, _ in
let subItems: Signal<ContextController.Items, NoError> = context.engine.stickers.availableReactions()
|> map { reactions -> ContextController.Items in
var subActions: [ContextMenuItem] = []
if let reactions = reactions {
for reaction in reactions.reactions {
if !reaction.isEnabled || !reaction.isPremium {
continue
}
subActions.append(.action(ContextMenuActionItem(text: reaction.value, icon: { _ in
return nil
}, action: { _, f in
let _ = updateExperimentalUISettingsInteractively(accountManager: context.sharedContext.accountManager, { settings in
var settings = settings
var currentItems: [ExperimentalUISettings.AccountReactionOverrides.Item]
if let value = settings.accountReactionEffectOverrides.first(where: { $0.accountId == context.account.id.int64 }) {
currentItems = value.items
} else {
currentItems = []
}
currentItems.removeAll(where: { $0.key == reaction.value })
currentItems.append(ExperimentalUISettings.AccountReactionOverrides.Item(
key: reaction.value,
messageId: message.id,
mediaId: file.fileId
))
settings.accountReactionEffectOverrides.removeAll(where: { $0.accountId == context.account.id.int64 })
settings.accountReactionEffectOverrides.append(ExperimentalUISettings.AccountReactionOverrides(accountId: context.account.id.int64, items: currentItems))
return settings
}).start()
f(.default)
})))
}
}
return ContextController.Items(content: .list(subActions), disablePositionLock: true, tip: nil)
}
c.pushItems(items: subItems)
})))
actions.append(.action(ContextMenuActionItem(text: "Set as Sticker Effect", icon: { _ in
return nil
}, action: { c, _ in
let stickersKey: PostboxViewKey = .orderedItemList(id: Namespaces.OrderedItemList.CloudPremiumStickers)
let subItems: Signal<ContextController.Items, NoError> = context.account.postbox.combinedView(keys: [stickersKey])
|> map { views -> [String] in
if let view = views.views[stickersKey] as? OrderedItemListView, !view.items.isEmpty {
return view.items.compactMap { item -> String? in
guard let mediaItem = item.contents.get(RecentMediaItem.self) else {
return nil
}
let file = mediaItem.media
for attribute in file.attributes {
switch attribute {
case let .Sticker(text, _, _):
return text
default:
break
}
}
return nil
}
} else {
return []
}
}
|> map { stickerNames -> ContextController.Items in
var subActions: [ContextMenuItem] = []
for stickerName in stickerNames {
subActions.append(.action(ContextMenuActionItem(text: stickerName, icon: { _ in
return nil
}, action: { _, f in
let _ = updateExperimentalUISettingsInteractively(accountManager: context.sharedContext.accountManager, { settings in
var settings = settings
var currentItems: [ExperimentalUISettings.AccountReactionOverrides.Item]
if let value = settings.accountStickerEffectOverrides.first(where: { $0.accountId == context.account.id.int64 }) {
currentItems = value.items
} else {
currentItems = []
}
currentItems.removeAll(where: { $0.key == stickerName })
currentItems.append(ExperimentalUISettings.AccountReactionOverrides.Item(
key: stickerName,
messageId: message.id,
mediaId: file.fileId
))
settings.accountStickerEffectOverrides.removeAll(where: { $0.accountId == context.account.id.int64 })
settings.accountStickerEffectOverrides.append(ExperimentalUISettings.AccountReactionOverrides(accountId: context.account.id.int64, items: currentItems))
return settings
}).start()
f(.default)
})))
}
return ContextController.Items(content: .list(subActions), disablePositionLock: true, tip: nil)
}
c.pushItems(items: subItems)
})))
actions.append(.separator)
break
}
}
}
}
var isReplyThreadHead = false

View File

@ -4,6 +4,28 @@ import TelegramCore
import SwiftSignalKit
public struct ExperimentalUISettings: Codable, Equatable {
public struct AccountReactionOverrides: Equatable, Codable {
public struct Item: Equatable, Codable {
public var key: String
public var messageId: MessageId
public var mediaId: MediaId
public init(key: String, messageId: MessageId, mediaId: MediaId) {
self.key = key
self.messageId = messageId
self.mediaId = mediaId
}
}
public var accountId: Int64
public var items: [Item]
public init(accountId: Int64, items: [Item]) {
self.accountId = accountId
self.items = items
}
}
public var keepChatNavigationStack: Bool
public var skipReadHistory: Bool
public var crashOnLongQueries: Bool
@ -22,6 +44,9 @@ public struct ExperimentalUISettings: Codable, Equatable {
public var snow: Bool
public var inlineStickers: Bool
public var localTranscription: Bool
public var enableReactionOverrides: Bool
public var accountReactionEffectOverrides: [AccountReactionOverrides]
public var accountStickerEffectOverrides: [AccountReactionOverrides]
public static var defaultSettings: ExperimentalUISettings {
return ExperimentalUISettings(
@ -42,7 +67,10 @@ public struct ExperimentalUISettings: Codable, Equatable {
experimentalBackground: false,
snow: false,
inlineStickers: false,
localTranscription: false
localTranscription: false,
enableReactionOverrides: false,
accountReactionEffectOverrides: [],
accountStickerEffectOverrides: []
)
}
@ -64,7 +92,10 @@ public struct ExperimentalUISettings: Codable, Equatable {
experimentalBackground: Bool,
snow: Bool,
inlineStickers: Bool,
localTranscription: Bool
localTranscription: Bool,
enableReactionOverrides: Bool,
accountReactionEffectOverrides: [AccountReactionOverrides],
accountStickerEffectOverrides: [AccountReactionOverrides]
) {
self.keepChatNavigationStack = keepChatNavigationStack
self.skipReadHistory = skipReadHistory
@ -84,6 +115,9 @@ public struct ExperimentalUISettings: Codable, Equatable {
self.snow = snow
self.inlineStickers = inlineStickers
self.localTranscription = localTranscription
self.enableReactionOverrides = enableReactionOverrides
self.accountReactionEffectOverrides = accountReactionEffectOverrides
self.accountStickerEffectOverrides = accountStickerEffectOverrides
}
public init(from decoder: Decoder) throws {
@ -107,6 +141,9 @@ public struct ExperimentalUISettings: Codable, Equatable {
self.snow = (try container.decodeIfPresent(Int32.self, forKey: "snow") ?? 0) != 0
self.inlineStickers = (try container.decodeIfPresent(Int32.self, forKey: "inlineStickers") ?? 0) != 0
self.localTranscription = (try container.decodeIfPresent(Int32.self, forKey: "localTranscription") ?? 0) != 0
self.enableReactionOverrides = try container.decodeIfPresent(Bool.self, forKey: "enableReactionOverrides") ?? false
self.accountReactionEffectOverrides = (try container.decodeIfPresent([AccountReactionOverrides].self, forKey: "accountReactionEffectOverrides")) ?? []
self.accountStickerEffectOverrides = (try container.decodeIfPresent([AccountReactionOverrides].self, forKey: "accountStickerEffectOverrides")) ?? []
}
public func encode(to encoder: Encoder) throws {
@ -130,6 +167,9 @@ public struct ExperimentalUISettings: Codable, Equatable {
try container.encode((self.snow ? 1 : 0) as Int32, forKey: "snow")
try container.encode((self.inlineStickers ? 1 : 0) as Int32, forKey: "inlineStickers")
try container.encode((self.localTranscription ? 1 : 0) as Int32, forKey: "localTranscription")
try container.encode(self.enableReactionOverrides, forKey: "enableReactionOverrides")
try container.encode(self.accountReactionEffectOverrides, forKey: "accountReactionEffectOverrides")
try container.encode(self.accountStickerEffectOverrides, forKey: "accountStickerEffectOverrides")
}
}