mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge commit 'a6292e752a7de0c7fd28f07b0a24c215d227e593'
This commit is contained in:
commit
f17f51b5a0
@ -588,6 +588,7 @@ public final class AnimatedStickerDirectFrameSource: AnimatedStickerFrameSource
|
|||||||
let decompressedData = TGGUnzipData(data, 8 * 1024 * 1024) ?? data
|
let decompressedData = TGGUnzipData(data, 8 * 1024 * 1024) ?? data
|
||||||
|
|
||||||
guard let animation = LottieInstance(data: decompressedData, fitzModifier: fitzModifier?.lottieFitzModifier ?? .none, colorReplacements: nil, cacheKey: "") else {
|
guard let animation = LottieInstance(data: decompressedData, fitzModifier: fitzModifier?.lottieFitzModifier ?? .none, colorReplacements: nil, cacheKey: "") else {
|
||||||
|
print("Could not load sticker data")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
self.animation = animation
|
self.animation = animation
|
||||||
|
@ -2197,12 +2197,14 @@ public final class ContextController: ViewController, StandalonePresentableContr
|
|||||||
public var content: Content
|
public var content: Content
|
||||||
public var context: AccountContext?
|
public var context: AccountContext?
|
||||||
public var reactionItems: [ReactionContextItem]
|
public var reactionItems: [ReactionContextItem]
|
||||||
|
public var disablePositionLock: Bool
|
||||||
public var tip: Tip?
|
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.content = content
|
||||||
self.context = context
|
self.context = context
|
||||||
self.reactionItems = reactionItems
|
self.reactionItems = reactionItems
|
||||||
|
self.disablePositionLock = disablePositionLock
|
||||||
self.tip = tip
|
self.tip = tip
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2210,6 +2212,7 @@ public final class ContextController: ViewController, StandalonePresentableContr
|
|||||||
self.content = .list([])
|
self.content = .list([])
|
||||||
self.context = nil
|
self.context = nil
|
||||||
self.reactionItems = []
|
self.reactionItems = []
|
||||||
|
self.disablePositionLock = false
|
||||||
self.tip = nil
|
self.tip = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -320,7 +320,10 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
|
|||||||
|
|
||||||
func pushItems(items: ContextController.Items) {
|
func pushItems(items: ContextController.Items) {
|
||||||
let currentScrollingState = self.getCurrentScrollingState()
|
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)
|
self.actionsStackNode.push(item: makeContextControllerActionsStackItem(items: items), currentScrollingState: currentScrollingState, positionLock: positionLock, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,6 +87,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
|||||||
case experimentalBackground(Bool)
|
case experimentalBackground(Bool)
|
||||||
case inlineStickers(Bool)
|
case inlineStickers(Bool)
|
||||||
case localTranscription(Bool)
|
case localTranscription(Bool)
|
||||||
|
case enableReactionOverrides(Bool)
|
||||||
case playerEmbedding(Bool)
|
case playerEmbedding(Bool)
|
||||||
case playlistPlayback(Bool)
|
case playlistPlayback(Bool)
|
||||||
case voiceConference
|
case voiceConference
|
||||||
@ -109,7 +110,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
|||||||
return DebugControllerSection.logging.rawValue
|
return DebugControllerSection.logging.rawValue
|
||||||
case .enableRaiseToSpeak, .keepChatNavigationStack, .skipReadHistory, .crashOnSlowQueries:
|
case .enableRaiseToSpeak, .keepChatNavigationStack, .skipReadHistory, .crashOnSlowQueries:
|
||||||
return DebugControllerSection.experiments.rawValue
|
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
|
return DebugControllerSection.experiments.rawValue
|
||||||
case .preferredVideoCodec:
|
case .preferredVideoCodec:
|
||||||
return DebugControllerSection.videoExperiments.rawValue
|
return DebugControllerSection.videoExperiments.rawValue
|
||||||
@ -188,16 +189,18 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
|||||||
return 31
|
return 31
|
||||||
case .localTranscription:
|
case .localTranscription:
|
||||||
return 32
|
return 32
|
||||||
case .resetInAppPurchases:
|
case .enableReactionOverrides:
|
||||||
return 33
|
return 33
|
||||||
case .playerEmbedding:
|
case .resetInAppPurchases:
|
||||||
return 34
|
return 34
|
||||||
case .playlistPlayback:
|
case .playerEmbedding:
|
||||||
return 35
|
return 35
|
||||||
case .voiceConference:
|
case .playlistPlayback:
|
||||||
return 36
|
return 36
|
||||||
|
case .voiceConference:
|
||||||
|
return 37
|
||||||
case let .preferredVideoCodec(index, _, _, _):
|
case let .preferredVideoCodec(index, _, _, _):
|
||||||
return 37 + index
|
return 38 + index
|
||||||
case .disableVideoAspectScaling:
|
case .disableVideoAspectScaling:
|
||||||
return 100
|
return 100
|
||||||
case .enableVoipTcp:
|
case .enableVoipTcp:
|
||||||
@ -970,6 +973,20 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
|||||||
})
|
})
|
||||||
}).start()
|
}).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):
|
case let .playerEmbedding(value):
|
||||||
return ItemListSwitchItem(presentationData: presentationData, title: "Player Embedding", value: value, sectionId: self.section, style: .blocks, updated: { value in
|
return ItemListSwitchItem(presentationData: presentationData, title: "Player Embedding", value: value, sectionId: self.section, style: .blocks, updated: { value in
|
||||||
let _ = arguments.sharedContext.accountManager.transaction ({ transaction 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(.experimentalBackground(experimentalSettings.experimentalBackground))
|
||||||
entries.append(.inlineStickers(experimentalSettings.inlineStickers))
|
entries.append(.inlineStickers(experimentalSettings.inlineStickers))
|
||||||
entries.append(.localTranscription(experimentalSettings.localTranscription))
|
entries.append(.localTranscription(experimentalSettings.localTranscription))
|
||||||
|
if case .internal = sharedContext.applicationBindings.appBuildType {
|
||||||
|
entries.append(.enableReactionOverrides(experimentalSettings.enableReactionOverrides))
|
||||||
|
}
|
||||||
entries.append(.resetInAppPurchases(presentationData.theme))
|
entries.append(.resetInAppPurchases(presentationData.theme))
|
||||||
entries.append(.playerEmbedding(experimentalSettings.playerEmbedding))
|
entries.append(.playerEmbedding(experimentalSettings.playerEmbedding))
|
||||||
entries.append(.playlistPlayback(experimentalSettings.playlistPlayback))
|
entries.append(.playlistPlayback(experimentalSettings.playlistPlayback))
|
||||||
|
@ -15,6 +15,7 @@ import MultilineTextComponent
|
|||||||
import BundleIconComponent
|
import BundleIconComponent
|
||||||
import SolidRoundedButtonComponent
|
import SolidRoundedButtonComponent
|
||||||
import Markdown
|
import Markdown
|
||||||
|
import TelegramUIPreferences
|
||||||
|
|
||||||
private final class GradientBackgroundComponent: Component {
|
private final class GradientBackgroundComponent: Component {
|
||||||
public let colors: [UIColor]
|
public let colors: [UIColor]
|
||||||
@ -523,6 +524,27 @@ private final class DemoSheetContent: CombinedComponent {
|
|||||||
|
|
||||||
super.init()
|
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)
|
let stickersKey: PostboxViewKey = .orderedItemList(id: Namespaces.OrderedItemList.CloudPremiumStickers)
|
||||||
self.disposable = (combineLatest(
|
self.disposable = (combineLatest(
|
||||||
queue: Queue.mainQueue(),
|
queue: Queue.mainQueue(),
|
||||||
@ -542,9 +564,33 @@ private final class DemoSheetContent: CombinedComponent {
|
|||||||
self.context.engine.data.get(
|
self.context.engine.data.get(
|
||||||
TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId),
|
TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId),
|
||||||
TelegramEngine.EngineData.Item.Configuration.PremiumPromo()
|
TelegramEngine.EngineData.Item.Configuration.PremiumPromo()
|
||||||
|
),
|
||||||
|
reactionOverrideMessages,
|
||||||
|
stickerOverrideMessages
|
||||||
)
|
)
|
||||||
)
|
|> map { reactions, items, data, reactionOverrideMessages, stickerOverrideMessages -> ([AvailableReactions.Reaction], [TelegramMediaFile], Bool?, PremiumPromoConfiguration?) in
|
||||||
|> map { reactions, items, data -> ([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 {
|
if let reactions = reactions {
|
||||||
var result: [TelegramMediaFile] = []
|
var result: [TelegramMediaFile] = []
|
||||||
if let items = items {
|
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 {
|
} else {
|
||||||
return ([], [], nil, nil)
|
return ([], [], nil, nil)
|
||||||
}
|
}
|
||||||
|
@ -97,13 +97,13 @@ private class StickerNode: ASDisplayNode {
|
|||||||
|
|
||||||
private var setupTimestamp: Double?
|
private var setupTimestamp: Double?
|
||||||
|
|
||||||
init(context: AccountContext, file: TelegramMediaFile) {
|
init(context: AccountContext, file: TelegramMediaFile, forceIsPremium: Bool) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.file = file
|
self.file = file
|
||||||
|
|
||||||
self.imageNode = TransformImageNode()
|
self.imageNode = TransformImageNode()
|
||||||
|
|
||||||
if file.isPremiumSticker {
|
if file.isPremiumSticker || forceIsPremium {
|
||||||
let animationNode = AnimatedStickerNode()
|
let animationNode = AnimatedStickerNode()
|
||||||
animationNode.automaticallyLoadFirstFrame = true
|
animationNode.automaticallyLoadFirstFrame = true
|
||||||
self.animationNode = animationNode
|
self.animationNode = animationNode
|
||||||
@ -124,8 +124,11 @@ private class StickerNode: ASDisplayNode {
|
|||||||
let source = AnimatedStickerResourceSource(account: self.context.account, resource: effect.resource, fitzModifier: nil)
|
let source = AnimatedStickerResourceSource(account: self.context.account, resource: effect.resource, fitzModifier: nil)
|
||||||
let additionalAnimationNode = AnimatedStickerNode()
|
let additionalAnimationNode = AnimatedStickerNode()
|
||||||
|
|
||||||
let pathPrefix = context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(effect.resource.id)
|
var pathPrefix: String?
|
||||||
additionalAnimationNode.setup(source: source, width: Int(fittedDimensions.width * 1.4), height: Int(fittedDimensions.height * 1.4), playbackMode: .loop, mode: .direct(cachePathPrefix: pathPrefix))
|
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
|
self.additionalAnimationNode = additionalAnimationNode
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -592,7 +595,7 @@ private class StickersCarouselNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
if let current = self.itemNodes[i] {
|
if let current = self.itemNodes[i] {
|
||||||
itemNode = current
|
itemNode = current
|
||||||
} else {
|
} else {
|
||||||
itemNode = StickerNode(context: self.context, file: self.stickers[i])
|
itemNode = StickerNode(context: self.context, file: self.stickers[i], forceIsPremium: true)
|
||||||
containerNode.addSubnode(itemNode)
|
containerNode.addSubnode(itemNode)
|
||||||
self.itemNodes[i] = itemNode
|
self.itemNodes[i] = itemNode
|
||||||
}
|
}
|
||||||
|
@ -1076,7 +1076,13 @@ public final class StandaloneReactionAnimation: ASDisplayNode {
|
|||||||
additionalAnimation = itemNode.item.applicationAnimation
|
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.frame = effectFrame
|
||||||
additionalAnimationNode.updateLayout(size: effectFrame.size)
|
additionalAnimationNode.updateLayout(size: effectFrame.size)
|
||||||
self.addSubnode(additionalAnimationNode)
|
self.addSubnode(additionalAnimationNode)
|
||||||
|
@ -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
|
var isReplyThreadHead = false
|
||||||
|
@ -4,6 +4,28 @@ import TelegramCore
|
|||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
|
|
||||||
public struct ExperimentalUISettings: Codable, Equatable {
|
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 keepChatNavigationStack: Bool
|
||||||
public var skipReadHistory: Bool
|
public var skipReadHistory: Bool
|
||||||
public var crashOnLongQueries: Bool
|
public var crashOnLongQueries: Bool
|
||||||
@ -22,6 +44,9 @@ public struct ExperimentalUISettings: Codable, Equatable {
|
|||||||
public var snow: Bool
|
public var snow: Bool
|
||||||
public var inlineStickers: Bool
|
public var inlineStickers: Bool
|
||||||
public var localTranscription: Bool
|
public var localTranscription: Bool
|
||||||
|
public var enableReactionOverrides: Bool
|
||||||
|
public var accountReactionEffectOverrides: [AccountReactionOverrides]
|
||||||
|
public var accountStickerEffectOverrides: [AccountReactionOverrides]
|
||||||
|
|
||||||
public static var defaultSettings: ExperimentalUISettings {
|
public static var defaultSettings: ExperimentalUISettings {
|
||||||
return ExperimentalUISettings(
|
return ExperimentalUISettings(
|
||||||
@ -42,7 +67,10 @@ public struct ExperimentalUISettings: Codable, Equatable {
|
|||||||
experimentalBackground: false,
|
experimentalBackground: false,
|
||||||
snow: false,
|
snow: false,
|
||||||
inlineStickers: false,
|
inlineStickers: false,
|
||||||
localTranscription: false
|
localTranscription: false,
|
||||||
|
enableReactionOverrides: false,
|
||||||
|
accountReactionEffectOverrides: [],
|
||||||
|
accountStickerEffectOverrides: []
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +92,10 @@ public struct ExperimentalUISettings: Codable, Equatable {
|
|||||||
experimentalBackground: Bool,
|
experimentalBackground: Bool,
|
||||||
snow: Bool,
|
snow: Bool,
|
||||||
inlineStickers: Bool,
|
inlineStickers: Bool,
|
||||||
localTranscription: Bool
|
localTranscription: Bool,
|
||||||
|
enableReactionOverrides: Bool,
|
||||||
|
accountReactionEffectOverrides: [AccountReactionOverrides],
|
||||||
|
accountStickerEffectOverrides: [AccountReactionOverrides]
|
||||||
) {
|
) {
|
||||||
self.keepChatNavigationStack = keepChatNavigationStack
|
self.keepChatNavigationStack = keepChatNavigationStack
|
||||||
self.skipReadHistory = skipReadHistory
|
self.skipReadHistory = skipReadHistory
|
||||||
@ -84,6 +115,9 @@ public struct ExperimentalUISettings: Codable, Equatable {
|
|||||||
self.snow = snow
|
self.snow = snow
|
||||||
self.inlineStickers = inlineStickers
|
self.inlineStickers = inlineStickers
|
||||||
self.localTranscription = localTranscription
|
self.localTranscription = localTranscription
|
||||||
|
self.enableReactionOverrides = enableReactionOverrides
|
||||||
|
self.accountReactionEffectOverrides = accountReactionEffectOverrides
|
||||||
|
self.accountStickerEffectOverrides = accountStickerEffectOverrides
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(from decoder: Decoder) throws {
|
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.snow = (try container.decodeIfPresent(Int32.self, forKey: "snow") ?? 0) != 0
|
||||||
self.inlineStickers = (try container.decodeIfPresent(Int32.self, forKey: "inlineStickers") ?? 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.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 {
|
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.snow ? 1 : 0) as Int32, forKey: "snow")
|
||||||
try container.encode((self.inlineStickers ? 1 : 0) as Int32, forKey: "inlineStickers")
|
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.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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user