Various improvements

This commit is contained in:
Ilya Laktyushin
2022-10-13 19:49:15 +03:00
parent 35e9b2caab
commit fe7dcc6866
14 changed files with 594 additions and 43 deletions

View File

@@ -5,6 +5,8 @@ import AsyncDisplayKit
import AppBundle
import WallpaperBackgroundNode
private let size = CGSize(width: 33.0, height: 33.0)
final class ChatMessageSwipeToReplyNode: ASDisplayNode {
enum Action {
case reply
@@ -17,6 +19,10 @@ final class ChatMessageSwipeToReplyNode: ASDisplayNode {
private let backgroundNode: NavigationBackgroundNode
private let foregroundNode: ASImageNode
private let maskNode: ASDisplayNode
private let progressLayer: CAShapeLayer
private let fillLayer: CAShapeLayer
private var absolutePosition: (CGRect, CGSize)?
init(fillColor: UIColor, enableBlur: Bool, foregroundColor: UIColor, backgroundNode: WallpaperBackgroundNode?, action: ChatMessageSwipeToReplyNode.Action) {
@@ -60,16 +66,43 @@ final class ChatMessageSwipeToReplyNode: ASDisplayNode {
}
})
self.maskNode = ASDisplayNode()
self.progressLayer = CAShapeLayer()
self.fillLayer = CAShapeLayer()
super.init()
self.allowsGroupOpacity = true
self.addSubnode(self.backgroundNode)
self.addSubnode(self.foregroundNode)
self.backgroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 33.0, height: 33.0))
self.backgroundNode.update(size: self.backgroundNode.bounds.size, cornerRadius: self.backgroundNode.bounds.height / 2.0, transition: .immediate)
self.foregroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 33.0, height: 33.0))
self.maskNode.layer.addSublayer(self.progressLayer)
self.maskNode.layer.addSublayer(self.fillLayer)
self.addSubnode(self.foregroundNode)
let backgroundFrame = CGRect(origin: CGPoint(), size: size).insetBy(dx: -22.0, dy: -22.0)
self.backgroundNode.frame = backgroundFrame
self.backgroundNode.update(size: self.backgroundNode.bounds.size, cornerRadius: self.backgroundNode.bounds.height / 2.0, transition: .immediate)
self.foregroundNode.frame = CGRect(origin: CGPoint(), size: size)
self.progressLayer.strokeColor = UIColor.white.cgColor
self.progressLayer.fillColor = UIColor.clear.cgColor
self.progressLayer.lineCap = .round
self.progressLayer.lineWidth = 2.0 - UIScreenPixel
self.fillLayer.strokeColor = UIColor.white.cgColor
self.fillLayer.fillColor = UIColor.clear.cgColor
self.fillLayer.isHidden = true
self.maskNode.frame = CGRect(origin: CGPoint(x: 22.0, y: 22.0), size: backgroundFrame.size)
self.progressLayer.frame = CGRect(origin: .zero, size: size).insetBy(dx: -20.0, dy: -20.0)
self.fillLayer.frame = CGRect(origin: .zero, size: size)
let path = UIBezierPath(arcCenter: CGPoint(x: self.progressLayer.frame.width / 2.0, y: self.progressLayer.frame.height / 2.0), radius: size.width / 2.0, startAngle: CGFloat(-0.5 * .pi), endAngle: CGFloat(1.5 * .pi), clockwise: true)
self.progressLayer.path = path.cgPath
if backgroundNode?.hasExtraBubbleBackground() == true {
if let backgroundContent = backgroundNode?.makeBubbleBackground(for: .free) {
backgroundContent.clipsToBounds = true
@@ -84,8 +117,7 @@ final class ChatMessageSwipeToReplyNode: ASDisplayNode {
if let backgroundContent = self.backgroundContent {
self.backgroundNode.isHidden = true
backgroundContent.cornerRadius = min(self.backgroundNode.bounds.width, self.backgroundNode.bounds.height) / 2.0
backgroundContent.frame = self.backgroundNode.frame
backgroundContent.frame = backgroundFrame
if let (rect, containerSize) = self.absolutePosition {
var backgroundFrame = backgroundContent.frame
backgroundFrame.origin.x += rect.minX
@@ -97,6 +129,73 @@ final class ChatMessageSwipeToReplyNode: ASDisplayNode {
}
}
override func didLoad() {
super.didLoad()
if let backgroundContent = self.backgroundContent {
backgroundContent.view.mask = self.maskNode.view
} else {
self.backgroundNode.view.mask = self.maskNode.view
}
}
private var animatedWave = false
func updateProgress(_ progress: CGFloat) {
let progress = max(0.0, min(1.0, progress))
var foregroundProgress = min(1.0, progress * 1.2)
var scaleProgress = 0.65 + foregroundProgress * 0.35
if !self.animatedWave {
let path = UIBezierPath(arcCenter: CGPoint(x: self.progressLayer.frame.width / 2.0, y: self.progressLayer.frame.height / 2.0), radius: size.width / 2.0, startAngle: CGFloat(-0.5 * .pi), endAngle: CGFloat(-0.5 * .pi + progress * 2.0 * .pi), clockwise: true)
self.progressLayer.path = path.cgPath
} else {
foregroundProgress = progress
scaleProgress = progress
self.maskNode.alpha = progress
}
self.layer.sublayerTransform = CATransform3DMakeScale(scaleProgress, scaleProgress, 1.0)
self.foregroundNode.alpha = foregroundProgress
self.foregroundNode.transform = CATransform3DMakeScale(foregroundProgress, foregroundProgress, 1.0)
if progress == 1.0 {
self.playSuccessAnimation()
}
}
func playSuccessAnimation() {
guard !self.animatedWave else {
return
}
self.animatedWave = true
var lineWidth = self.progressLayer.lineWidth
self.progressLayer.lineWidth = 1.0
self.progressLayer.animate(from: lineWidth as NSNumber, to: 1.0 as NSNumber, keyPath: "lineWidth", timingFunction: CAMediaTimingFunctionName.linear.rawValue, duration: 0.25, completion: { [weak self] _ in
self?.progressLayer.animate(from: 1.0 as NSNumber, to: 0.0 as NSNumber, keyPath: "lineWidth", timingFunction: CAMediaTimingFunctionName.linear.rawValue, duration: 0.15, removeOnCompletion: false)
})
var path = self.progressLayer.path
var targetPath = UIBezierPath(arcCenter: CGPoint(x: self.progressLayer.frame.width / 2.0, y: self.progressLayer.frame.height / 2.0), radius: 35.0, startAngle: CGFloat(-0.5 * .pi), endAngle: CGFloat(-0.5 * .pi + 2.0 * .pi), clockwise: true).cgPath
self.progressLayer.path = targetPath
self.progressLayer.animate(from: path, to: targetPath, keyPath: "path", timingFunction: kCAMediaTimingFunctionSpring, duration: 0.25)
self.fillLayer.isHidden = false
self.fillLayer.path = UIBezierPath(ovalIn: CGRect(origin: .zero, size: size)).cgPath
self.fillLayer.lineWidth = 2.0 - UIScreenPixel
lineWidth = self.fillLayer.lineWidth
self.fillLayer.lineWidth = 18.0
self.fillLayer.animate(from: lineWidth as NSNumber, to: 18.0 as NSNumber, keyPath: "lineWidth", timingFunction: CAMediaTimingFunctionName.linear.rawValue, duration: 0.25)
path = self.fillLayer.path
targetPath = UIBezierPath(ovalIn: CGRect(origin: .zero, size: size).insetBy(dx: 9.0, dy: 9.0)).cgPath
self.fillLayer.path = targetPath
self.fillLayer.animate(from: path, to: targetPath, keyPath: "path", timingFunction: CAMediaTimingFunctionName.linear.rawValue, duration: 0.25)
}
func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
self.absolutePosition = (rect, containerSize)
if let backgroundContent = self.backgroundContent {