Repository: airbnb/lottie-ios
File: Sources/Private/Experimental/ExperimentalAnimationLayer.swift (Swift)

Code before:
    for sublayer in sublayers ?? [] {
      sublayer.fillBoundsOfSuperlayer()
    }

    // If no animation has been set up yet, display the first frame
    // now that the layer hierarchy has been setup and laid out
    if
      currentAnimationConfiguration == nil,
      bounds.size != .zero
    {
      currentFrame = animation.frameTime(forProgress: animationProgress)
    }
  }

  // MARK: Private

  private struct AnimationConfiguration: Equatable {
    let animationContext: AnimationContext
    let timingConfiguration: CAMediaTimingConfiguration
  }

  private enum PlaybackState: Equatable {
    /// The animation is playing in real-time
    case realtime
    /// The animation is statically displaying a specific frame
    case specificFrame(AnimationFrameTime)
  }

  // Configuration for the animation that is currently setup in this layer
  private var currentAnimationConfiguration: AnimationConfiguration?

  /// The current progress of the placeholder `CAAnimation`,
  /// which is also the realtime animation progress of this layer's animation
  @objc private var animationProgress: CGFloat = 0

  private let animation: Animation
  private let valueProviderStore = ValueProviderStore()

  // The current state of the animation that is playing in this layer
  private var playbackState: PlaybackState? {
    didSet {
      switch playbackState {
      case .realtime, nil:
        timeOffset = 0
      case .specificFrame(let frame):
        timeOffset = animation.time(forFrame: frame)
      }
    }
  }

  private func setup() {

Review comment (suggestion):
nit: to me these case names are a bit confusing, I personally would find this more obvious if it was:
```suggestion
    /// The animation is playing in real-time
    case playing
    /// The animation is statically displaying a specific frame
    case paused(frame: AnimationFrameTime)
```

Code after:
    for sublayer in sublayers ?? [] {
      sublayer.fillBoundsOfSuperlayer()
    }

    // If no animation has been set up yet, display the first frame
    // now that the layer hierarchy has been setup and laid out
    if
      currentAnimationConfiguration == nil,
      bounds.size != .zero
    {
      currentFrame = animation.frameTime(forProgress: animationProgress)
    }
  }

  // MARK: Private

  private struct AnimationConfiguration: Equatable {
    let animationContext: AnimationContext
    let timingConfiguration: CAMediaTimingConfiguration
  }

  private enum PlaybackState: Equatable {
    /// The animation is playing in real-time
    case playing
    /// The animation is statically displaying a specific frame
    case paused(frame: AnimationFrameTime)
  }

  // Configuration for the animation that is currently setup in this layer
  private var currentAnimationConfiguration: AnimationConfiguration?

  /// The current progress of the placeholder `CAAnimation`,
  /// which is also the realtime animation progress of this layer's animation
  @objc private var animationProgress: CGFloat = 0

  private let animation: Animation
  private let valueProviderStore = ValueProviderStore()

  // The current playback state of the animation that is displayed in this layer
  private var playbackState: PlaybackState? {
    didSet {
      guard playbackState != oldValue else { return }

      switch playbackState {
      case .playing, nil:
        timeOffset = 0
      case .paused(let frame):
        timeOffset = animation.time(forFrame: frame)
      }
    }
  }