mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-24 07:05:35 +00:00
Various improvements
This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user