blob: 592573e80788a6cc3770dc4c65e9cfa67f8a610f [file] [log] [blame]
package com.airbnb.lottie.samples
import android.animation.ValueAnimator
import android.app.Application
import android.net.Uri
import com.airbnb.lottie.LottieComposition
import com.airbnb.lottie.LottieCompositionFactory
import com.airbnb.lottie.LottieTask
import com.airbnb.lottie.samples.model.CompositionArgs
import com.airbnb.lottie.samples.utils.MvRxViewModel
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.MvRxState
import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.Uninitialized
import com.airbnb.mvrx.ViewModelContext
import java.io.FileInputStream
import kotlin.math.max
import kotlin.math.min
data class PlayerState(
val composition: Async<LottieComposition> = Uninitialized,
val controlsVisible: Boolean = true,
val controlBarVisible: Boolean = true,
val renderGraphVisible: Boolean = false,
val outlineMasksAndMattes: Boolean = false,
val borderVisible: Boolean = false,
val backgroundColorVisible: Boolean = false,
val speedVisible: Boolean = false,
val trimVisible: Boolean = false,
val useMergePaths: Boolean = false,
val minFrame: Int = 0,
val maxFrame: Int = 0,
val speed: Float = 1f,
val repeatCount: Int = ValueAnimator.INFINITE
) : MvRxState
class PlayerViewModel(
initialState: PlayerState,
private val application: Application
) : MvRxViewModel<PlayerState>(initialState) {
fun fetchAnimation(args: CompositionArgs) {
val url = args.url ?: args.animationDataV2?.file ?: args.animationData?.lottieLink
when {
url != null -> LottieCompositionFactory.fromUrl(application, url, null)
args.fileUri != null -> taskForUri(args.fileUri)
args.asset != null -> LottieCompositionFactory.fromAsset(application, args.asset, null)
else -> error("Don't know how to fetch animation for $args")
}
.addListener {
setState {
copy(composition = Success(it), minFrame = it.startFrame.toInt(), maxFrame = it.endFrame.toInt())
}
}
.addFailureListener { setState { copy(composition = Fail(it)) } }
}
private fun taskForUri(uri: Uri): LottieTask<LottieComposition> {
val fis = when (uri.scheme) {
"file" -> FileInputStream(uri.path ?: error("File has no path!"))
"content" -> application.contentResolver.openInputStream(uri)
else -> error("Unknown scheme ${uri.scheme}")
}
return LottieCompositionFactory.fromJsonInputStream(fis, null)
}
fun toggleRenderGraphVisible() = setState { copy(renderGraphVisible = !renderGraphVisible) }
fun toggleOutlineMasksAndMattes() = setState { copy(outlineMasksAndMattes = !outlineMasksAndMattes) }
fun toggleBorderVisible() = setState { copy(borderVisible = !borderVisible) }
fun toggleBackgroundColorVisible() = setState { copy(backgroundColorVisible = !backgroundColorVisible) }
fun setBackgroundColorVisible(visible: Boolean) = setState { copy(backgroundColorVisible = visible) }
fun toggleSpeedVisible() = setState { copy(speedVisible = !speedVisible) }
fun setSpeedVisible(visible: Boolean) = setState { copy(speedVisible = visible) }
fun toggleTrimVisible() = setState { copy(trimVisible = !trimVisible) }
fun setTrimVisible(visible: Boolean) = setState { copy(trimVisible = visible) }
fun toggleMergePaths() = setState { copy(useMergePaths = !useMergePaths) }
fun setMinFrame(minFrame: Int) = setState {
copy(minFrame = max(minFrame, composition()?.startFrame?.toInt() ?: 0))
}
fun setMaxFrame(maxFrame: Int) = setState {
copy(maxFrame = min(maxFrame, composition()?.endFrame?.toInt() ?: 0))
}
fun setSpeed(speed: Float) = setState { copy(speed = speed) }
fun toggleLoop() = setState { copy(repeatCount = if (repeatCount == ValueAnimator.INFINITE) 0 else ValueAnimator.INFINITE) }
fun setDistractionFree(distractionFree: Boolean) = setState {
copy(
controlsVisible = !distractionFree,
controlBarVisible = !distractionFree,
renderGraphVisible = false,
borderVisible = false,
backgroundColorVisible = false,
speedVisible = false,
trimVisible = false
)
}
companion object : MvRxViewModelFactory<PlayerViewModel, PlayerState> {
override fun create(viewModelContext: ViewModelContext, state: PlayerState): PlayerViewModel {
return PlayerViewModel(state, viewModelContext.app())
}
}
}