175 lines
5.2 KiB
Swift

import Foundation
import UIKit
import AsyncDisplayKit
import Display
import CallScreen
import MetalEngine
final class VoiceBlobView: UIView {
//private let mediumBlob: BlobView
//private let bigBlob: BlobView
private let blobsLayer: CallBlobsLayer
private let maxLevel: CGFloat
private var displayLinkAnimator: ConstantDisplayLinkAnimator?
private var audioLevel: CGFloat = 0.0
var presentationAudioLevel: CGFloat = 0.0
var scaleUpdated: ((CGFloat) -> Void)? {
didSet {
//self.bigBlob.scaleUpdated = self.scaleUpdated
}
}
private(set) var isAnimating = false
public typealias BlobRange = (min: CGFloat, max: CGFloat)
private let hierarchyTrackingNode: HierarchyTrackingNode
private var isCurrentlyInHierarchy = true
init(
frame: CGRect,
maxLevel: CGFloat,
mediumBlobRange: BlobRange,
bigBlobRange: BlobRange
) {
var updateInHierarchy: ((Bool) -> Void)?
self.hierarchyTrackingNode = HierarchyTrackingNode({ value in
updateInHierarchy?(value)
})
self.maxLevel = maxLevel
/*self.mediumBlob = BlobView(
pointsCount: 8,
minRandomness: 1,
maxRandomness: 1,
minSpeed: 0.9,
maxSpeed: 4.0,
minScale: mediumBlobRange.min,
maxScale: mediumBlobRange.max
)
self.bigBlob = BlobView(
pointsCount: 8,
minRandomness: 1,
maxRandomness: 1,
minSpeed: 1.0,
maxSpeed: 4.4,
minScale: bigBlobRange.min,
maxScale: bigBlobRange.max
)*/
self.blobsLayer = CallBlobsLayer()
super.init(frame: frame)
self.addSubnode(self.hierarchyTrackingNode)
//self.addSubview(self.bigBlob)
//self.addSubview(self.mediumBlob)
self.layer.addSublayer(self.blobsLayer)
self.displayLinkAnimator = ConstantDisplayLinkAnimator() { [weak self] in
guard let strongSelf = self else { return }
if !strongSelf.isCurrentlyInHierarchy {
return
}
strongSelf.presentationAudioLevel = strongSelf.presentationAudioLevel * 0.9 + strongSelf.audioLevel * 0.1
strongSelf.updateAudioLevel()
//strongSelf.mediumBlob.level = strongSelf.presentationAudioLevel
//strongSelf.bigBlob.level = strongSelf.presentationAudioLevel
}
updateInHierarchy = { [weak self] value in
if let strongSelf = self {
strongSelf.isCurrentlyInHierarchy = value
}
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public func setColor(_ color: UIColor) {
//self.mediumBlob.setColor(color.withAlphaComponent(0.5))
//self.bigBlob.setColor(color.withAlphaComponent(0.21))
}
public func updateLevel(_ level: CGFloat, immediately: Bool) {
let normalizedLevel = min(1, max(level / maxLevel, 0))
//self.mediumBlob.updateSpeedLevel(to: normalizedLevel)
//self.bigBlob.updateSpeedLevel(to: normalizedLevel)
self.audioLevel = normalizedLevel
if immediately {
self.presentationAudioLevel = normalizedLevel
}
}
private func updateAudioLevel() {
let additionalAvatarScale = CGFloat(max(0.0, min(self.presentationAudioLevel * 18.0, 5.0)) * 0.05)
let blobAmplificationFactor: CGFloat = 2.0
let blobScale = 1.0 + additionalAvatarScale * blobAmplificationFactor
self.blobsLayer.transform = CATransform3DMakeScale(blobScale, blobScale, 1.0)
self.scaleUpdated?(blobScale)
}
public func startAnimating() {
guard !self.isAnimating else { return }
self.isAnimating = true
self.updateBlobsState()
self.displayLinkAnimator?.isPaused = false
}
public func stopAnimating() {
self.stopAnimating(duration: 0.15)
}
public func stopAnimating(duration: Double) {
guard isAnimating else { return }
self.isAnimating = false
self.updateBlobsState()
self.displayLinkAnimator?.isPaused = true
}
private func updateBlobsState() {
/*if self.isAnimating {
if self.mediumBlob.frame.size != .zero {
self.mediumBlob.startAnimating()
self.bigBlob.startAnimating()
}
} else {
self.mediumBlob.stopAnimating()
self.bigBlob.stopAnimating()
}*/
}
override public func layoutSubviews() {
super.layoutSubviews()
//self.mediumBlob.frame = bounds
//self.bigBlob.frame = bounds
let blobsFrame = bounds.insetBy(dx: floor(bounds.width * 0.12), dy: floor(bounds.height * 0.12))
self.blobsLayer.position = blobsFrame.center
self.blobsLayer.bounds = CGRect(origin: CGPoint(), size: blobsFrame.size)
self.updateBlobsState()
}
}