mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-24 07:05:35 +00:00
Story mute button animation
This commit is contained in:
@@ -12,6 +12,10 @@ public final class LottieComponent: Component {
|
||||
public typealias EnvironmentType = Empty
|
||||
|
||||
open class Content: Equatable {
|
||||
open var frameRange: Range<Double> {
|
||||
preconditionFailure()
|
||||
}
|
||||
|
||||
public init() {
|
||||
}
|
||||
|
||||
@@ -34,8 +38,14 @@ public final class LottieComponent: Component {
|
||||
public final class AppBundleContent: Content {
|
||||
public let name: String
|
||||
|
||||
public init(name: String) {
|
||||
private let frameRangeValue: Range<Double>
|
||||
override public var frameRange: Range<Double> {
|
||||
return self.frameRangeValue
|
||||
}
|
||||
|
||||
public init(name: String, frameRange: Range<Double> = 0.0 ..< 1.0) {
|
||||
self.name = name
|
||||
self.frameRangeValue = frameRange
|
||||
}
|
||||
|
||||
override public func isEqual(to other: Content) -> Bool {
|
||||
@@ -45,6 +55,9 @@ public final class LottieComponent: Component {
|
||||
if self.name != other.name {
|
||||
return false
|
||||
}
|
||||
if self.frameRangeValue != other.frameRangeValue {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -59,9 +72,10 @@ public final class LottieComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
public enum StartingPosition {
|
||||
public enum StartingPosition: Equatable {
|
||||
case begin
|
||||
case end
|
||||
case fraction(Double)
|
||||
}
|
||||
|
||||
public let content: Content
|
||||
@@ -104,6 +118,7 @@ public final class LottieComponent: Component {
|
||||
private var scheduledPlayOnce: Bool = false
|
||||
private var playOnceCompletion: (() -> Void)?
|
||||
private var animationInstance: LottieInstance?
|
||||
private var animationFrameRange: Range<Int>?
|
||||
private var currentDisplaySize: CGSize?
|
||||
private var currentContentDisposable: Disposable?
|
||||
|
||||
@@ -171,7 +186,7 @@ public final class LottieComponent: Component {
|
||||
public func playOnce(delay: Double = 0.0, completion: (() -> Void)? = nil) {
|
||||
self.playOnceCompletion = completion
|
||||
|
||||
guard let _ = self.animationInstance else {
|
||||
guard let _ = self.animationInstance, let animationFrameRange = self.animationFrameRange else {
|
||||
self.scheduledPlayOnce = true
|
||||
return
|
||||
}
|
||||
@@ -182,8 +197,8 @@ public final class LottieComponent: Component {
|
||||
|
||||
self.scheduledPlayOnce = false
|
||||
|
||||
if self.currentFrame != 0 {
|
||||
self.currentFrame = 0
|
||||
if self.currentFrame != animationFrameRange.lowerBound {
|
||||
self.currentFrame = animationFrameRange.lowerBound
|
||||
self.updateImage()
|
||||
}
|
||||
|
||||
@@ -218,24 +233,35 @@ public final class LottieComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
private func loadAnimation(data: Data, cacheKey: String?, startingPosition: StartingPosition) {
|
||||
private func loadAnimation(data: Data, cacheKey: String?, startingPosition: StartingPosition, frameRange: Range<Double>) {
|
||||
self.animationInstance = LottieInstance(data: data, fitzModifier: .none, colorReplacements: nil, cacheKey: cacheKey ?? "")
|
||||
if let animationInstance = self.animationInstance {
|
||||
self.animationFrameRange = Int(floor(frameRange.lowerBound * Double(animationInstance.frameCount))) ..< Int(floor(frameRange.upperBound * Double(animationInstance.frameCount)))
|
||||
} else {
|
||||
self.animationFrameRange = nil
|
||||
}
|
||||
|
||||
if let _ = self.animationInstance, let animationFrameRange = self.animationFrameRange {
|
||||
switch startingPosition {
|
||||
case .begin:
|
||||
self.currentFrame = animationFrameRange.lowerBound
|
||||
case .end:
|
||||
self.currentFrame = Int(max(animationFrameRange.lowerBound, animationFrameRange.upperBound - 1))
|
||||
case let .fraction(fraction):
|
||||
self.currentFrame = animationFrameRange.lowerBound + Int(floor(Double(animationFrameRange.upperBound - animationFrameRange.lowerBound) * fraction))
|
||||
}
|
||||
}
|
||||
|
||||
if self.scheduledPlayOnce {
|
||||
self.scheduledPlayOnce = false
|
||||
self.playOnce()
|
||||
} else if let animationInstance = self.animationInstance {
|
||||
switch startingPosition {
|
||||
case .begin:
|
||||
self.currentFrame = 0
|
||||
case .end:
|
||||
self.currentFrame = Int(animationInstance.frameCount - 1)
|
||||
}
|
||||
} else {
|
||||
self.updateImage()
|
||||
}
|
||||
}
|
||||
|
||||
private func advanceIfNeeded() {
|
||||
guard let animationInstance = self.animationInstance else {
|
||||
guard let animationInstance = self.animationInstance, let animationFrameRange = self.animationFrameRange else {
|
||||
return
|
||||
}
|
||||
guard let currentFrameStartTime = self.currentFrameStartTime else {
|
||||
@@ -258,8 +284,8 @@ public final class LottieComponent: Component {
|
||||
advanceFrameCount = 4
|
||||
}
|
||||
self.currentFrame += advanceFrameCount
|
||||
if self.currentFrame >= Int(animationInstance.frameCount) - 1 {
|
||||
self.currentFrame = Int(animationInstance.frameCount) - 1
|
||||
if self.currentFrame >= animationFrameRange.upperBound - 1 {
|
||||
self.currentFrame = animationFrameRange.upperBound - 1
|
||||
self.updateImage()
|
||||
self.displayLink?.invalidate()
|
||||
self.displayLink = nil
|
||||
@@ -276,14 +302,17 @@ public final class LottieComponent: Component {
|
||||
}
|
||||
|
||||
private func updateImage() {
|
||||
guard let animationInstance = self.animationInstance, let currentDisplaySize = self.currentDisplaySize else {
|
||||
guard let animationInstance = self.animationInstance, let animationFrameRange = self.animationFrameRange, let currentDisplaySize = self.currentDisplaySize else {
|
||||
return
|
||||
}
|
||||
guard let context = DrawingContext(size: currentDisplaySize, scale: 1.0, opaque: false, clear: true) else {
|
||||
return
|
||||
}
|
||||
|
||||
animationInstance.renderFrame(with: Int32(self.currentFrame % Int(animationInstance.frameCount)), into: context.bytes.assumingMemoryBound(to: UInt8.self), width: Int32(currentDisplaySize.width), height: Int32(currentDisplaySize.height), bytesPerRow: Int32(context.bytesPerRow))
|
||||
var effectiveFrameIndex = self.currentFrame
|
||||
effectiveFrameIndex = max(animationFrameRange.lowerBound, min(animationFrameRange.upperBound, effectiveFrameIndex))
|
||||
|
||||
animationInstance.renderFrame(with: Int32(effectiveFrameIndex), into: context.bytes.assumingMemoryBound(to: UInt8.self), width: Int32(currentDisplaySize.width), height: Int32(currentDisplaySize.height), bytesPerRow: Int32(context.bytesPerRow))
|
||||
|
||||
var image = context.generateImage()
|
||||
if let _ = self.component?.color {
|
||||
@@ -316,12 +345,13 @@ public final class LottieComponent: Component {
|
||||
if previousComponent?.content != component.content {
|
||||
self.currentContentDisposable?.dispose()
|
||||
let content = component.content
|
||||
let frameRange = content.frameRange
|
||||
self.currentContentDisposable = component.content.load { [weak self, weak content] data, cacheKey in
|
||||
Queue.mainQueue().async {
|
||||
guard let self, let component = self.component, component.content == content else {
|
||||
return
|
||||
}
|
||||
self.loadAnimation(data: data, cacheKey: cacheKey, startingPosition: component.startingPosition)
|
||||
self.loadAnimation(data: data, cacheKey: cacheKey, startingPosition: component.startingPosition, frameRange: frameRange)
|
||||
}
|
||||
}
|
||||
} else if redrawImage {
|
||||
|
||||
Reference in New Issue
Block a user