2022-04-10 17:39:30 +02:00
/ * *
* Teapod
*
* Copyright 2020 - 2022 < seil0 @mosad . xyz >
*
* 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
2023-02-19 14:21:46 +01:00
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
2022-04-10 17:39:30 +02:00
import kotlinx.coroutines.launch
import org.mosad.teapod.parser.crunchyroll.*
import kotlin.random.Random
2023-10-15 18:44:22 +02:00
class HomeViewModel : ViewModel ( ) {
2022-04-10 17:39:30 +02:00
2022-11-26 17:46:25 +01:00
private val WATCHLIST _LENGTH = 50
2022-04-10 17:39:30 +02:00
private val uiState = MutableStateFlow < UiState > ( UiState . Loading )
sealed class UiState {
object Loading : UiState ( )
data class Normal (
2023-02-19 14:21:46 +01:00
val upNextItems : List < UpNextAccountItem > ,
2022-04-10 17:39:30 +02:00
val watchlistItems : List < Item > ,
2022-05-22 11:21:49 +02:00
val recommendationsItems : List < Item > ,
2022-04-10 17:39:30 +02:00
val recentlyAddedItems : List < Item > ,
val topTenItems : List < Item > ,
val highlightItem : Item ,
2022-09-20 19:47:42 +02:00
val highlightItemUpNext : UpNextSeriesItem ,
2022-04-10 17:39:30 +02:00
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
2023-07-21 17:22:45 +02:00
val upNextJob = viewModelScope . async { Crunchyroll . upNextAccount ( n = 20 ) . data }
2023-07-21 11:39:48 +02:00
val watchlistJob = viewModelScope . async { Crunchyroll . watchlist ( WATCHLIST _LENGTH ) . data }
2022-05-22 11:21:49 +02:00
val recommendationsJob = viewModelScope . async {
2023-07-21 17:22:45 +02:00
Crunchyroll . recommendations ( n = 20 ) . data
2022-05-22 11:21:49 +02:00
}
2022-04-10 17:39:30 +02:00
val recentlyAddedJob = viewModelScope . async {
2023-07-21 17:22:45 +02:00
Crunchyroll . browse ( sortBy = SortBy . NEWLY _ADDED , n = 50 ) . data
2022-04-10 17:39:30 +02:00
}
val topTenJob = viewModelScope . async {
2023-07-21 17:22:45 +02:00
Crunchyroll . browse ( sortBy = SortBy . POPULARITY , n = 10 ) . data
2022-04-10 17:39:30 +02:00
}
val recentlyAddedItems = recentlyAddedJob . await ( )
// FIXME crashes on newTitles.items.size == 0
val highlightItem = recentlyAddedItems [ Random . nextInt ( recentlyAddedItems . size ) ]
2022-09-20 19:47:42 +02:00
val highlightItemUpNextJob = viewModelScope . async {
2023-02-19 14:21:46 +01:00
Crunchyroll . upNextSeries ( highlightItem . id ) . data . first ( )
2022-09-20 19:47:42 +02:00
}
val highlightItemIsWatchlistJob = viewModelScope . async {
Crunchyroll . isWatchlist ( highlightItem . id )
}
2022-04-10 17:39:30 +02:00
uiState . emit ( UiState . Normal (
2022-05-22 11:21:49 +02:00
upNextJob . await ( ) , watchlistJob . await ( ) , recommendationsJob . await ( ) ,
recentlyAddedJob . await ( ) , topTenJob . await ( ) , highlightItem ,
2022-09-20 19:47:42 +02:00
highlightItemUpNextJob . await ( ) , highlightItemIsWatchlistJob . await ( )
2022-04-10 17:39:30 +02:00
) )
} 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
2023-07-21 11:39:48 +02:00
val watchlistItems = Crunchyroll . watchlist ( WATCHLIST _LENGTH ) . data
2022-04-10 17:39:30 +02:00
currentUiState . copy (
watchlistItems = watchlistItems ,
highlightIsWatchlist = ! currentUiState . highlightIsWatchlist )
} else {
currentUiState
}
}
}
}
2022-11-26 17:46:25 +01:00
/ * *
* Update the up next list . To be used on player result callbacks .
* /
fun updateUpNextItems ( ) {
viewModelScope . launch {
uiState . update { currentUiState ->
if ( currentUiState is UiState . Normal ) {
2023-07-21 17:22:45 +02:00
val upNextItems = Crunchyroll . upNextAccount ( n = 20 ) . data
2022-11-26 17:46:25 +01:00
currentUiState . copy ( upNextItems = upNextItems )
} else {
currentUiState
}
}
}
}
}