From 314e4ca964382489f8f7597baad514a9e317b346 Mon Sep 17 00:00:00 2001 From: Owen LeJeune Date: Sun, 30 Jul 2023 22:11:33 -0400 Subject: [PATCH] fix up some season loading stuff --- .../tvtime/api/tmdb/api/v3/MoviesApi.kt | 2 +- .../tvtime/api/tmdb/api/v3/MoviesService.kt | 3 +- .../tvtime/ui/screens/MediaDetailScreen.kt | 9 +- .../tvtime/ui/screens/SeasonDetailsView.kt | 87 ++++++++++++++++--- .../tvtime/ui/screens/SeasonListScreen.kt | 2 +- .../tvtime/utils/SessionManager.kt | 3 + 6 files changed, 88 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/MoviesApi.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/MoviesApi.kt index 75cc409..0a81839 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/MoviesApi.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/MoviesApi.kt @@ -64,7 +64,7 @@ interface MoviesApi { suspend fun getExternalIds(@Path("id") id: Int): Response @GET("movie/{id}/account_states") - suspend fun getAccountStates(@Path("id") id: Int, @Query("session_id") sessionId: String): Response + suspend fun getAccountStates(@Path("id") id: Int): Response @GET("discover/movie") suspend fun discover(@Query("with_keywords") keywords: String? = null, @Query("page") page: Int): Response> diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/MoviesService.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/MoviesService.kt index 2ed24a0..35c12de 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/MoviesService.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/MoviesService.kt @@ -148,9 +148,8 @@ class MoviesService: KoinComponent, DetailService, HomePageService { } override suspend fun getAccountStates(id: Int) { - val sessionId = SessionManager.currentSession.value?.sessionId ?: throw Exception("Session must not be null") loadRemoteData( - { movieService.getAccountStates(id, sessionId) }, + { movieService.getAccountStates(id) }, { accountStates[id] = it }, accountStatesLoadingState, false diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/MediaDetailScreen.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/MediaDetailScreen.kt index 9eee454..cb05834 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/MediaDetailScreen.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/MediaDetailScreen.kt @@ -145,7 +145,9 @@ private fun fetchData( scope.launch { mainViewModel.getVideos(itemId, type, force) } scope.launch { mainViewModel.getWatchProviders(itemId, type, force) } scope.launch { mainViewModel.getReviews(itemId, type, force) } - scope.launch { mainViewModel.getAccountStates(itemId, type) } + if (SessionManager.isLoggedIn) { + scope.launch { mainViewModel.getAccountStates(itemId, type) } + } when (type) { MediaViewType.MOVIE -> { @@ -190,6 +192,9 @@ fun MediaDetailScreen( if (type == MediaViewType.TV) { LaunchedEffect(mediaItem) { val lastSeason = (mediaItem as DetailedTv?)?.numberOfSeasons ?: 0 +// for (i in lastSeason downTo 0) { +// mainViewModel.getSeason(itemId, i) +// } if (lastSeason > 0) { mainViewModel.getSeason(itemId, lastSeason) } @@ -871,7 +876,7 @@ private fun SeasonCard( appNavController: NavController ) { val seasonsMap = remember { mainViewModel.tvSeasons } - val lastSeason = seasonsMap[itemId]?.lastOrNull() + val lastSeason = seasonsMap[itemId]?.maxByOrNull { it.seasonNumber } lastSeason?.let { ContentCard( diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/SeasonDetailsView.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/SeasonDetailsView.kt index f69b5c1..3dd3039 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/SeasonDetailsView.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/SeasonDetailsView.kt @@ -1,6 +1,11 @@ package com.owenlejeune.tvtime.ui.screens +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.core.Animatable +import androidx.compose.animation.core.LinearEasing +import androidx.compose.animation.core.tween import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -9,17 +14,26 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.ExpandMore import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.rotate import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @@ -29,6 +43,7 @@ import com.google.accompanist.pager.ExperimentalPagerApi import com.owenlejeune.tvtime.R import com.owenlejeune.tvtime.api.tmdb.api.v3.model.Episode import com.owenlejeune.tvtime.api.tmdb.api.v3.model.Season +import com.owenlejeune.tvtime.api.tmdb.api.v3.model.SeasonAccountStates import com.owenlejeune.tvtime.extensions.toCompositeParts import com.owenlejeune.tvtime.ui.components.BackButton import com.owenlejeune.tvtime.ui.components.CastCrewCard @@ -42,6 +57,7 @@ import com.owenlejeune.tvtime.ui.components.WatchProvidersCard import com.owenlejeune.tvtime.ui.theme.Typography import com.owenlejeune.tvtime.ui.viewmodel.ApplicationViewModel import com.owenlejeune.tvtime.ui.viewmodel.MainViewModel +import com.owenlejeune.tvtime.utils.SessionManager import com.owenlejeune.tvtime.utils.TmdbUtils import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -55,7 +71,9 @@ private fun fetchData( ) { val scope = CoroutineScope(Dispatchers.IO) scope.launch { mainViewModel.getSeason(seriesId, seasonNumber, force) } - scope.launch { mainViewModel.getSeasonAccountStates(seriesId, seasonNumber, force) } + if (SessionManager.isLoggedIn) { + scope.launch { mainViewModel.getSeasonAccountStates(seriesId, seasonNumber, force) } + } scope.launch { mainViewModel.getSeasonImages(seriesId, seasonNumber, force) } scope.launch { mainViewModel.getSeasonVideos(seriesId, seasonNumber, force) } scope.launch { mainViewModel.getSeasonCredits(seriesId, seasonNumber, force) } @@ -126,26 +144,61 @@ private fun SeasonContent( expandedPosterAsBackdrop = true ) + var isExpanded by remember { mutableStateOf(true) } Column( modifier = Modifier .padding(start = 16.dp, end = 16.dp), verticalArrangement = Arrangement.spacedBy(16.dp) ) { - Text( - text = season.name, - color = MaterialTheme.colorScheme.secondary, - style = Typography.headlineLarge, - maxLines = 2, - overflow = TextOverflow.Ellipsis, - modifier = Modifier.fillMaxWidth() - ) + Row { + Text( + text = season.name, + color = MaterialTheme.colorScheme.secondary, + style = Typography.headlineLarge, + maxLines = 2, + overflow = TextOverflow.Ellipsis + ) + Spacer(modifier = Modifier.weight(1f)) + var currentRotation by remember { mutableFloatStateOf(180f) } + val rotation = remember { Animatable(currentRotation) } + LaunchedEffect(isExpanded) { + rotation.animateTo( + targetValue = if (isExpanded) 180f else 0f, + animationSpec = tween(200, easing = LinearEasing) + ) { + currentRotation = value + } + } + Icon( + imageVector = Icons.Outlined.ExpandMore, + contentDescription = null, + modifier = Modifier + .size(48.dp) + .rotate(currentRotation) + .clickable { + isExpanded = !isExpanded + }, + tint = MaterialTheme.colorScheme.onSurface, + ) + } val accountStatesMap = remember { mainViewModel.tvSeasonAccountStates } val accountStates = accountStatesMap[seriesId]?.get(season.seasonNumber) - season.episodes.forEach { episode -> - val rating = accountStates?.results?.find { it.id == episode.id }?.takeUnless { !it.isRated }?.rating - SeasonEpisodeItem(appNavController = appNavController, episode = episode, rating = rating) + AnimatedVisibility( + visible = isExpanded + ) { + Column( + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + season.episodes.forEach { episode -> + DrawEpisodeCard( + episode = episode, + accountStates = accountStates, + appNavController = appNavController + ) + } + } } val imagesMap = remember { mainViewModel.tvSeasonImages } @@ -173,6 +226,16 @@ private fun SeasonContent( } } +@Composable +private fun DrawEpisodeCard( + episode: Episode, + accountStates: SeasonAccountStates?, + appNavController: NavController +) { + val rating = accountStates?.results?.find { it.id == episode.id }?.takeUnless { !it.isRated }?.rating + SeasonEpisodeItem(appNavController = appNavController, episode = episode, rating = rating) +} + @Composable private fun SeasonEpisodeItem( appNavController: NavController, diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/SeasonListScreen.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/SeasonListScreen.kt index 82b709d..9414450 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/SeasonListScreen.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/SeasonListScreen.kt @@ -102,7 +102,7 @@ fun SeasonListScreen( appNavController = appNavController, seriesId = id, season = season, - expandedByDefault = index == 0 + expandedByDefault = index == 1 ) } diff --git a/app/src/main/java/com/owenlejeune/tvtime/utils/SessionManager.kt b/app/src/main/java/com/owenlejeune/tvtime/utils/SessionManager.kt index 8d85cae..5958cef 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/utils/SessionManager.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/utils/SessionManager.kt @@ -29,6 +29,9 @@ object SessionManager: KoinComponent { val currentSession = mutableStateOf(null) + val isLoggedIn: Boolean + get() = currentSession.value?.isAuthorized == true + class AuthorizedSessionValues( @SerializedName("session_id") val sessionId: String, @SerializedName("access_token") val accessToken: String,