mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-08 08:31:13 +00:00
Mege patch
This commit is contained in:
parent
184570c8a6
commit
e8f6fb6c05
@ -14,25 +14,31 @@ final class VoiceBlobView: UIView, TGModernConversationInputMicButtonDecoration
|
|||||||
pointsCount: 8,
|
pointsCount: 8,
|
||||||
minRandomness: 0.1,
|
minRandomness: 0.1,
|
||||||
maxRandomness: 1,
|
maxRandomness: 1,
|
||||||
idleSize: 1,
|
|
||||||
minSpeed: 0.2,
|
minSpeed: 0.2,
|
||||||
maxSpeed: 1
|
maxSpeed: 1,
|
||||||
|
minScale: 0.56,
|
||||||
|
maxScale: 0.56,
|
||||||
|
scaleSpeed: 0
|
||||||
)
|
)
|
||||||
private let mediumBlob = BlobView(
|
private let mediumBlob = BlobView(
|
||||||
pointsCount: 8,
|
pointsCount: 8,
|
||||||
minRandomness: 1,
|
minRandomness: 1,
|
||||||
maxRandomness: 2,
|
maxRandomness: 2,
|
||||||
idleSize: 0.667,
|
minSpeed: 3,
|
||||||
minSpeed: 1,
|
maxSpeed: 8,
|
||||||
maxSpeed: 8
|
minScale: 0.67,
|
||||||
|
maxScale: 0.9,
|
||||||
|
scaleSpeed: 0.1
|
||||||
)
|
)
|
||||||
private let bigBlob = BlobView(
|
private let bigBlob = BlobView(
|
||||||
pointsCount: 8,
|
pointsCount: 8,
|
||||||
minRandomness: 1,
|
minRandomness: 1,
|
||||||
maxRandomness: 2,
|
maxRandomness: 2,
|
||||||
idleSize: 0.667,
|
minSpeed: 3,
|
||||||
minSpeed: 1,
|
maxSpeed: 8,
|
||||||
maxSpeed: 8
|
minScale: 0.67,
|
||||||
|
maxScale: 1,
|
||||||
|
scaleSpeed: 0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
@ -66,27 +72,16 @@ final class VoiceBlobView: UIView, TGModernConversationInputMicButtonDecoration
|
|||||||
override func layoutSubviews() {
|
override func layoutSubviews() {
|
||||||
super.layoutSubviews()
|
super.layoutSubviews()
|
||||||
|
|
||||||
func frameForBlobSize(_ blobSize: CGFloat) -> CGRect {
|
|
||||||
let blobWidth = bounds.width * blobSize
|
|
||||||
let blobHeight = bounds.height * blobSize
|
|
||||||
return CGRect(
|
|
||||||
x: (bounds.width - blobWidth) / 2,
|
|
||||||
y: (bounds.height - blobHeight) / 2,
|
|
||||||
width: blobWidth,
|
|
||||||
height: blobHeight
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
let isInitial = smallBlob.frame == .zero
|
let isInitial = smallBlob.frame == .zero
|
||||||
|
|
||||||
smallBlob.frame = frameForBlobSize(0.56)
|
smallBlob.frame = bounds
|
||||||
mediumBlob.frame = frameForBlobSize(0.9)
|
mediumBlob.frame = bounds
|
||||||
bigBlob.frame = frameForBlobSize(1)
|
bigBlob.frame = bounds
|
||||||
|
|
||||||
if isInitial {
|
if isInitial {
|
||||||
smallBlob.animateToNewShape()
|
smallBlob.startAnimating()
|
||||||
mediumBlob.animateToNewShape()
|
mediumBlob.startAnimating()
|
||||||
bigBlob.animateToNewShape()
|
bigBlob.startAnimating()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,7 +89,6 @@ final class VoiceBlobView: UIView, TGModernConversationInputMicButtonDecoration
|
|||||||
final class BlobView: UIView {
|
final class BlobView: UIView {
|
||||||
|
|
||||||
let pointsCount: Int
|
let pointsCount: Int
|
||||||
let idleSize: CGFloat
|
|
||||||
let smoothness: CGFloat
|
let smoothness: CGFloat
|
||||||
|
|
||||||
let minRandomness: CGFloat
|
let minRandomness: CGFloat
|
||||||
@ -103,19 +97,19 @@ final class BlobView: UIView {
|
|||||||
let minSpeed: CGFloat
|
let minSpeed: CGFloat
|
||||||
let maxSpeed: CGFloat
|
let maxSpeed: CGFloat
|
||||||
|
|
||||||
|
let minScale: CGFloat
|
||||||
|
let maxScale: CGFloat
|
||||||
|
let scaleSpeed: CGFloat
|
||||||
|
|
||||||
var level: CGFloat = 0 {
|
var level: CGFloat = 0 {
|
||||||
didSet {
|
didSet {
|
||||||
let shouldInterruptAnimation = abs(level - oldValue) > 0.3
|
speedLevel = max(level, speedLevel)
|
||||||
|
scaleLevel = max(level, scaleLevel)
|
||||||
debouncedLevel = max(level, debouncedLevel)
|
|
||||||
|
|
||||||
if shouldInterruptAnimation {
|
|
||||||
animateToNewShape()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var debouncedLevel: CGFloat = 0
|
private var speedLevel: CGFloat = 0
|
||||||
|
private var scaleLevel: CGFloat = 0
|
||||||
|
|
||||||
private let shapeLayer: CAShapeLayer = {
|
private let shapeLayer: CAShapeLayer = {
|
||||||
let layer = CAShapeLayer()
|
let layer = CAShapeLayer()
|
||||||
@ -150,16 +144,20 @@ final class BlobView: UIView {
|
|||||||
pointsCount: Int,
|
pointsCount: Int,
|
||||||
minRandomness: CGFloat,
|
minRandomness: CGFloat,
|
||||||
maxRandomness: CGFloat,
|
maxRandomness: CGFloat,
|
||||||
idleSize: CGFloat,
|
|
||||||
minSpeed: CGFloat,
|
minSpeed: CGFloat,
|
||||||
maxSpeed: CGFloat
|
maxSpeed: CGFloat,
|
||||||
|
minScale: CGFloat,
|
||||||
|
maxScale: CGFloat,
|
||||||
|
scaleSpeed: CGFloat
|
||||||
) {
|
) {
|
||||||
self.pointsCount = pointsCount
|
self.pointsCount = pointsCount
|
||||||
self.minRandomness = minRandomness
|
self.minRandomness = minRandomness
|
||||||
self.maxRandomness = maxRandomness
|
self.maxRandomness = maxRandomness
|
||||||
self.idleSize = idleSize
|
|
||||||
self.minSpeed = minSpeed
|
self.minSpeed = minSpeed
|
||||||
self.maxSpeed = maxSpeed
|
self.maxSpeed = maxSpeed
|
||||||
|
self.minScale = minScale
|
||||||
|
self.maxScale = maxScale
|
||||||
|
self.scaleSpeed = scaleSpeed
|
||||||
|
|
||||||
let angle = (CGFloat.pi * 2) / CGFloat(pointsCount)
|
let angle = (CGFloat.pi * 2) / CGFloat(pointsCount)
|
||||||
self.smoothness = ((4 / 3) * tan(angle / 4)) / sin(angle / 2) / 2
|
self.smoothness = ((4 / 3) * tan(angle / 4)) / sin(angle / 2) / 2
|
||||||
@ -167,6 +165,8 @@ final class BlobView: UIView {
|
|||||||
super.init(frame: .zero)
|
super.init(frame: .zero)
|
||||||
|
|
||||||
layer.addSublayer(shapeLayer)
|
layer.addSublayer(shapeLayer)
|
||||||
|
|
||||||
|
shapeLayer.transform = CATransform3DMakeScale(minScale, minScale, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
@ -177,16 +177,29 @@ final class BlobView: UIView {
|
|||||||
shapeLayer.fillColor = color.cgColor
|
shapeLayer.fillColor = color.cgColor
|
||||||
}
|
}
|
||||||
|
|
||||||
func animateToNewShape() {
|
func startAnimating() {
|
||||||
let minSize = CGSize(
|
animateToNewShape()
|
||||||
width: bounds.size.width * idleSize,
|
animateToNewScale()
|
||||||
height: bounds.size.height * idleSize
|
}
|
||||||
)
|
|
||||||
let currentSize = CGSize(
|
func animateToNewScale() {
|
||||||
width: minSize.width + (bounds.size.width - minSize.width) * debouncedLevel,
|
shapeLayer.pop_removeAnimation(forKey: "scale")
|
||||||
height: minSize.height + (bounds.size.height - minSize.height) * debouncedLevel
|
|
||||||
)
|
|
||||||
|
|
||||||
|
let currentScale = minScale + (maxScale - minScale) * scaleLevel
|
||||||
|
let scaleAnimation = POPBasicAnimation(propertyNamed: kPOPLayerScaleXY)!
|
||||||
|
scaleAnimation.toValue = CGPoint(x: currentScale, y: currentScale)
|
||||||
|
scaleAnimation.duration = CFTimeInterval(scaleSpeed)
|
||||||
|
scaleAnimation.completionBlock = { [weak self] animation, finished in
|
||||||
|
if finished {
|
||||||
|
self?.animateToNewScale()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shapeLayer.pop_add(scaleAnimation, forKey: "scale")
|
||||||
|
|
||||||
|
scaleLevel = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func animateToNewShape() {
|
||||||
if pop_animation(forKey: "blob") != nil {
|
if pop_animation(forKey: "blob") != nil {
|
||||||
fromPoints = currentPoints
|
fromPoints = currentPoints
|
||||||
toPoints = nil
|
toPoints = nil
|
||||||
@ -194,10 +207,10 @@ final class BlobView: UIView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if fromPoints == nil {
|
if fromPoints == nil {
|
||||||
fromPoints = generateNextBlob(for: currentSize)
|
fromPoints = generateNextBlob(for: bounds.size)
|
||||||
}
|
}
|
||||||
if toPoints == nil {
|
if toPoints == nil {
|
||||||
toPoints = generateNextBlob(for: currentSize)
|
toPoints = generateNextBlob(for: bounds.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
let animation = POPBasicAnimation()
|
let animation = POPBasicAnimation()
|
||||||
@ -220,19 +233,19 @@ final class BlobView: UIView {
|
|||||||
self?.animateToNewShape()
|
self?.animateToNewShape()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
animation.duration = CFTimeInterval(1 / (minSpeed + (maxSpeed - minSpeed) * debouncedLevel))
|
animation.duration = CFTimeInterval(1 / (minSpeed + (maxSpeed - minSpeed) * speedLevel))
|
||||||
animation.timingFunction = CAMediaTimingFunction(name: .linear)
|
animation.timingFunction = CAMediaTimingFunction(name: .linear)
|
||||||
animation.fromValue = 0
|
animation.fromValue = 0
|
||||||
animation.toValue = 1
|
animation.toValue = 1
|
||||||
pop_add(animation, forKey: "blob")
|
pop_add(animation, forKey: "blob")
|
||||||
|
|
||||||
debouncedLevel = 0
|
speedLevel = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Helpers
|
// MARK: Helpers
|
||||||
|
|
||||||
private func generateNextBlob(for size: CGSize) -> [CGPoint] {
|
private func generateNextBlob(for size: CGSize) -> [CGPoint] {
|
||||||
let randomness = minRandomness + (maxRandomness - minRandomness) * debouncedLevel
|
let randomness = minRandomness + (maxRandomness - minRandomness) * speedLevel
|
||||||
return blob(pointsCount: pointsCount, randomness: randomness)
|
return blob(pointsCount: pointsCount, randomness: randomness)
|
||||||
.map {
|
.map {
|
||||||
return CGPoint(
|
return CGPoint(
|
||||||
|
@ -1021,12 +1021,16 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
|||||||
audioRecordingTimeNode.audioRecorder = recorder
|
audioRecordingTimeNode.audioRecorder = recorder
|
||||||
|
|
||||||
var animateDotAppearing = false
|
var animateDotAppearing = false
|
||||||
|
let audioRecordingDotNode: AnimationNode
|
||||||
|
if let currentAudioRecordingDotNode = self.audioRecordingDotNode, !currentAudioRecordingDotNode.played {
|
||||||
|
audioRecordingDotNode = currentAudioRecordingDotNode
|
||||||
|
} else {
|
||||||
|
self.audioRecordingDotNode?.removeFromSupernode()
|
||||||
|
audioRecordingDotNode = AnimationNode(animation: "voicebin")
|
||||||
|
self.audioRecordingDotNode = audioRecordingDotNode
|
||||||
|
self.addSubnode(audioRecordingDotNode)
|
||||||
|
}
|
||||||
|
|
||||||
self.audioRecordingDotNode?.removeFromSupernode()
|
|
||||||
let audioRecordingDotNode = AnimationNode(animation: "voicebin")
|
|
||||||
self.audioRecordingDotNode = audioRecordingDotNode
|
|
||||||
self.addSubnode(audioRecordingDotNode)
|
|
||||||
|
|
||||||
animateDotAppearing = transition.isAnimated
|
animateDotAppearing = transition.isAnimated
|
||||||
|
|
||||||
audioRecordingDotNode.frame = CGRect(origin: CGPoint(x: leftInset + 2.0 - UIScreenPixel, y: panelHeight - 44 + 1), size: CGSize(width: 40.0, height: 40))
|
audioRecordingDotNode.frame = CGRect(origin: CGPoint(x: leftInset + 2.0 - UIScreenPixel, y: panelHeight - 44 + 1), size: CGSize(width: 40.0, height: 40))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user