Repository: airbnb/lottie-ios
File: Sources/Public/Animation/LottieAnimationLayer.swift (Swift)

Code before:
      fatalError("\(Self.self).init(layer:) incorrectly called with \(type(of: layer))")
    }

    animation = typedLayer.animation
    imageProvider = typedLayer.imageProvider
    textProvider = typedLayer.textProvider
    fontProvider = typedLayer.fontProvider
    logger = typedLayer.logger
    screenScale = typedLayer.screenScale
    configuration = typedLayer.configuration
    super.init(layer: typedLayer)
  }

  required init?(coder _: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  // MARK: Open

  /// Plays the animation from its current state to the end.
  ///
  /// - Parameter completion: An optional completion closure to be called when the animation completes playing.
  open func play(completion: LottieCompletionBlock? = nil) {
    guard let animation else { return }

    if renderStaticFrameIfNeeded(completion: completion) { return }

    defer {
      currentPlaybackMode = .playing(.fromProgress(nil, toProgress: 1, loopMode: loopMode))
    }

    if shouldOverrideWithReducedMotionAnimation {
      playReducedMotionAnimation(completion: completion)
      return
    }

    /// Build a context for the animation.
    let context = AnimationContext(
      playFrom: CGFloat(animation.startFrame),
      playTo: CGFloat(animation.endFrame),
      framerate: animation.framerate,
      closure: completion
    )
    removeCurrentAnimationIfNecessary()
    addNewAnimationForContext(context)
  }

  /// Plays the animation from a progress (0-1) to a progress (0-1).
  ///
  /// - Parameter fromProgress: The start progress of the animation. If `nil` the animation will start at the current progress.
  /// - Parameter toProgress: The end progress of the animation.

Review comment (refactor):
wdyt about https://github.com/airbnb/lottie-ios/pull/2642#pullrequestreview-3699712052?

> There's an existing pattern we're using everywhere:
>
> ```swift
> if shouldOverrideWithReducedMotionAnimation {
>   playReducedMotionAnimation(completion: completion)
>   return
> }
> ```
>
> We should create a shared helper that handles both of these cases, and then use that in all of the places that are currently calling `playReducedMotionAnimation`

It would be great for the reduced motion and disabled motion checks to be colocated

Code after:
      fatalError("\(Self.self).init(layer:) incorrectly called with \(type(of: layer))")
    }

    animation = typedLayer.animation
    imageProvider = typedLayer.imageProvider
    textProvider = typedLayer.textProvider
    fontProvider = typedLayer.fontProvider
    logger = typedLayer.logger
    screenScale = typedLayer.screenScale
    configuration = typedLayer.configuration
    super.init(layer: typedLayer)
  }

  required init?(coder _: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  // MARK: Open

  /// Plays the animation from its current state to the end.
  ///
  /// - Parameter completion: An optional completion closure to be called when the animation completes playing.
  open func play(completion: LottieCompletionBlock? = nil) {
    guard let animation else { return }

    defer {
      currentPlaybackMode = .playing(.fromProgress(nil, toProgress: 1, loopMode: loopMode))
    }

    if overrideReducedMotionIfNeeded(completion: completion) { return }

    /// Build a context for the animation.
    let context = AnimationContext(
      playFrom: CGFloat(animation.startFrame),
      playTo: CGFloat(animation.endFrame),
      framerate: animation.framerate,
      closure: completion
    )
    removeCurrentAnimationIfNecessary()
    addNewAnimationForContext(context)
  }

  /// Plays the animation from a progress (0-1) to a progress (0-1).
  ///
  /// - Parameter fromProgress: The start progress of the animation. If `nil` the animation will start at the current progress.
  /// - Parameter toProgress: The end progress of the animation.
  /// - Parameter loopMode: The loop behavior of the animation. If `nil` the layer's `loopMode` property will be used.
  /// - Parameter completion: An optional completion closure to be called when the animation stops.
  open func play(
    fromProgress: AnimationProgressTime? = nil,
    toProgress: AnimationProgressTime,