diff --git a/submodules/InvisibleInkDustNode/Sources/InvisibleInkDustNode.swift b/submodules/InvisibleInkDustNode/Sources/InvisibleInkDustNode.swift index b8ba77c842..913ff045ad 100644 --- a/submodules/InvisibleInkDustNode/Sources/InvisibleInkDustNode.swift +++ b/submodules/InvisibleInkDustNode/Sources/InvisibleInkDustNode.swift @@ -6,25 +6,11 @@ import AsyncDisplayKit import Display import AppBundle import LegacyComponents -import GameplayKit -private struct ArbitraryRandomNumberGenerator : RandomNumberGenerator { +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: "") @@ -323,25 +309,28 @@ public class InvisibleInkDustNode: ASDisplayNode { } 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))) + Queue.concurrentDefaultQueue().async { + 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))) + } } } + }) + Queue.mainQueue().async { + self.staticNode?.image = image } - }) + } self.staticNode?.frame = CGRect(origin: CGPoint(), size: size) - self.staticNode?.image = image print("total draw \(CACurrentMediaTime() - start)") } diff --git a/submodules/InvisibleInkDustNode/Sources/MediaDustNode.swift b/submodules/InvisibleInkDustNode/Sources/MediaDustNode.swift index 3de61b6081..31ad26614b 100644 --- a/submodules/InvisibleInkDustNode/Sources/MediaDustNode.swift +++ b/submodules/InvisibleInkDustNode/Sources/MediaDustNode.swift @@ -92,6 +92,7 @@ public class MediaDustLayer: CALayer { public class MediaDustNode: ASDisplayNode { private var currentParams: (size: CGSize, color: UIColor)? private var animColor: CGColor? + private let enableAnimations: Bool private var emitterNode: ASDisplayNode private var emitter: CAEmitterCell? @@ -101,13 +102,18 @@ public class MediaDustNode: ASDisplayNode { private let emitterSpotNode: ASImageNode private let emitterMaskFillNode: ASDisplayNode + private var staticNode: ASImageNode? + private var staticParams: CGSize? + public var isRevealed = false private var isExploding = false public var revealed: () -> Void = {} public var tapped: () -> Void = {} - public override init() { + public init(enableAnimations: Bool) { + self.enableAnimations = enableAnimations + self.emitterNode = ASDisplayNode() self.emitterNode.isUserInteractionEnabled = false self.emitterNode.clipsToBounds = true @@ -132,65 +138,71 @@ public class MediaDustNode: ASDisplayNode { public override func didLoad() { super.didLoad() - let emitter = CAEmitterCell() - emitter.color = UIColor(rgb: 0xffffff, alpha: 0.0).cgColor - emitter.contents = UIImage(bundleImageName: "Components/TextSpeckle")?.cgImage - emitter.contentsScale = 1.8 - emitter.emissionRange = .pi * 2.0 - emitter.lifetime = 8.0 - emitter.scale = 0.5 - emitter.velocityRange = 0.0 - emitter.name = "dustCell" - emitter.alphaRange = 1.0 - emitter.setValue("point", forKey: "particleType") - emitter.setValue(1.0, forKey: "mass") - emitter.setValue(0.01, forKey: "massRange") - self.emitter = emitter - - let alphaBehavior = createEmitterBehavior(type: "valueOverLife") - alphaBehavior.setValue("color.alpha", forKey: "keyPath") - alphaBehavior.setValue([0, 0, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 1, 0, -1], forKey: "values") - alphaBehavior.setValue(true, forKey: "additive") - - let scaleBehavior = createEmitterBehavior(type: "valueOverLife") - scaleBehavior.setValue("scale", forKey: "keyPath") - scaleBehavior.setValue([0.0, 0.5], forKey: "values") - scaleBehavior.setValue([0.0, 0.05], forKey: "locations") - - let randomAttractor0 = createEmitterBehavior(type: "simpleAttractor") - randomAttractor0.setValue("randomAttractor0", forKey: "name") - randomAttractor0.setValue(20, forKey: "falloff") - randomAttractor0.setValue(35, forKey: "radius") - randomAttractor0.setValue(5, forKey: "stiffness") - randomAttractor0.setValue(NSValue(cgPoint: .zero), forKey: "position") - - let randomAttractor1 = createEmitterBehavior(type: "simpleAttractor") - randomAttractor1.setValue("randomAttractor1", forKey: "name") - randomAttractor1.setValue(20, forKey: "falloff") - randomAttractor1.setValue(35, forKey: "radius") - randomAttractor1.setValue(5, forKey: "stiffness") - randomAttractor1.setValue(NSValue(cgPoint: .zero), forKey: "position") - - let fingerAttractor = createEmitterBehavior(type: "simpleAttractor") - fingerAttractor.setValue("fingerAttractor", forKey: "name") - - let behaviors = [randomAttractor0, randomAttractor1, fingerAttractor, alphaBehavior, scaleBehavior] - - let emitterLayer = CAEmitterLayer() - emitterLayer.masksToBounds = true - emitterLayer.allowsGroupOpacity = true - emitterLayer.lifetime = 1 - emitterLayer.emitterCells = [emitter] - emitterLayer.seed = arc4random() - emitterLayer.emitterShape = .rectangle - emitterLayer.setValue(behaviors, forKey: "emitterBehaviors") - - emitterLayer.setValue(4.0, forKeyPath: "emitterBehaviors.fingerAttractor.stiffness") - emitterLayer.setValue(false, forKeyPath: "emitterBehaviors.fingerAttractor.enabled") - - self.emitterLayer = emitterLayer - - self.emitterNode.layer.addSublayer(emitterLayer) + if self.enableAnimations { + let emitter = CAEmitterCell() + emitter.color = UIColor(rgb: 0xffffff, alpha: 0.0).cgColor + emitter.contents = UIImage(bundleImageName: "Components/TextSpeckle")?.cgImage + emitter.contentsScale = 1.8 + emitter.emissionRange = .pi * 2.0 + emitter.lifetime = 8.0 + emitter.scale = 0.5 + emitter.velocityRange = 0.0 + emitter.name = "dustCell" + emitter.alphaRange = 1.0 + emitter.setValue("point", forKey: "particleType") + emitter.setValue(1.0, forKey: "mass") + emitter.setValue(0.01, forKey: "massRange") + self.emitter = emitter + + let alphaBehavior = createEmitterBehavior(type: "valueOverLife") + alphaBehavior.setValue("color.alpha", forKey: "keyPath") + alphaBehavior.setValue([0, 0, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 1, 0, -1], forKey: "values") + alphaBehavior.setValue(true, forKey: "additive") + + let scaleBehavior = createEmitterBehavior(type: "valueOverLife") + scaleBehavior.setValue("scale", forKey: "keyPath") + scaleBehavior.setValue([0.0, 0.5], forKey: "values") + scaleBehavior.setValue([0.0, 0.05], forKey: "locations") + + let randomAttractor0 = createEmitterBehavior(type: "simpleAttractor") + randomAttractor0.setValue("randomAttractor0", forKey: "name") + randomAttractor0.setValue(20, forKey: "falloff") + randomAttractor0.setValue(35, forKey: "radius") + randomAttractor0.setValue(5, forKey: "stiffness") + randomAttractor0.setValue(NSValue(cgPoint: .zero), forKey: "position") + + let randomAttractor1 = createEmitterBehavior(type: "simpleAttractor") + randomAttractor1.setValue("randomAttractor1", forKey: "name") + randomAttractor1.setValue(20, forKey: "falloff") + randomAttractor1.setValue(35, forKey: "radius") + randomAttractor1.setValue(5, forKey: "stiffness") + randomAttractor1.setValue(NSValue(cgPoint: .zero), forKey: "position") + + let fingerAttractor = createEmitterBehavior(type: "simpleAttractor") + fingerAttractor.setValue("fingerAttractor", forKey: "name") + + let behaviors = [randomAttractor0, randomAttractor1, fingerAttractor, alphaBehavior, scaleBehavior] + + let emitterLayer = CAEmitterLayer() + emitterLayer.masksToBounds = true + emitterLayer.allowsGroupOpacity = true + emitterLayer.lifetime = 1 + emitterLayer.emitterCells = [emitter] + emitterLayer.seed = arc4random() + emitterLayer.emitterShape = .rectangle + emitterLayer.setValue(behaviors, forKey: "emitterBehaviors") + + emitterLayer.setValue(4.0, forKeyPath: "emitterBehaviors.fingerAttractor.stiffness") + emitterLayer.setValue(false, forKeyPath: "emitterBehaviors.fingerAttractor.enabled") + + self.emitterLayer = emitterLayer + + self.emitterNode.layer.addSublayer(emitterLayer) + } else { + let staticNode = ASImageNode() + self.staticNode = staticNode + self.addSubnode(staticNode) + } self.updateEmitter() @@ -207,49 +219,57 @@ public class MediaDustNode: ASDisplayNode { self.tapped() self.isRevealed = true - self.isExploding = true - let position = gestureRecognizer.location(in: self.view) - self.emitterLayer?.setValue(true, forKeyPath: "emitterBehaviors.fingerAttractor.enabled") - self.emitterLayer?.setValue(position, forKeyPath: "emitterBehaviors.fingerAttractor.position") - - let maskSize = self.emitterNode.frame.size - Queue.concurrentDefaultQueue().async { - let emitterMaskImage = generateMaskImage(size: maskSize, position: position, inverse: true) + if self.enableAnimations { + self.isExploding = true - Queue.mainQueue().async { - self.emitterSpotNode.image = emitterMaskImage - } - } - - Queue.mainQueue().after(0.1 * UIView.animationDurationFactor()) { - let xFactor = (position.x / self.emitterNode.frame.width - 0.5) * 2.0 - let yFactor = (position.y / self.emitterNode.frame.height - 0.5) * 2.0 - let maxFactor = max(abs(xFactor), abs(yFactor)) - - let scaleAddition = maxFactor * 4.0 - let durationAddition = -maxFactor * 0.2 + let position = gestureRecognizer.location(in: self.view) + self.emitterLayer?.setValue(true, forKeyPath: "emitterBehaviors.fingerAttractor.enabled") + self.emitterLayer?.setValue(position, forKeyPath: "emitterBehaviors.fingerAttractor.position") - self.supernode?.view.mask = self.emitterMaskNode.view - self.emitterSpotNode.frame = CGRect(x: 0.0, y: 0.0, width: self.emitterMaskNode.frame.width * 3.0, height: self.emitterMaskNode.frame.height * 3.0) - - self.emitterSpotNode.layer.anchorPoint = CGPoint(x: position.x / self.emitterMaskNode.frame.width, y: position.y / self.emitterMaskNode.frame.height) - self.emitterSpotNode.position = position - self.emitterSpotNode.layer.animateScale(from: 0.3333, to: 10.5 + scaleAddition, duration: 0.45 + durationAddition, removeOnCompletion: false, completion: { [weak self] _ in - self?.revealed() - self?.alpha = 0.0 - self?.supernode?.view.mask = nil + let maskSize = self.emitterNode.frame.size + Queue.concurrentDefaultQueue().async { + let emitterMaskImage = generateMaskImage(size: maskSize, position: position, inverse: true) - }) - self.emitterMaskFillNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false) - } - - Queue.mainQueue().after(0.8 * UIView.animationDurationFactor()) { - self.isExploding = false - self.emitterLayer?.setValue(false, forKeyPath: "emitterBehaviors.fingerAttractor.enabled") + Queue.mainQueue().async { + self.emitterSpotNode.image = emitterMaskImage + } + } - self.emitterSpotNode.layer.removeAllAnimations() - self.emitterMaskFillNode.layer.removeAllAnimations() + Queue.mainQueue().after(0.1 * UIView.animationDurationFactor()) { + let xFactor = (position.x / self.emitterNode.frame.width - 0.5) * 2.0 + let yFactor = (position.y / self.emitterNode.frame.height - 0.5) * 2.0 + let maxFactor = max(abs(xFactor), abs(yFactor)) + + let scaleAddition = maxFactor * 4.0 + let durationAddition = -maxFactor * 0.2 + + self.supernode?.view.mask = self.emitterMaskNode.view + self.emitterSpotNode.frame = CGRect(x: 0.0, y: 0.0, width: self.emitterMaskNode.frame.width * 3.0, height: self.emitterMaskNode.frame.height * 3.0) + + self.emitterSpotNode.layer.anchorPoint = CGPoint(x: position.x / self.emitterMaskNode.frame.width, y: position.y / self.emitterMaskNode.frame.height) + self.emitterSpotNode.position = position + self.emitterSpotNode.layer.animateScale(from: 0.3333, to: 10.5 + scaleAddition, duration: 0.45 + durationAddition, removeOnCompletion: false, completion: { [weak self] _ in + self?.revealed() + self?.alpha = 0.0 + self?.supernode?.view.mask = nil + + }) + self.emitterMaskFillNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false) + } + + Queue.mainQueue().after(0.8 * UIView.animationDurationFactor()) { + self.isExploding = false + self.emitterLayer?.setValue(false, forKeyPath: "emitterBehaviors.fingerAttractor.enabled") + + self.emitterSpotNode.layer.removeAllAnimations() + self.emitterMaskFillNode.layer.removeAllAnimations() + } + } else { + self.supernode?.alpha = 0.0 + self.supernode?.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, completion: { [weak self] _ in + self?.revealed() + }) } } @@ -327,18 +347,49 @@ public class MediaDustNode: ASDisplayNode { guard let (size, _) = self.currentParams else { return } - - self.emitterLayer?.frame = CGRect(origin: CGPoint(), size: size) - self.emitterLayer?.emitterSize = size - self.emitterLayer?.emitterPosition = CGPoint(x: size.width / 2.0, y: size.height / 2.0) - - let radius = max(size.width, size.height) - self.emitterLayer?.setValue(max(size.width, size.height), forKeyPath: "emitterBehaviors.fingerAttractor.radius") - self.emitterLayer?.setValue(radius * -0.5, forKeyPath: "emitterBehaviors.fingerAttractor.falloff") - - let square = Float(size.width * size.height) - Queue.mainQueue().async { - self.emitter?.birthRate = min(100000.0, square * 0.02) + if self.enableAnimations { + self.emitterLayer?.frame = CGRect(origin: CGPoint(), size: size) + self.emitterLayer?.emitterSize = size + self.emitterLayer?.emitterPosition = CGPoint(x: size.width / 2.0, y: size.height / 2.0) + + let radius = max(size.width, size.height) + self.emitterLayer?.setValue(max(size.width, size.height), forKeyPath: "emitterBehaviors.fingerAttractor.radius") + self.emitterLayer?.setValue(radius * -0.5, forKeyPath: "emitterBehaviors.fingerAttractor.falloff") + + let square = Float(size.width * size.height) + Queue.mainQueue().async { + self.emitter?.birthRate = min(100000.0, square * 0.02) + } + } else { + if let staticParams = self.staticParams, staticParams == size && self.staticNode?.image != nil { + return + } + self.staticParams = size + + let start = CACurrentMediaTime() + + Queue.concurrentDefaultQueue().async { + 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(UIColor.white.cgColor) + let rect = CGRect(origin: .zero, size: size) + + let rate = Int(rect.width * rect.height * 0.04) + 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))) + } + }) + Queue.mainQueue().async { + self.staticNode?.image = image + } + } + self.staticNode?.frame = CGRect(origin: CGPoint(), size: size) + + print("total draw \(CACurrentMediaTime() - start)") } } @@ -351,6 +402,8 @@ public class MediaDustNode: ASDisplayNode { self.emitterMaskNode.frame = bounds self.emitterMaskFillNode.frame = bounds + self.staticNode?.frame = bounds + if self.isNodeLoaded { self.updateEmitter() self.setupRandomAnimations() diff --git a/submodules/MediaPickerUI/Sources/MediaPickerGridItem.swift b/submodules/MediaPickerUI/Sources/MediaPickerGridItem.swift index a1082e8001..a4c38edaf9 100644 --- a/submodules/MediaPickerUI/Sources/MediaPickerGridItem.swift +++ b/submodules/MediaPickerUI/Sources/MediaPickerGridItem.swift @@ -25,24 +25,26 @@ final class MediaPickerGridItem: GridItem { let content: MediaPickerGridItemContent let interaction: MediaPickerInteraction let theme: PresentationTheme + let enableAnimations: Bool let section: GridSection? = nil - init(content: MediaPickerGridItemContent, interaction: MediaPickerInteraction, theme: PresentationTheme) { + init(content: MediaPickerGridItemContent, interaction: MediaPickerInteraction, theme: PresentationTheme, enableAnimations: Bool) { self.content = content self.interaction = interaction self.theme = theme + self.enableAnimations = enableAnimations } func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode { switch self.content { case let .asset(fetchResult, index): let node = MediaPickerGridItemNode() - node.setup(interaction: self.interaction, fetchResult: fetchResult, index: index, theme: self.theme) + node.setup(interaction: self.interaction, fetchResult: fetchResult, index: index, theme: self.theme, enableAnimations: self.enableAnimations) return node case let .media(media, index): let node = MediaPickerGridItemNode() - node.setup(interaction: self.interaction, media: media, index: index, theme: self.theme) + node.setup(interaction: self.interaction, media: media, index: index, theme: self.theme, enableAnimations: self.enableAnimations) return node } } @@ -54,13 +56,13 @@ final class MediaPickerGridItem: GridItem { assertionFailure() return } - node.setup(interaction: self.interaction, fetchResult: fetchResult, index: index, theme: self.theme) + node.setup(interaction: self.interaction, fetchResult: fetchResult, index: index, theme: self.theme, enableAnimations: self.enableAnimations) case let .media(media, index): guard let node = node as? MediaPickerGridItemNode else { assertionFailure() return } - node.setup(interaction: self.interaction, media: media, index: index, theme: self.theme) + node.setup(interaction: self.interaction, media: media, index: index, theme: self.theme, enableAnimations: self.enableAnimations) } } } @@ -81,6 +83,8 @@ private let maskImage = generateImage(CGSize(width: 1.0, height: 24.0), opaque: final class MediaPickerGridItemNode: GridItemNode { var currentMediaState: (TGMediaSelectableItem, Int)? var currentState: (PHFetchResult, Int)? + var enableAnimations: Bool = true + private let imageNode: ImageNode private var checkNode: InteractiveCheckNode? private let gradientNode: ASImageNode @@ -214,9 +218,10 @@ final class MediaPickerGridItemNode: GridItemNode { self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.imageNodeTap(_:)))) } - func setup(interaction: MediaPickerInteraction, media: MediaPickerScreen.Subject.Media, index: Int, theme: PresentationTheme) { + func setup(interaction: MediaPickerInteraction, media: MediaPickerScreen.Subject.Media, index: Int, theme: PresentationTheme, enableAnimations: Bool) { self.interaction = interaction self.theme = theme + self.enableAnimations = enableAnimations self.backgroundColor = theme.list.mediaPlaceholderColor @@ -281,9 +286,10 @@ final class MediaPickerGridItemNode: GridItemNode { self.updateHiddenMedia() } - func setup(interaction: MediaPickerInteraction, fetchResult: PHFetchResult, index: Int, theme: PresentationTheme) { + func setup(interaction: MediaPickerInteraction, fetchResult: PHFetchResult, index: Int, theme: PresentationTheme, enableAnimations: Bool) { self.interaction = interaction self.theme = theme + self.enableAnimations = enableAnimations self.backgroundColor = theme.list.mediaPlaceholderColor @@ -395,7 +401,7 @@ final class MediaPickerGridItemNode: GridItemNode { if hasSpoiler { if self.spoilerNode == nil { - let spoilerNode = SpoilerOverlayNode() + let spoilerNode = SpoilerOverlayNode(enableAnimations: self.enableAnimations) self.insertSubnode(spoilerNode, aboveSubnode: self.imageNode) self.spoilerNode = spoilerNode @@ -458,12 +464,12 @@ class SpoilerOverlayNode: ASDisplayNode { private var maskView: UIView? private var maskLayer: CAShapeLayer? - override init() { + init(enableAnimations: Bool) { self.blurNode = ASImageNode() self.blurNode.displaysAsynchronously = false self.blurNode.contentMode = .scaleAspectFill - self.dustNode = MediaDustNode() + self.dustNode = MediaDustNode(enableAnimations: enableAnimations) super.init() diff --git a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift index 3c8960f0c3..57b6f59862 100644 --- a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift +++ b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift @@ -53,8 +53,8 @@ private struct MediaPickerGridEntry: Comparable, Identifiable { return lhs.stableId < rhs.stableId } - func item(account: Account, interaction: MediaPickerInteraction, theme: PresentationTheme) -> MediaPickerGridItem { - return MediaPickerGridItem(content: self.content, interaction: interaction, theme: theme) + func item(context: AccountContext, interaction: MediaPickerInteraction, theme: PresentationTheme) -> MediaPickerGridItem { + return MediaPickerGridItem(content: self.content, interaction: interaction, theme: theme, enableAnimations: context.sharedContext.energyUsageSettings.fullTranslucency) } } @@ -64,12 +64,12 @@ private struct MediaPickerGridTransaction { let updates: [GridNodeUpdateItem] let scrollToItem: GridNodeScrollToItem? - init(previousList: [MediaPickerGridEntry], list: [MediaPickerGridEntry], account: Account, interaction: MediaPickerInteraction, theme: PresentationTheme, scrollToItem: GridNodeScrollToItem?) { + init(previousList: [MediaPickerGridEntry], list: [MediaPickerGridEntry], context: AccountContext, interaction: MediaPickerInteraction, theme: PresentationTheme, scrollToItem: GridNodeScrollToItem?) { let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: previousList, rightList: list) self.deletions = deleteIndices - self.insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(account: account, interaction: interaction, theme: theme), previousIndex: $0.2) } - self.updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, interaction: interaction, theme: theme)) } + self.insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(context: context, interaction: interaction, theme: theme), previousIndex: $0.2) } + self.updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, interaction: interaction, theme: theme)) } self.scrollToItem = scrollToItem } @@ -545,7 +545,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable { scrollToItem = GridNodeScrollToItem(index: entries.count - 1, position: .bottom(0.0), transition: .immediate, directionHint: .down, adjustForSection: false) } - let transaction = MediaPickerGridTransaction(previousList: previousEntries, list: entries, account: controller.context.account, interaction: interaction, theme: self.presentationData.theme, scrollToItem: scrollToItem) + let transaction = MediaPickerGridTransaction(previousList: previousEntries, list: entries, context: controller.context, interaction: interaction, theme: self.presentationData.theme, scrollToItem: scrollToItem) self.enqueueTransaction(transaction) if updateLayout, let (layout, navigationBarHeight) = self.validLayout { diff --git a/submodules/MediaPickerUI/Sources/MediaPickerSelectedListNode.swift b/submodules/MediaPickerUI/Sources/MediaPickerSelectedListNode.swift index ff17f148e5..770d27ca53 100644 --- a/submodules/MediaPickerUI/Sources/MediaPickerSelectedListNode.swift +++ b/submodules/MediaPickerUI/Sources/MediaPickerSelectedListNode.swift @@ -17,6 +17,7 @@ import ChatMessageBackground private class MediaPickerSelectedItemNode: ASDisplayNode { let asset: TGMediaEditableItem private let interaction: MediaPickerInteraction? + private let enableAnimations: Bool private let imageNode: ImageNode private var checkNode: InteractiveCheckNode? @@ -56,15 +57,16 @@ private class MediaPickerSelectedItemNode: ASDisplayNode { private var videoDuration: Double? - init(asset: TGMediaEditableItem, interaction: MediaPickerInteraction?) { + init(asset: TGMediaEditableItem, interaction: MediaPickerInteraction?, enableAnimations: Bool) { + self.asset = asset + self.interaction = interaction + self.enableAnimations = enableAnimations + self.imageNode = ImageNode() self.imageNode.contentMode = .scaleAspectFill self.imageNode.clipsToBounds = true self.imageNode.animateFirstTransition = false - self.asset = asset - self.interaction = interaction - super.init() self.clipsToBounds = true @@ -165,7 +167,7 @@ private class MediaPickerSelectedItemNode: ASDisplayNode { if hasSpoiler { if self.spoilerNode == nil { - let spoilerNode = SpoilerOverlayNode() + let spoilerNode = SpoilerOverlayNode(enableAnimations: self.enableAnimations) self.insertSubnode(spoilerNode, aboveSubnode: self.imageNode) self.spoilerNode = spoilerNode @@ -781,7 +783,7 @@ final class MediaPickerSelectedListNode: ASDisplayNode, UIScrollViewDelegate, UI if let current = self.itemNodes[identifier] { itemNode = current } else { - itemNode = MediaPickerSelectedItemNode(asset: asset, interaction: self.interaction) + itemNode = MediaPickerSelectedItemNode(asset: asset, interaction: self.interaction, enableAnimations: self.context.sharedContext.energyUsageSettings.fullTranslucency) self.itemNodes[identifier] = itemNode self.scrollNode.addSubnode(itemNode) diff --git a/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift b/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift index db35c913ac..c241ca3da9 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift @@ -189,11 +189,11 @@ private class ExtendedMediaOverlayNode: ASDisplayNode { var isRevealed = false var tapped: () -> Void = {} - override init() { + init(enableAnimations: Bool) { self.blurredImageNode = TransformImageNode() self.blurredImageNode.contentAnimations = [] - self.dustNode = MediaDustNode() + self.dustNode = MediaDustNode(enableAnimations: enableAnimations) self.buttonNode = HighlightTrackingButtonNode() self.buttonNode.backgroundColor = UIColor(rgb: 0x000000, alpha: 0.3) @@ -1898,7 +1898,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio if displaySpoiler { if self.extendedMediaOverlayNode == nil { - let extendedMediaOverlayNode = ExtendedMediaOverlayNode() + let extendedMediaOverlayNode = ExtendedMediaOverlayNode(enableAnimations: self.context?.sharedContext.energyUsageSettings.fullTranslucency ?? true) extendedMediaOverlayNode.tapped = { [weak self] in self?.internallyVisible = true self?.updateVisibility()