Skip to content

Commit

Permalink
Kotlinify FrameBasedAnimationDriver (facebook#45764)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: facebook#45764

# Changelog:
[Internal] -

As in the title.

Differential Revision: D60348765
  • Loading branch information
rshest authored and facebook-github-bot committed Jul 29, 2024
1 parent 0b26183 commit 308fad7
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 114 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

package com.facebook.react.animated

import com.facebook.common.logging.FLog
import com.facebook.react.bridge.ReadableMap
import com.facebook.react.bridge.ReadableType
import com.facebook.react.common.ReactConstants
import com.facebook.react.common.build.ReactBuildConfig

/**
* Implementation of [AnimationDriver] which provides a support for simple time-based animations
* that are pre-calculate on the JS side. For each animation frame JS provides a value from 0 to 1
* that indicates a progress of the animation at that frame.
*/
internal class FrameBasedAnimationDriver(config: ReadableMap) : AnimationDriver() {
private var startFrameTimeNanos: Long = -1
private var frames: DoubleArray = DoubleArray(0)
private var toValue = 0.0
private var fromValue = 0.0
private var iterations = 1
private var currentLoop = 1
private var logCount = 0

init {
resetConfig(config)
}

override fun resetConfig(config: ReadableMap) {
val framesConfig = config.getArray("frames")
if (framesConfig != null) {
val numberOfFrames = framesConfig.size()
if (frames.size != numberOfFrames) {
frames = DoubleArray(numberOfFrames)
}
for (i in 0 until numberOfFrames) {
frames[i] = framesConfig.getDouble(i)
}
}
toValue =
if (config.hasKey("toValue")) {
if (config.getType("toValue") == ReadableType.Number) config.getDouble("toValue") else 0.0
} else {
0.0
}
iterations =
if (config.hasKey("iterations")) {
if (config.getType("iterations") == ReadableType.Number) config.getInt("iterations")
else 1
} else {
1
}
currentLoop = 1
mHasFinished = iterations == 0
startFrameTimeNanos = -1
}

override fun runAnimationStep(frameTimeNanos: Long) {
if (startFrameTimeNanos < 0) {
startFrameTimeNanos = frameTimeNanos
if (currentLoop == 1) {
// initiate start value when animation runs for the first time
fromValue = mAnimatedValue.nodeValue
}
}
val timeFromStartMillis = (frameTimeNanos - startFrameTimeNanos) / 1000000
val frameIndex = Math.round(timeFromStartMillis / FRAME_TIME_MILLIS).toInt()
if (frameIndex < 0) {
val message =
("Calculated frame index should never be lower than 0. Called with frameTimeNanos " +
frameTimeNanos +
" and mStartFrameTimeNanos " +
startFrameTimeNanos)
check(!ReactBuildConfig.DEBUG) { message }
if (logCount < 100) {
FLog.w(ReactConstants.TAG, message)
logCount++
}
return
} else if (mHasFinished) {
// nothing to do here
return
}
val nextValue: Double
if (frameIndex >= frames.size - 1) {
if (iterations == -1 || currentLoop < iterations) {
// Use last frame value, just in case it's different from mToValue
nextValue = fromValue + frames[frames.size - 1] * (toValue - fromValue)
startFrameTimeNanos = -1
currentLoop++
} else {
// animation has completed, no more frames left
nextValue = toValue
mHasFinished = true
}
} else {
nextValue = fromValue + frames[frameIndex] * (toValue - fromValue)
}
mAnimatedValue.nodeValue = nextValue
}

companion object {
// 60FPS
private const val FRAME_TIME_MILLIS = 1000.0 / 60.0
}
}

0 comments on commit 308fad7

Please sign in to comment.