• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download

<lambda>null1 package com.airbnb.lottie.sample.compose.lottiefiles
2 
3 import android.util.Log
4 import androidx.compose.foundation.layout.Box
5 import androidx.compose.foundation.layout.Column
6 import androidx.compose.foundation.layout.fillMaxWidth
7 import androidx.compose.foundation.layout.padding
8 import androidx.compose.foundation.lazy.LazyColumn
9 import androidx.compose.foundation.lazy.itemsIndexed
10 import androidx.compose.material.FloatingActionButton
11 import androidx.compose.material.Icon
12 import androidx.compose.material.icons.Icons
13 import androidx.compose.material.icons.filled.Repeat
14 import androidx.compose.runtime.Composable
15 import androidx.compose.runtime.SideEffect
16 import androidx.compose.runtime.getValue
17 import androidx.compose.ui.Alignment
18 import androidx.compose.ui.Modifier
19 import androidx.compose.ui.graphics.Color
20 import androidx.compose.ui.unit.dp
21 import androidx.navigation.NavController
22 import com.airbnb.lottie.sample.compose.Route
23 import com.airbnb.lottie.sample.compose.api.AnimationDataV2
24 import com.airbnb.lottie.sample.compose.api.LottieFilesApi
25 import com.airbnb.lottie.sample.compose.composables.AnimationRow
26 import com.airbnb.lottie.sample.compose.dagger.AssistedViewModelFactory
27 import com.airbnb.lottie.sample.compose.dagger.daggerMavericksViewModelFactory
28 import com.airbnb.mvrx.MavericksState
29 import com.airbnb.mvrx.MavericksViewModel
30 import com.airbnb.mvrx.MavericksViewModelFactory
31 import com.airbnb.mvrx.compose.collectAsState
32 import com.airbnb.mvrx.compose.mavericksViewModel
33 import dagger.assisted.Assisted
34 import dagger.assisted.AssistedFactory
35 import dagger.assisted.AssistedInject
36 import kotlinx.coroutines.Job
37 import kotlinx.coroutines.launch
38 
39 enum class LottieFilesMode {
40     Recent,
41     Popular,
42 }
43 
44 data class LottieFilesRecentAndPopularState(
45     val mode: LottieFilesMode = LottieFilesMode.Recent,
46     val results: List<AnimationDataV2> = emptyList(),
47     val currentPage: Int = 1,
48     val lastPage: Int = 0,
49     val fetchException: Boolean = false,
50 ) : MavericksState
51 
52 class LottieFilesRecentAndPopularViewModel @AssistedInject constructor(
53     @Assisted initialState: LottieFilesRecentAndPopularState,
54     private val api: LottieFilesApi,
55 ) : MavericksViewModel<LottieFilesRecentAndPopularState>(initialState) {
56     private var fetchJob: Job? = null
57 
58     init {
<lambda>null59         onEach(LottieFilesRecentAndPopularState::mode) {
60             setState { copy(results = emptyList(), currentPage = 0, lastPage = 1, fetchException = false) }
61             withState {
62                 fetchNextPage()
63             }
64         }
65     }
66 
fetchNextPagenull67     fun fetchNextPage() = withState { state ->
68         fetchJob?.cancel()
69         if (state.currentPage >= state.lastPage) return@withState
70         fetchJob = viewModelScope.launch {
71             val response = try {
72                 Log.d(TAG, "Fetching page ${state.currentPage + 1}")
73                 when (state.mode) {
74                     LottieFilesMode.Recent -> api.getRecent(state.currentPage + 1)
75                     LottieFilesMode.Popular -> api.getPopular(state.currentPage + 1)
76                 }
77             } catch (e: Exception) {
78                 Log.w(TAG, "Failed to fetch from Lottie Files.", e)
79                 setState { copy(fetchException = true) }
80                 return@launch
81             }
82             setState {
83                 copy(
84                     results = results + response.data.map(::AnimationDataV2),
85                     currentPage = response.current_page,
86                     lastPage = response.last_page,
87                     fetchException = false
88                 )
89             }
90         }
91     }
92 
<lambda>null93     fun setMode(mode: LottieFilesMode) = setState { copy(mode = mode) }
94 
95     @AssistedFactory
96     interface Factory : AssistedViewModelFactory<LottieFilesRecentAndPopularViewModel, LottieFilesRecentAndPopularState> {
createnull97         override fun create(initialState: LottieFilesRecentAndPopularState): LottieFilesRecentAndPopularViewModel
98     }
99 
100     companion object :
101         MavericksViewModelFactory<LottieFilesRecentAndPopularViewModel, LottieFilesRecentAndPopularState> by daggerMavericksViewModelFactory() {
102         private const val TAG = "LottieFilesVM"
103     }
104 }
105 
106 @Composable
LottieFilesRecentAndPopularPagenull107 fun LottieFilesRecentAndPopularPage(navController: NavController, mode: LottieFilesMode) {
108     val viewModel: LottieFilesRecentAndPopularViewModel = mavericksViewModel()
109     val state by viewModel.collectAsState()
110     SideEffect {
111         viewModel.setMode(mode)
112     }
113     LottieFilesRecentAndPopularPage(
114         state,
115         viewModel::fetchNextPage,
116         onAnimationClicked = { data ->
117             navController.navigate(Route.Player.forUrl(data.file, backgroundColor = data.bg_color))
118         }
119     )
120 }
121 
122 @Composable
LottieFilesRecentAndPopularPagenull123 fun LottieFilesRecentAndPopularPage(
124     state: LottieFilesRecentAndPopularState,
125     fetchNextPage: () -> Unit,
126     onAnimationClicked: (AnimationDataV2) -> Unit,
127     modifier: Modifier = Modifier,
128 ) {
129     Box(
130         modifier = Modifier
131             .fillMaxWidth()
132     ) {
133         Column(
134             modifier = Modifier.then(modifier)
135         ) {
136             LazyColumn(
137                 modifier = Modifier.weight(1f)
138             ) {
139                 itemsIndexed(state.results) { index, result ->
140                     if (index == state.results.size - 1) {
141                         SideEffect(fetchNextPage)
142                     }
143                     AnimationRow(
144                         title = result.title,
145                         previewUrl = result.preview_url ?: "",
146                         previewBackgroundColor = result.bgColor,
147                         onClick = { onAnimationClicked(result) }
148                     )
149                 }
150             }
151         }
152         if (state.fetchException) {
153             FloatingActionButton(
154                 onClick = fetchNextPage,
155                 content = {
156                     Icon(
157                         imageVector = Icons.Filled.Repeat,
158                         tint = Color.White,
159                         contentDescription = null
160                     )
161                 },
162                 modifier = Modifier
163                     .align(Alignment.BottomCenter)
164                     .padding(bottom = 24.dp)
165             )
166         }
167     }
168 }