mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-08 19:10:53 +00:00
Support spoilers
This commit is contained in:
parent
8a236faa16
commit
8d11af19ac
@ -1672,6 +1672,27 @@ public extension ContainedViewLayoutTransition {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func animateContents(layer: CALayer, from fromContents: Any) {
|
||||
guard case let .animated(duration, curve) = self else {
|
||||
return
|
||||
}
|
||||
guard let contents = layer.contents, CFGetTypeID(contents as CFTypeRef) == CGImage.typeID else {
|
||||
return
|
||||
}
|
||||
guard CFGetTypeID(fromContents as CFTypeRef) == CGImage.typeID else {
|
||||
return
|
||||
}
|
||||
|
||||
let contentsImage = contents as! CGImage
|
||||
let fromContentsImage = fromContents as! CGImage
|
||||
|
||||
if contentsImage === fromContentsImage {
|
||||
return
|
||||
}
|
||||
|
||||
layer.animate(from: fromContentsImage, to: contentsImage, keyPath: "contents", timingFunction: curve.timingFunction, duration: duration, delay: 0.0, mediaTimingFunction: curve.mediaTimingFunction, removeOnCompletion: true, additive: false)
|
||||
}
|
||||
}
|
||||
|
||||
public struct CombinedTransition {
|
||||
|
@ -8,7 +8,6 @@ import TextFormat
|
||||
import UrlEscaping
|
||||
import TelegramUniversalVideoContent
|
||||
import TextSelectionNode
|
||||
import InvisibleInkDustNode
|
||||
import Emoji
|
||||
import AnimatedStickerNode
|
||||
import TelegramAnimatedStickerNode
|
||||
@ -85,7 +84,6 @@ private func findQuoteRange(string: String, quoteText: String, offset: Int?) ->
|
||||
public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
private let containerNode: ASDisplayNode
|
||||
private let textNode: InteractiveTextNodeWithEntities
|
||||
private var dustNode: InvisibleInkDustNode?
|
||||
|
||||
private let textAccessibilityOverlayNode: TextAccessibilityOverlayNode
|
||||
public var statusNode: ChatMessageDateAndStatusNode?
|
||||
@ -112,6 +110,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
private var codeHighlightState: (id: EngineMessage.Id, specs: [CachedMessageSyntaxHighlight.Spec], disposable: Disposable)?
|
||||
|
||||
private var expandedBlockIds: Set<Int> = Set()
|
||||
private var displayContentsUnderSpoilers: Bool = false
|
||||
|
||||
override public var visibility: ListViewItemNodeVisibility {
|
||||
didSet {
|
||||
@ -162,6 +161,12 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
item.controllerInteraction.requestMessageUpdate(item.message.id, false)
|
||||
}
|
||||
self.textNode.textNode.requestDisplayContentsUnderSpoilers = { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.updateDisplayContentsUnderSpoilers(value: true)
|
||||
}
|
||||
self.textNode.textNode.canHandleTapAtPoint = { [weak self] point in
|
||||
guard let self else {
|
||||
return false
|
||||
@ -192,6 +197,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
|
||||
let currentCachedChatMessageText = self.cachedChatMessageText
|
||||
let expandedBlockIds = self.expandedBlockIds
|
||||
let displayContentsUnderSpoilers = self.displayContentsUnderSpoilers
|
||||
|
||||
return { item, layoutConstants, _, _, _, _ in
|
||||
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 0.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
|
||||
@ -579,7 +585,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
cutout: nil,
|
||||
insets: textInsets,
|
||||
lineColor: messageTheme.accentControlColor,
|
||||
displayContentsUnderSpoilers: false,
|
||||
displayContentsUnderSpoilers: displayContentsUnderSpoilers,
|
||||
customTruncationToken: customTruncationToken,
|
||||
expandedBlocks: expandedBlockIds
|
||||
))
|
||||
@ -677,31 +683,6 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
))
|
||||
animation.animator.updateFrame(layer: strongSelf.textNode.textNode.layer, frame: textFrame, completion: nil)
|
||||
|
||||
/*if let (_, spoilerTextApply) = spoilerTextLayoutAndApply {
|
||||
let spoilerTextNode = spoilerTextApply(InteractiveTextNodeWithEntities.Arguments(context: item.context, cache: item.controllerInteraction.presentationContext.animationCache, renderer: item.controllerInteraction.presentationContext.animationRenderer, placeholderColor: messageTheme.mediaPlaceholderColor, attemptSynchronous: synchronousLoads, animation: animation))
|
||||
|
||||
strongSelf.spoilerTextNode?.textNode.frame = textFrame
|
||||
|
||||
let dustNode: InvisibleInkDustNode
|
||||
if let current = strongSelf.dustNode {
|
||||
dustNode = current
|
||||
} else {
|
||||
dustNode = InvisibleInkDustNode(textNode: spoilerTextNode.textNode, enableAnimations: item.context.sharedContext.energyUsageSettings.fullTranslucency && !item.presentationData.isPreview)
|
||||
strongSelf.dustNode = dustNode
|
||||
strongSelf.containerNode.insertSubnode(dustNode, aboveSubnode: spoilerTextNode.textNode)
|
||||
}
|
||||
dustNode.frame = textFrame.insetBy(dx: -3.0, dy: -3.0).offsetBy(dx: 0.0, dy: 3.0)
|
||||
dustNode.update(size: dustNode.frame.size, color: messageTheme.secondaryTextColor, textColor: messageTheme.primaryTextColor, rects: textLayout.spoilers.map { $0.1.offsetBy(dx: 3.0, dy: 3.0).insetBy(dx: 1.0, dy: 1.0) }, wordRects: textLayout.spoilerWords.map { $0.1.offsetBy(dx: 3.0, dy: 3.0).insetBy(dx: 1.0, dy: 1.0) })
|
||||
} else if let spoilerTextNode = strongSelf.spoilerTextNode {
|
||||
strongSelf.spoilerTextNode = nil
|
||||
spoilerTextNode.textNode.removeFromSupernode()
|
||||
|
||||
if let dustNode = strongSelf.dustNode {
|
||||
strongSelf.dustNode = nil
|
||||
dustNode.removeFromSupernode()
|
||||
}
|
||||
}*/
|
||||
|
||||
switch strongSelf.visibility {
|
||||
case .none:
|
||||
strongSelf.textNode.visibilityRect = nil
|
||||
@ -866,7 +847,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
let textNodeFrame = self.textNode.textNode.frame
|
||||
let textLocalPoint = CGPoint(x: point.x - textNodeFrame.minX, y: point.y - textNodeFrame.minY)
|
||||
if let (index, attributes) = self.textNode.textNode.attributesAtPoint(textLocalPoint) {
|
||||
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler)], !(self.dustNode?.isRevealed ?? true) {
|
||||
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler)], !self.displayContentsUnderSpoilers {
|
||||
return ChatMessageBubbleContentTapAction(content: .none)
|
||||
} else if let url = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] as? String {
|
||||
var concealed = true
|
||||
@ -1058,8 +1039,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
}
|
||||
|
||||
if let spoilerRects = spoilerRects, !spoilerRects.isEmpty, let dustNode = self.dustNode, !dustNode.isRevealed {
|
||||
|
||||
if let spoilerRects = spoilerRects, !spoilerRects.isEmpty, !self.displayContentsUnderSpoilers {
|
||||
} else if let rects = rects {
|
||||
let linkHighlightingNode: LinkHighlightingNode
|
||||
if let current = self.linkHighlightingNode {
|
||||
@ -1329,11 +1309,11 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if let dustNode = strongSelf.dustNode, !dustNode.isRevealed, let textLayout = strongSelf.textNode.textNode.cachedLayout, textLayout.segments.contains(where: { !$0.spoilers.isEmpty }), let selectionRange {
|
||||
if !strongSelf.displayContentsUnderSpoilers, let textLayout = strongSelf.textNode.textNode.cachedLayout, textLayout.segments.contains(where: { !$0.spoilers.isEmpty }), let selectionRange {
|
||||
for segment in textLayout.segments {
|
||||
for (spoilerRange, _) in segment.spoilers {
|
||||
if let intersection = selectionRange.intersection(spoilerRange), intersection.length > 0 {
|
||||
dustNode.update(revealed: true)
|
||||
strongSelf.updateDisplayContentsUnderSpoilers(value: true)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -1389,12 +1369,22 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
})
|
||||
}
|
||||
|
||||
if let dustNode = self.dustNode, dustNode.isRevealed {
|
||||
dustNode.update(revealed: false)
|
||||
if self.displayContentsUnderSpoilers {
|
||||
self.updateDisplayContentsUnderSpoilers(value: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func updateDisplayContentsUnderSpoilers(value: Bool) {
|
||||
if self.displayContentsUnderSpoilers == value {
|
||||
return
|
||||
}
|
||||
self.displayContentsUnderSpoilers = value
|
||||
if let item = self.item {
|
||||
item.controllerInteraction.requestMessageUpdate(item.message.id, false)
|
||||
}
|
||||
}
|
||||
|
||||
override public func reactionTargetView(value: MessageReaction.Reaction) -> UIView? {
|
||||
if let statusNode = self.statusNode, !statusNode.isHidden {
|
||||
return statusNode.reactionView(value: value)
|
||||
|
@ -390,7 +390,7 @@ public final class InteractiveTextNodeLayout: NSObject {
|
||||
fileprivate let textShadowColor: UIColor?
|
||||
fileprivate let textShadowBlur: CGFloat?
|
||||
fileprivate let textStroke: (UIColor, CGFloat)?
|
||||
fileprivate let displayContentsUnderSpoilers: Bool
|
||||
public let displayContentsUnderSpoilers: Bool
|
||||
fileprivate let expandedBlocks: Set<Int>
|
||||
|
||||
fileprivate init(
|
||||
@ -441,6 +441,33 @@ public final class InteractiveTextNodeLayout: NSObject {
|
||||
self.expandedBlocks = expandedBlocks
|
||||
}
|
||||
|
||||
func withUpdatedDisplayContentsUnderSpoilers(_ displayContentsUnderSpoilers: Bool) -> InteractiveTextNodeLayout {
|
||||
return InteractiveTextNodeLayout(
|
||||
attributedString: self.attributedString,
|
||||
maximumNumberOfLines: self.maximumNumberOfLines,
|
||||
truncationType: self.truncationType,
|
||||
constrainedSize: self.constrainedSize,
|
||||
explicitAlignment: self.explicitAlignment,
|
||||
resolvedAlignment: self.resolvedAlignment,
|
||||
verticalAlignment: self.verticalAlignment,
|
||||
lineSpacing: self.lineSpacing,
|
||||
cutout: self.cutout,
|
||||
insets: self.insets,
|
||||
size: self.size,
|
||||
rawTextSize: self.rawTextSize,
|
||||
truncated: self.truncated,
|
||||
firstLineOffset: self.firstLineOffset,
|
||||
segments: self.segments,
|
||||
backgroundColor: self.backgroundColor,
|
||||
lineColor: self.lineColor,
|
||||
textShadowColor: self.textShadowColor,
|
||||
textShadowBlur: self.textShadowBlur,
|
||||
textStroke: self.textStroke,
|
||||
displayContentsUnderSpoilers: displayContentsUnderSpoilers,
|
||||
expandedBlocks: self.expandedBlocks
|
||||
)
|
||||
}
|
||||
|
||||
public var numberOfLines: Int {
|
||||
var result = 0
|
||||
for segment in self.segments {
|
||||
@ -1075,8 +1102,11 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn
|
||||
public var renderContentTypes: RenderContentTypes = .all
|
||||
private var contentItemLayers: [Int: TextContentItemLayer] = [:]
|
||||
|
||||
private var isDisplayingContentsUnderSpoilers: Bool?
|
||||
|
||||
public var canHandleTapAtPoint: ((CGPoint) -> Bool)?
|
||||
public var requestToggleBlockCollapsed: ((Int) -> Void)?
|
||||
public var requestDisplayContentsUnderSpoilers: (() -> Void)?
|
||||
private var tapRecognizer: UITapGestureRecognizer?
|
||||
|
||||
public var currentText: NSAttributedString? {
|
||||
@ -1535,7 +1565,10 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn
|
||||
var descent: CGFloat = 0.0
|
||||
CTLineGetTypographicBounds(line.line, &ascent, &descent, nil)
|
||||
|
||||
let isHiddenBySpoiler = attributes[NSAttributedString.Key(rawValue: "Attribute__Spoiler")] != nil || attributes[NSAttributedString.Key(rawValue: "TelegramSpoiler")] != nil
|
||||
var isHiddenBySpoiler = attributes[NSAttributedString.Key(rawValue: "Attribute__Spoiler")] != nil || attributes[NSAttributedString.Key(rawValue: "TelegramSpoiler")] != nil
|
||||
if displayContentsUnderSpoilers {
|
||||
isHiddenBySpoiler = false
|
||||
}
|
||||
|
||||
addEmbeddedItem(item: embeddedItem, isHiddenBySpoiler: isHiddenBySpoiler, line: line, ascent: ascent, descent: descent, startIndex: range.location, endIndex: range.location + range.length)
|
||||
}
|
||||
@ -1648,6 +1681,10 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn
|
||||
return
|
||||
}
|
||||
|
||||
let animateContents = self.isDisplayingContentsUnderSpoilers != nil && self.isDisplayingContentsUnderSpoilers != cachedLayout.displayContentsUnderSpoilers && animation.isAnimated
|
||||
let synchronous = animateContents
|
||||
self.isDisplayingContentsUnderSpoilers = cachedLayout.displayContentsUnderSpoilers
|
||||
|
||||
let topLeftOffset = CGPoint(x: cachedLayout.insets.left, y: cachedLayout.insets.top)
|
||||
|
||||
var validIds: [Int] = []
|
||||
@ -1701,7 +1738,7 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn
|
||||
self.layer.addSublayer(contentItemLayer)
|
||||
}
|
||||
|
||||
contentItemLayer.update(item: contentItem, animation: contentItemAnimation)
|
||||
contentItemLayer.update(item: contentItem, animation: contentItemAnimation, synchronously: synchronous, animateContents: animateContents && contentItemAnimation.isAnimated)
|
||||
|
||||
contentItemAnimation.animator.updateFrame(layer: contentItemLayer, frame: contentItemFrame, completion: nil)
|
||||
}
|
||||
@ -1736,6 +1773,12 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn
|
||||
@objc private func tapGesture(_ recognizer: UITapGestureRecognizer) {
|
||||
if case .ended = recognizer.state {
|
||||
let point = recognizer.location(in: self.view)
|
||||
if let cachedLayout = self.cachedLayout, !cachedLayout.displayContentsUnderSpoilers, let (_, attributes) = self.attributesAtPoint(point) {
|
||||
if attributes[NSAttributedString.Key(rawValue: "Attribute__Spoiler")] != nil || attributes[NSAttributedString.Key(rawValue: "TelegramSpoiler")] != nil {
|
||||
self.requestDisplayContentsUnderSpoilers?()
|
||||
return
|
||||
}
|
||||
}
|
||||
if let blockId = self.collapsibleBlockAtPoint(point) {
|
||||
self.requestToggleBlockCollapsed?(blockId)
|
||||
}
|
||||
@ -1746,7 +1789,7 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn
|
||||
let existingLayout: InteractiveTextNodeLayout? = maybeNode?.cachedLayout
|
||||
|
||||
return { arguments in
|
||||
let layout: InteractiveTextNodeLayout
|
||||
var layout: InteractiveTextNodeLayout
|
||||
|
||||
if let existingLayout = existingLayout, existingLayout.constrainedSize == arguments.constrainedSize && existingLayout.maximumNumberOfLines == arguments.maximumNumberOfLines && existingLayout.truncationType == arguments.truncationType && existingLayout.cutout == arguments.cutout && existingLayout.explicitAlignment == arguments.alignment && existingLayout.lineSpacing.isEqual(to: arguments.lineSpacing) && existingLayout.expandedBlocks == arguments.expandedBlocks {
|
||||
let stringMatch: Bool
|
||||
@ -1772,6 +1815,9 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn
|
||||
|
||||
if stringMatch {
|
||||
layout = existingLayout
|
||||
if layout.displayContentsUnderSpoilers != arguments.displayContentsUnderSpoilers {
|
||||
layout = layout.withUpdatedDisplayContentsUnderSpoilers(arguments.displayContentsUnderSpoilers)
|
||||
}
|
||||
} else {
|
||||
layout = InteractiveTextNode.calculateLayout(attributedString: arguments.attributedString, minimumNumberOfLines: arguments.minimumNumberOfLines, maximumNumberOfLines: arguments.maximumNumberOfLines, truncationType: arguments.truncationType, backgroundColor: arguments.backgroundColor, constrainedSize: arguments.constrainedSize, alignment: arguments.alignment, verticalAlignment: arguments.verticalAlignment, lineSpacingFactor: arguments.lineSpacing, cutout: arguments.cutout, insets: arguments.insets, lineColor: arguments.lineColor, textShadowColor: arguments.textShadowColor, textShadowBlur: arguments.textShadowBlur, textStroke: arguments.textStroke, displayContentsUnderSpoilers: arguments.displayContentsUnderSpoilers, customTruncationToken: arguments.customTruncationToken, expandedBlocks: arguments.expandedBlocks)
|
||||
}
|
||||
@ -1961,7 +2007,7 @@ final class TextContentItemLayer: SimpleLayer {
|
||||
if attributes["Attribute__EmbeddedItem"] != nil {
|
||||
continue
|
||||
}
|
||||
if hasHiddenSpoilers && attributes["Attribute__Spoiler"] != nil || attributes["TelegramSpoiler"] != nil {
|
||||
if hasHiddenSpoilers && (attributes["Attribute__Spoiler"] != nil || attributes["TelegramSpoiler"] != nil) {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -2152,9 +2198,8 @@ final class TextContentItemLayer: SimpleLayer {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func update(item: TextContentItem, animation: ListViewItemUpdateAnimation, synchronously: Bool = false) {
|
||||
func update(item: TextContentItem, animation: ListViewItemUpdateAnimation, synchronously: Bool = false, animateContents: Bool = false) {
|
||||
self.item = item
|
||||
self.setNeedsDisplay()
|
||||
|
||||
let contentFrame = CGRect(origin: CGPoint(), size: item.size)
|
||||
var effectiveContentFrame = contentFrame
|
||||
@ -2313,7 +2358,11 @@ final class TextContentItemLayer: SimpleLayer {
|
||||
|
||||
self.renderNode.params = RenderParams(size: contentFrame.size, item: item, mask: staticContentMask)
|
||||
if synchronously {
|
||||
let previousContents = self.renderNode.layer.contents
|
||||
self.renderNode.displayImmediately()
|
||||
if animateContents, let previousContents {
|
||||
animation.transition.animateContents(layer: self.renderNode.layer, from: previousContents)
|
||||
}
|
||||
} else {
|
||||
self.renderNode.setNeedsDisplay()
|
||||
}
|
||||
|
@ -257,6 +257,11 @@ public final class InteractiveTextNodeWithEntities {
|
||||
) {
|
||||
self.enableLooping = context.sharedContext.energyUsageSettings.loopEmoji
|
||||
|
||||
var displayContentsUnderSpoilers = false
|
||||
if let textLayout {
|
||||
displayContentsUnderSpoilers = textLayout.displayContentsUnderSpoilers
|
||||
}
|
||||
|
||||
var nextIndexById: [Int64: Int] = [:]
|
||||
var validIds: [InlineStickerItemLayer.Key] = []
|
||||
|
||||
@ -291,6 +296,7 @@ public final class InteractiveTextNodeWithEntities {
|
||||
itemFrame.origin.y += segmentItem.contentOffset.y
|
||||
|
||||
let itemLayerData: InlineStickerItemLayerData
|
||||
var itemLayerTransition = animation.transition
|
||||
if let current = self.inlineStickerItemLayers[id] {
|
||||
itemLayerData = current
|
||||
itemLayerData.itemLayer.dynamicColor = item.textColor
|
||||
@ -299,6 +305,7 @@ public final class InteractiveTextNodeWithEntities {
|
||||
segmentLayer.addSublayer(itemLayerData.itemLayer)
|
||||
}
|
||||
} else {
|
||||
itemLayerTransition = .immediate
|
||||
let pointSize = floor(itemSize * 1.3)
|
||||
itemLayerData = InlineStickerItemLayerData(itemLayer: InlineStickerItemLayer(context: context, userLocation: .other, attemptSynchronousLoad: attemptSynchronousLoad, emoji: stickerItem.emoji, file: stickerItem.file, cache: cache, renderer: renderer, placeholderColor: placeholderColor, pointSize: CGSize(width: pointSize, height: pointSize), dynamicColor: item.textColor))
|
||||
self.inlineStickerItemLayers[id] = itemLayerData
|
||||
@ -307,7 +314,7 @@ public final class InteractiveTextNodeWithEntities {
|
||||
itemLayerData.itemLayer.isVisibleForAnimations = self.enableLooping && self.isItemVisible(itemRect: itemFrame.offsetBy(dx: -segmentItem.contentOffset.x, dy: -segmentItem.contentOffset.x))
|
||||
}
|
||||
|
||||
itemLayerData.itemLayer.opacity = item.isHiddenBySpoiler ? 0.0 : 1.0
|
||||
itemLayerTransition.updateAlpha(layer: itemLayerData.itemLayer, alpha: item.isHiddenBySpoiler ? 0.0 : 1.0)
|
||||
|
||||
itemLayerData.itemLayer.frame = itemFrame
|
||||
itemLayerData.rect = itemFrame.offsetBy(dx: -segmentItem.contentOffset.x, dy: -segmentItem.contentOffset.y)
|
||||
@ -337,6 +344,8 @@ public final class InteractiveTextNodeWithEntities {
|
||||
rects: segment.spoilers.map { $0.1.offsetBy(dx: 3.0 + segmentItem.contentOffset.x, dy: segmentItem.contentOffset.y + 3.0).insetBy(dx: 1.0, dy: 1.0) },
|
||||
wordRects: segment.spoilerWords.map { $0.1.offsetBy(dx: segmentItem.contentOffset.x + 3.0, dy: segmentItem.contentOffset.y + 3.0).insetBy(dx: 1.0, dy: 1.0) }
|
||||
)
|
||||
|
||||
animation.transition.updateAlpha(node: dustEffectNode, alpha: displayContentsUnderSpoilers ? 0.0 : 1.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user