Last active
April 14, 2020 15:37
-
-
Save Nimrodda/2161e44e6f0d0ab157bc4eedbaec87c6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class WorkoutSummaryViewModel : ViewModel() { | |
private val _viewState = MutableLiveData<WorkoutSummaryViewState>() | |
val viewState: LiveData<WorkoutSummaryViewState> = _viewState | |
// Conflated channel makes sure that we always keep only the last emitted item | |
// other channels have been omitted for brevity | |
private val likesItemChannel = ConflatedBroadcastChannel<ViewState<LikesItem>>() | |
fun loadData(workoutId: Int) { | |
viewModelScope.launch { | |
combine( | |
listOf( | |
loadCoverImages(workoutId), | |
loadLikesItem(workoutId), | |
loadComments(workoutId), | |
loadWorkoutSummary(workoutId) | |
) | |
) { arrayOfViewStates -> | |
// The order in the array is the same as in the combine function | |
WorkoutSummaryViewState( | |
coverImagesItem = arrayOfViewStates[0] as ViewState<CoverImagesItem>, | |
likesItem = arrayOfViewStates[1] as ViewState<LikesItem>, | |
commentsItem = arrayOfViewStates[2] as ViewState<CommentsItem>, | |
workoutSummaryItem = arrayOfViewStates[3] as ViewState<WorkoutSummaryItem> | |
) | |
}.conflate() | |
.flowOn(Dispatchers.Default) | |
.onEach { viewState -> | |
// Updating view state | |
_viewState.value = viewState | |
} | |
.collect() | |
} | |
} | |
private fun loadLikesItem( | |
workoutId: Int, | |
initialState: ViewState<LikesItem> = ViewState.Loading() | |
): Flow<ViewState<LikesItem>> { | |
viewModelScope.launch { | |
// Initial state, empty | |
likesItemChannel.send(initialState) | |
try { | |
// Load likes from db/server. likesRepository.loadLikes() is Main Safe. | |
// NOTE: Make sure your API is Main Safe or wrap call with withContext(Dispatchers.IO). | |
val loadedLikes = likesRepository.loadLikes(workoutId) | |
likesItemChannel.send( | |
ViewState.Loaded( | |
LikesItem( | |
// bind below props from loaded data, | |
hasUserLiked = loadedLikes.hasUserLiked, | |
likesCount = loadLikes.likesCount, | |
userAvatars = loadedLikes.userAvatars, | |
onClickHandler = ::onLikeClicked | |
) | |
) | |
) | |
} catch (e: Exception) { | |
likesItemChannel.send(ViewState.Error(e, initialState.data)) | |
} | |
} | |
return likesItemChannel.asFlow() | |
} | |
private fun onLikeClicked(workoutId: Int) { | |
viewModelScope.launch { | |
// We can get the old state from the channel | |
val oldState = likesItemChannel.asFlow().first() // TODO try-catch needed here | |
try { | |
// store like in local DB. storeLike() is Main Safe. | |
likesRepository.storeLike(workoutId) | |
// Reload likes, but this time we provide the previous state as initial state | |
// By reloading, we get a fresh state from the local DB | |
loadLikesItem(workoutId, oldState) | |
} catch (e: Exception) { | |
// Emit an error with the previous state. This way we can show an error, | |
// while still keeping the previous state in place. | |
likesItemChannel.send(ViewState.Error(e, oldState.data)) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment