Use static spoiler when energy saving

This commit is contained in:
Ilya Laktyushin 2023-03-03 16:48:20 +04:00
parent 6fa3948d22
commit 9fddaf9f96
13 changed files with 229 additions and 144 deletions

View File

@ -1038,7 +1038,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
if let current = self.dustNode {
dustNode = current
} else {
dustNode = InvisibleInkDustNode(textNode: nil)
dustNode = InvisibleInkDustNode(textNode: nil, enableAnimations: self.context.sharedContext.energyUsageSettings.fullTranslucency)
dustNode.alpha = self.spoilersRevealed ? 0.0 : 1.0
dustNode.isUserInteractionEnabled = false
textInputNode.textView.addSubview(dustNode.view)
@ -1298,7 +1298,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
private func updateOneLineSpoiler() {
if let textLayout = self.oneLineNode.textNode.cachedLayout, !textLayout.spoilers.isEmpty {
if self.oneLineDustNode == nil {
let oneLineDustNode = InvisibleInkDustNode(textNode: nil)
let oneLineDustNode = InvisibleInkDustNode(textNode: nil, enableAnimations: self.context.sharedContext.energyUsageSettings.fullTranslucency)
self.oneLineDustNode = oneLineDustNode
self.oneLineNode.textNode.supernode?.insertSubnode(oneLineDustNode, aboveSubnode: self.oneLineNode.textNode)

View File

@ -549,7 +549,7 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
if let textLayout = self.currentOptionNode.cachedLayout, !textLayout.spoilers.isEmpty {
if self.dustNode == nil {
let dustNode = InvisibleInkDustNode(textNode: nil)
let dustNode = InvisibleInkDustNode(textNode: nil, enableAnimations: true)
self.dustNode = dustNode
self.currentOptionNode.supernode?.insertSubnode(dustNode, aboveSubnode: self.currentOptionNode)

View File

@ -3124,7 +3124,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
if let current = strongSelf.dustNode {
dustNode = current
} else {
dustNode = InvisibleInkDustNode(textNode: nil)
dustNode = InvisibleInkDustNode(textNode: nil, enableAnimations: item.context.sharedContext.energyUsageSettings.fullTranslucency)
dustNode.isUserInteractionEnabled = false
strongSelf.dustNode = dustNode

View File

@ -813,7 +813,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
self.spoilerTextNode = spoilerTextNode
self.textNode.supernode?.insertSubnode(spoilerTextNode, aboveSubnode: self.textNode)
let dustNode = InvisibleInkDustNode(textNode: spoilerTextNode)
let dustNode = InvisibleInkDustNode(textNode: spoilerTextNode, enableAnimations: self.context.sharedContext.energyUsageSettings.fullTranslucency)
self.dustNode = dustNode
spoilerTextNode.supernode?.insertSubnode(dustNode, aboveSubnode: spoilerTextNode)

View File

@ -6,6 +6,25 @@ import AsyncDisplayKit
import Display
import AppBundle
import LegacyComponents
import GameplayKit
private struct ArbitraryRandomNumberGenerator : RandomNumberGenerator {
init(seed: Int) { srand48(seed) }
func next() -> UInt64 { return UInt64(drand48() * Double(UInt64.max)) }
}
// mutating func next() -> UInt64 {
// // GKRandom produces values in [INT32_MIN, INT32_MAX] range; hence we need two numbers to produce 64-bit value.
// let next1 = UInt64(bitPattern: Int64(gkrandom.nextInt()))
// let next2 = UInt64(bitPattern: Int64(gkrandom.nextInt()))
// return next1 ^ (next2 << 32)
// }
//
// init(seed: UInt64) {
// self.gkrandom = GKMersenneTwisterRandomSource(seed: seed)
// }
//
// private let gkrandom: GKRandom
//}
func createEmitterBehavior(type: String) -> NSObject {
let selector = ["behaviorWith", "Type:"].joined(separator: "")
@ -45,6 +64,7 @@ func generateMaskImage(size originalSize: CGSize, position: CGPoint, inverse: Bo
public class InvisibleInkDustNode: ASDisplayNode {
private var currentParams: (size: CGSize, color: UIColor, textColor: UIColor, rects: [CGRect], wordRects: [CGRect])?
private var animColor: CGColor?
private let enableAnimations: Bool
private weak var textNode: TextNode?
private let textMaskNode: ASDisplayNode
@ -57,11 +77,15 @@ public class InvisibleInkDustNode: ASDisplayNode {
private let emitterSpotNode: ASImageNode
private let emitterMaskFillNode: ASDisplayNode
private var staticNode: ASImageNode?
private var staticParams: (size: CGSize, color: UIColor, rects: [CGRect])?
public var isRevealed = false
private var isExploding = false
public init(textNode: TextNode?) {
public init(textNode: TextNode?, enableAnimations: Bool) {
self.textNode = textNode
self.enableAnimations = enableAnimations
self.emitterNode = ASDisplayNode()
self.emitterNode.isUserInteractionEnabled = false
@ -94,6 +118,7 @@ public class InvisibleInkDustNode: ASDisplayNode {
public override func didLoad() {
super.didLoad()
if self.enableAnimations {
let emitter = CAEmitterCell()
emitter.contents = UIImage(bundleImageName: "Components/TextSpeckle")?.cgImage
emitter.contentsScale = 1.8
@ -135,6 +160,11 @@ public class InvisibleInkDustNode: ASDisplayNode {
self.emitterLayer = emitterLayer
self.emitterNode.layer.addSublayer(emitterLayer)
} else {
let staticNode = ASImageNode()
self.staticNode = staticNode
self.addSubnode(staticNode)
}
self.updateEmitter()
@ -170,6 +200,8 @@ public class InvisibleInkDustNode: ASDisplayNode {
}
self.isRevealed = true
if self.enableAnimations {
self.isExploding = true
let position = gestureRecognizer.location(in: self.view)
@ -233,13 +265,21 @@ public class InvisibleInkDustNode: ASDisplayNode {
self.emitterSpotNode.layer.removeAllAnimations()
self.emitterMaskFillNode.layer.removeAllAnimations()
}
} else {
textNode.alpha = 1.0
textNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
self.staticNode?.alpha = 0.0
self.staticNode?.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25)
}
}
private func updateEmitter() {
guard let (size, color, _, _, wordRects) = self.currentParams else {
guard let (size, color, _, lineRects, wordRects) = self.currentParams else {
return
}
if self.enableAnimations {
self.emitter?.color = self.animColor ?? color.cgColor
self.emitterLayer?.setValue(wordRects, forKey: "emitterRects")
self.emitterLayer?.frame = CGRect(origin: CGPoint(), size: size)
@ -256,16 +296,68 @@ public class InvisibleInkDustNode: ASDisplayNode {
Queue.mainQueue().async {
self.emitter?.birthRate = min(100000, square * 0.35)
}
} else {
if let staticParams = self.staticParams, staticParams.size == size && staticParams.color == color && staticParams.rects == lineRects && self.staticNode?.image != nil {
return
}
self.staticParams = (size, color, lineRects)
let start = CACurrentMediaTime()
var combinedRect: CGRect?
var combinedRects: [CGRect] = []
for rect in lineRects {
if let currentRect = combinedRect {
if abs(currentRect.minY - rect.minY) < 1.0 && abs(currentRect.maxY - rect.maxY) < 1.0 {
combinedRect = currentRect.union(rect)
} else {
combinedRects.append(currentRect.insetBy(dx: 0.0, dy: -1.0 + UIScreenPixel))
combinedRect = rect
}
} else {
combinedRect = rect
}
}
if let combinedRect {
combinedRects.append(combinedRect.insetBy(dx: 0.0, dy: -1.0))
}
print("combining \(CACurrentMediaTime() - start)")
var generator = ArbitraryRandomNumberGenerator(seed: 1)
let image = generateImage(size, rotatedContext: { size, context in
let bounds = CGRect(origin: .zero, size: size)
context.clear(bounds)
context.setFillColor(color.cgColor)
for rect in combinedRects {
if rect.width > 10.0 {
let rate = Int(rect.width * rect.height * 0.25)
for _ in 0 ..< rate {
let location = CGPoint(x: .random(in: rect.minX ..< rect.maxX, using: &generator), y: .random(in: rect.minY ..< rect.maxY, using: &generator))
context.fillEllipse(in: CGRect(origin: location, size: CGSize(width: 1.0, height: 1.0)))
}
}
}
})
self.staticNode?.frame = CGRect(origin: CGPoint(), size: size)
self.staticNode?.image = image
print("total draw \(CACurrentMediaTime() - start)")
}
}
public func update(size: CGSize, color: UIColor, textColor: UIColor, rects: [CGRect], wordRects: [CGRect]) {
self.currentParams = (size, color, textColor, rects, wordRects)
self.emitterNode.frame = CGRect(origin: CGPoint(), size: size)
self.emitterMaskNode.frame = self.emitterNode.bounds
self.emitterMaskFillNode.frame = self.emitterNode.bounds
let bounds = CGRect(origin: CGPoint(), size: size)
self.emitterNode.frame = bounds
self.emitterMaskNode.frame = bounds
self.emitterMaskFillNode.frame = bounds
self.textMaskNode.frame = CGRect(origin: CGPoint(x: 3.0, y: 3.0), size: size)
self.staticNode?.frame = bounds
if self.isNodeLoaded {
self.updateEmitter()
}

View File

@ -249,12 +249,6 @@ public func cacheAnimatedStickerFrames(data: Data, size: CGSize, fitzModifier: E
subscriber.putNext(.tempFile(tempFile))
subscriber.putCompletion()
/*print("animation render time \(CACurrentMediaTime() - startTime)")
print("of which drawing time \(drawingTime)")
print("of which appending time \(appendingTime)")
print("of which delta time \(deltaTime)")
print("of which compression time \(compressionTime)")*/
}
}
}))
@ -399,12 +393,6 @@ public func cacheVideoStickerFrames(path: String, size: CGSize, cacheKey: String
subscriber.putNext(.tempFile(tempFile))
subscriber.putCompletion()
/*print("animation render time \(CACurrentMediaTime() - startTime)")
print("of which drawing time \(drawingTime)")
print("of which appending time \(appendingTime)")
print("of which delta time \(deltaTime)")
print("of which compression time \(compressionTime)")*/
}))
return ActionDisposable {

View File

@ -316,7 +316,7 @@ class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
if let current = strongSelf.dustNode {
dustNode = current
} else {
dustNode = InvisibleInkDustNode(textNode: nil)
dustNode = InvisibleInkDustNode(textNode: nil, enableAnimations: item.context.sharedContext.energyUsageSettings.fullTranslucency)
dustNode.isUserInteractionEnabled = false
strongSelf.dustNode = dustNode
strongSelf.insertSubnode(dustNode, aboveSubnode: strongSelf.labelNode.textNode)

View File

@ -436,12 +436,13 @@ final class ChatMessageNotificationItemNode: NotificationItemNode {
transition.updateFrame(node: self.imageNode, frame: CGRect(origin: CGPoint(x: width - 10.0 - imageSize.width, y: (panelHeight - imageSize.height) / 2.0), size: imageSize))
if !textLayout.spoilers.isEmpty, let presentationData = self.item?.context.sharedContext.currentPresentationData.with({ $0 }) {
if !textLayout.spoilers.isEmpty, let item = self.item {
let presentationData = item.context.sharedContext.currentPresentationData.with({ $0 })
let dustNode: InvisibleInkDustNode
if let current = self.dustNode {
dustNode = current
} else {
dustNode = InvisibleInkDustNode(textNode: nil)
dustNode = InvisibleInkDustNode(textNode: nil, enableAnimations: item.context.sharedContext.energyUsageSettings.fullTranslucency)
dustNode.isUserInteractionEnabled = false
self.dustNode = dustNode
self.insertSubnode(dustNode, aboveSubnode: self.textNode.textNode)

View File

@ -344,7 +344,7 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
if let current = node.dustNode {
dustNode = current
} else {
dustNode = InvisibleInkDustNode(textNode: nil)
dustNode = InvisibleInkDustNode(textNode: nil, enableAnimations: arguments.context.sharedContext.energyUsageSettings.fullTranslucency)
dustNode.isUserInteractionEnabled = false
node.dustNode = dustNode
node.contentNode.insertSubnode(dustNode, aboveSubnode: textNode.textNode)

View File

@ -485,7 +485,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
if let current = strongSelf.dustNode {
dustNode = current
} else {
dustNode = InvisibleInkDustNode(textNode: spoilerTextNode.textNode)
dustNode = InvisibleInkDustNode(textNode: spoilerTextNode.textNode, enableAnimations: item.context.sharedContext.energyUsageSettings.fullTranslucency)
strongSelf.dustNode = dustNode
strongSelf.insertSubnode(dustNode, aboveSubnode: spoilerTextNode.textNode)
}

View File

@ -764,7 +764,7 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode {
if let current = strongSelf.dustNode {
dustNode = current
} else {
dustNode = InvisibleInkDustNode(textNode: spoilerTextNode.textNode)
dustNode = InvisibleInkDustNode(textNode: spoilerTextNode.textNode, enableAnimations: strongSelf.context.sharedContext.energyUsageSettings.fullTranslucency)
strongSelf.dustNode = dustNode
strongSelf.contentTextContainer.insertSubnode(dustNode, aboveSubnode: spoilerTextNode.textNode)
}

View File

@ -2289,10 +2289,12 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
if let start = textInputNode.textView.position(from: beginning, offset: startIndex), let end = textInputNode.textView.position(from: start, offset: endIndex - startIndex), let textRange = textInputNode.textView.textRange(from: start, to: end) {
let textRects = textInputNode.textView.selectionRects(for: textRange)
for textRect in textRects {
if textRect.rect.width > 1.0 && textRect.rect.size.height > 1.0 {
rects.append(textRect.rect.insetBy(dx: 1.0, dy: 1.0).offsetBy(dx: 0.0, dy: 1.0))
}
}
}
}
var startIndex: Int?
var currentIndex: Int?
@ -2335,7 +2337,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
if let current = self.dustNode {
dustNode = current
} else {
dustNode = InvisibleInkDustNode(textNode: nil)
dustNode = InvisibleInkDustNode(textNode: nil, enableAnimations: self.context?.sharedContext.energyUsageSettings.fullTranslucency ?? true)
dustNode.alpha = self.spoilersRevealed ? 0.0 : 1.0
dustNode.isUserInteractionEnabled = false
textInputNode.textView.addSubview(dustNode.view)

View File

@ -34,6 +34,7 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode {
private let actionArea: AccessibilityAreaNode
private let context: AccountContext
var theme: PresentationTheme
var strings: PresentationStrings
@ -42,6 +43,7 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode {
init(context: AccountContext, messageId: MessageId, theme: PresentationTheme, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, animationCache: AnimationCache?, animationRenderer: MultiAnimationRenderer?) {
self.messageId = messageId
self.context = context
self.theme = theme
self.strings = strings
@ -344,7 +346,7 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode {
if let textLayout = self.textNode.cachedLayout, !textLayout.spoilers.isEmpty {
if self.dustNode == nil {
let dustNode = InvisibleInkDustNode(textNode: nil)
let dustNode = InvisibleInkDustNode(textNode: nil, enableAnimations: self.context.sharedContext.energyUsageSettings.fullTranslucency)
self.dustNode = dustNode
self.textNode.supernode?.insertSubnode(dustNode, aboveSubnode: self.textNode)
}