All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.peanuuutz.fork.ui.animation.Animations.kt Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2020 The Android Open Source Project
 * Modifications Copyright 2022 Peanuuutz
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.peanuuutz.fork.ui.animation

import net.peanuuutz.fork.ui.animation.TimeConstants.UnspecifiedTimeMillis
import net.peanuuutz.fork.ui.animation.spec.decay.DefaultFloatDecayAnimationSpec
import net.peanuuutz.fork.ui.animation.spec.decay.composite.DecayAnimationSpec
import net.peanuuutz.fork.ui.animation.spec.decay.composite.ExponentialDecaySpec
import net.peanuuutz.fork.ui.animation.spec.target.DefaultFloatAnimationSpec
import net.peanuuutz.fork.ui.animation.spec.target.composite.AnimationSpec
import net.peanuuutz.fork.ui.animation.spec.target.composite.SpringSpec
import net.peanuuutz.fork.ui.animation.vector.AnimationVector
import net.peanuuutz.fork.ui.animation.vector.VectorConvertor

suspend fun animate(
    initialValue: Float,
    targetValue: Float,
    initialVelocity: Float = 0.0f,
    animationSpec: AnimationSpec = DefaultFloatAnimationSpec,
    onFrame: (value: Float, velocity: Float) -> Unit
) {
    val initialVelocityVector = Float.VectorConvertor.convertToVector(initialVelocity)
    val animation = TargetBasedAnimation(
        vectorizedAnimationSpec = animationSpec.vectorize(Float.VectorConvertor),
        convertor = Float.VectorConvertor,
        initialValue = initialValue,
        targetValue = targetValue,
        initialVelocityVector = initialVelocityVector
    )
    val executionState = AnimationStateImpl(
        convertor = Float.VectorConvertor,
        initialValue = initialValue,
        initialVelocityVector = initialVelocityVector
    )
    animation.run(
        startTimeMillis = UnspecifiedTimeMillis,
        executionState = executionState
    ) { state ->
        onFrame(state.value, state.velocity)
    }
}

suspend fun animateDecay(
    initialValue: Float,
    initialVelocity: Float,
    decayAnimationSpec: DecayAnimationSpec = DefaultFloatDecayAnimationSpec,
    onFrame: (value: Float, velocity: Float) -> Unit
) {
    val initialVelocityVector = Float.VectorConvertor.convertToVector(initialVelocity)
    val animation = DecayAnimation(
        vectorizedDecayAnimationSpec = decayAnimationSpec.vectorize(Float.VectorConvertor),
        convertor = Float.VectorConvertor,
        initialValue = initialValue,
        initialVelocityVector = initialVelocityVector
    )
    val executionState = AnimationStateImpl(
        convertor = Float.VectorConvertor,
        initialValue = initialValue,
        initialVelocityVector = initialVelocityVector
    )
    animation.run(
        startTimeMillis = UnspecifiedTimeMillis,
        executionState = executionState
    ) { state ->
        onFrame(state.value, state.velocity)
    }
}

suspend fun > animate(
    convertor: VectorConvertor,
    initialValue: S,
    targetValue: S,
    initialVelocityVector: V? = null,
    animationSpec: AnimationSpec = SpringSpec(),
    onFrame: (value: S, velocityVector: V) -> Unit
) {
    val animation = TargetBasedAnimation(
        vectorizedAnimationSpec = animationSpec.vectorize(convertor),
        convertor = convertor,
        initialValue = initialValue,
        targetValue = targetValue,
        initialVelocityVector = initialVelocityVector
    )
    val executionState = AnimationStateImpl(
        convertor = convertor,
        initialValue = initialValue,
        initialVelocityVector = initialVelocityVector
    )
    animation.run(
        startTimeMillis = UnspecifiedTimeMillis,
        executionState = executionState
    ) { state ->
        onFrame(state.value, state.velocityVector)
    }
}

suspend fun > animateDecay(
    convertor: VectorConvertor,
    initialValue: S,
    initialVelocityVector: V,
    decayAnimationSpec: DecayAnimationSpec = ExponentialDecaySpec(),
    onFrame: (value: S, velocityVector: V) -> Unit
) {
    val animation = DecayAnimation(
        vectorizedDecayAnimationSpec = decayAnimationSpec.vectorize(convertor),
        convertor = convertor,
        initialValue = initialValue,
        initialVelocityVector = initialVelocityVector
    )
    val executionState = AnimationStateImpl(
        convertor = convertor,
        initialValue = initialValue,
        initialVelocityVector = initialVelocityVector
    )
    animation.run(
        startTimeMillis = UnspecifiedTimeMillis,
        executionState = executionState
    ) { state ->
        onFrame(state.value, state.velocityVector)
    }
}

suspend fun > AnimationState.animateTo(
    targetValue: S,
    animationSpec: AnimationSpec = SpringSpec(),
    shouldRestart: Boolean = true,
    onFrame: ((executionState: AnimationState) -> Unit)? = null
) {
    this as AnimationStateImpl
    val animation = animationSpec.createAnimation(
        convertor = convertor,
        initialValue = value,
        targetValue = targetValue,
        initialVelocityVector = velocityVector
    )
    animation.run(
        startTimeMillis = if (shouldRestart) UnspecifiedTimeMillis else lastFrameTimeMillis,
        executionState = this,
        callback = onFrame
    )
}

suspend fun > AnimationState.animateDecay(
    decayAnimationSpec: DecayAnimationSpec = ExponentialDecaySpec(),
    shouldRestart: Boolean = true,
    onFrame: ((executionState: AnimationState) -> Unit)? = null
) {
    this as AnimationStateImpl
    val animation = decayAnimationSpec.createAnimation(
        convertor = convertor,
        initialValue = value,
        initialVelocityVector = velocityVector
    )
    animation.run(
        startTimeMillis = if (shouldRestart) UnspecifiedTimeMillis else lastFrameTimeMillis,
        executionState = this,
        callback = onFrame
    )
}