1 package com.airbnb.lottie.samples 2 3 import android.animation.ValueAnimator 4 import android.app.Application 5 import android.net.Uri 6 import com.airbnb.lottie.LottieComposition 7 import com.airbnb.lottie.LottieCompositionFactory 8 import com.airbnb.lottie.LottieTask 9 import com.airbnb.lottie.samples.model.CompositionArgs 10 import com.airbnb.mvrx.Async 11 import com.airbnb.mvrx.Fail 12 import com.airbnb.mvrx.MavericksState 13 import com.airbnb.mvrx.MavericksViewModel 14 import com.airbnb.mvrx.MavericksViewModelFactory 15 import com.airbnb.mvrx.Success 16 import com.airbnb.mvrx.Uninitialized 17 import com.airbnb.mvrx.ViewModelContext 18 import java.io.FileInputStream 19 import kotlin.math.max 20 import kotlin.math.min 21 22 data class PlayerState( 23 val composition: Async<LottieComposition> = Uninitialized, 24 val controlsVisible: Boolean = true, 25 val controlBarVisible: Boolean = true, 26 val renderGraphVisible: Boolean = false, 27 val outlineMasksAndMattes: Boolean = false, 28 val borderVisible: Boolean = false, 29 val backgroundColorVisible: Boolean = false, 30 val speedVisible: Boolean = false, 31 val trimVisible: Boolean = false, 32 val useMergePaths: Boolean = false, 33 val minFrame: Int = 0, 34 val maxFrame: Int = 0, 35 val speed: Float = 1f, 36 val repeatCount: Int = ValueAnimator.INFINITE 37 ) : MavericksState 38 39 class PlayerViewModel( 40 initialState: PlayerState, 41 private val application: Application 42 ) : MavericksViewModel<PlayerState>(initialState) { 43 fetchAnimationnull44 fun fetchAnimation(args: CompositionArgs) { 45 val url = args.url 46 47 when { 48 url != null -> LottieCompositionFactory.fromUrl(application, url, null) 49 args.fileUri != null -> taskForUri(args.fileUri) 50 args.asset != null -> LottieCompositionFactory.fromAsset(application, args.asset, null) 51 else -> error("Don't know how to fetch animation for $args") 52 } 53 .addListener { 54 setState { 55 copy(composition = Success(it), minFrame = it.startFrame.toInt(), maxFrame = it.endFrame.toInt()) 56 } 57 } 58 .addFailureListener { setState { copy(composition = Fail(it)) } } 59 } 60 taskForUrinull61 private fun taskForUri(uri: Uri): LottieTask<LottieComposition> { 62 val fis = when (uri.scheme) { 63 "file" -> FileInputStream(uri.path ?: error("File has no path!")) 64 "content" -> application.contentResolver.openInputStream(uri) 65 else -> error("Unknown scheme ${uri.scheme}") 66 } 67 68 return LottieCompositionFactory.fromJsonInputStream(fis, null) 69 } 70 <lambda>null71 fun toggleRenderGraphVisible() = setState { copy(renderGraphVisible = !renderGraphVisible) } 72 <lambda>null73 fun toggleOutlineMasksAndMattes() = setState { copy(outlineMasksAndMattes = !outlineMasksAndMattes) } 74 <lambda>null75 fun toggleBorderVisible() = setState { copy(borderVisible = !borderVisible) } 76 <lambda>null77 fun toggleBackgroundColorVisible() = setState { copy(backgroundColorVisible = !backgroundColorVisible) } 78 <lambda>null79 fun setBackgroundColorVisible(visible: Boolean) = setState { copy(backgroundColorVisible = visible) } 80 <lambda>null81 fun toggleSpeedVisible() = setState { copy(speedVisible = !speedVisible) } 82 <lambda>null83 fun setSpeedVisible(visible: Boolean) = setState { copy(speedVisible = visible) } 84 <lambda>null85 fun toggleTrimVisible() = setState { copy(trimVisible = !trimVisible) } 86 <lambda>null87 fun setTrimVisible(visible: Boolean) = setState { copy(trimVisible = visible) } 88 <lambda>null89 fun toggleMergePaths() = setState { copy(useMergePaths = !useMergePaths) } 90 <lambda>null91 fun setMinFrame(minFrame: Int) = setState { 92 copy(minFrame = max(minFrame, composition()?.startFrame?.toInt() ?: 0)) 93 } 94 <lambda>null95 fun setMaxFrame(maxFrame: Int) = setState { 96 copy(maxFrame = min(maxFrame, composition()?.endFrame?.toInt() ?: 0)) 97 } 98 <lambda>null99 fun setSpeed(speed: Float) = setState { copy(speed = speed) } 100 <lambda>null101 fun toggleLoop() = setState { copy(repeatCount = if (repeatCount == ValueAnimator.INFINITE) 0 else ValueAnimator.INFINITE) } 102 <lambda>null103 fun setDistractionFree(distractionFree: Boolean) = setState { 104 copy( 105 controlsVisible = !distractionFree, 106 controlBarVisible = !distractionFree, 107 renderGraphVisible = false, 108 borderVisible = false, 109 backgroundColorVisible = false, 110 speedVisible = false, 111 trimVisible = false 112 ) 113 } 114 115 companion object : MavericksViewModelFactory<PlayerViewModel, PlayerState> { createnull116 override fun create(viewModelContext: ViewModelContext, state: PlayerState): PlayerViewModel { 117 return PlayerViewModel(state, viewModelContext.app()) 118 } 119 } 120 } 121