/** * Teapod * * Copyright 2020-2022 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ package org.mosad.teapod.ui.activity.main.viewmodel import androidx.lifecycle.LifecycleCoroutineScope import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.async import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import org.mosad.teapod.parser.crunchyroll.* import kotlin.random.Random class HomeViewModel : ViewModel() { private val uiState = MutableStateFlow(UiState.Loading) sealed class UiState { object Loading : UiState() data class Normal( val upNextItems: List, val watchlistItems: List, val recentlyAddedItems: List, val topTenItems: List, val highlightItem: Item, val highlightIsWatchlist:Boolean ) : UiState() data class Error(val message: String?) : UiState() } init { load() } fun onUiState(scope: LifecycleCoroutineScope, collector: (UiState) -> Unit) { scope.launch { uiState.collect { collector(it) } } } fun load() { viewModelScope.launch { uiState.emit(UiState.Loading) try { // run the loading in parallel to speed up the process val upNextJob = viewModelScope.async { Crunchyroll.upNextAccount().items } val watchlistJob = viewModelScope.async { Crunchyroll.watchlist(50).items } val recentlyAddedJob = viewModelScope.async { Crunchyroll.browse(sortBy = SortBy.NEWLY_ADDED, n = 50).items } val topTenJob = viewModelScope.async { Crunchyroll.browse(sortBy = SortBy.POPULARITY, n = 10).items } val recentlyAddedItems = recentlyAddedJob.await() // FIXME crashes on newTitles.items.size == 0 val highlightItem = recentlyAddedItems[Random.nextInt(recentlyAddedItems.size)] val highlightItemIsWatchlist = Crunchyroll.isWatchlist(highlightItem.id) uiState.emit(UiState.Normal( upNextJob.await(), watchlistJob.await(), recentlyAddedJob.await(), topTenJob.await(), highlightItem, highlightItemIsWatchlist )) } catch (e: Exception) { uiState.emit(UiState.Error(e.message)) } } } /** * Toggle the watchlist state of the highlight media. */ fun toggleHighlightWatchlist() { viewModelScope.launch { uiState.update { currentUiState -> if (currentUiState is UiState.Normal) { if (currentUiState.highlightIsWatchlist) { Crunchyroll.deleteWatchlist(currentUiState.highlightItem.id) } else { Crunchyroll.postWatchlist(currentUiState.highlightItem.id) } // update the watchlist after a item has been added/removed val watchlistItems = Crunchyroll.watchlist(50).items currentUiState.copy( watchlistItems = watchlistItems, highlightIsWatchlist = !currentUiState.highlightIsWatchlist) } else { currentUiState } } } } }