mirror of
https://github.com/owenlejeune/TVTime.git
synced 2025-11-08 12:42:44 -05:00
fetch v4 lists from api
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package com.owenlejeune.tvtime
|
||||
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.animation.rememberSplineBasedDecay
|
||||
import androidx.compose.foundation.layout.*
|
||||
@@ -70,9 +71,14 @@ class MainActivity : MonetCompatActivity() {
|
||||
setContent {
|
||||
AppKeyboardFocusManager()
|
||||
TVTimeTheme(monetCompat = monet) {
|
||||
val windowSize = rememberWindowSizeClass()
|
||||
val appNavController = rememberNavController()
|
||||
Box {
|
||||
MainNavigationRoutes(appNavController = appNavController, mainNavStartRoute = mainNavStartRoute)
|
||||
MainNavigationRoutes(
|
||||
appNavController = appNavController,
|
||||
mainNavStartRoute = mainNavStartRoute,
|
||||
windowSize = windowSize
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,10 +89,9 @@ class MainActivity : MonetCompatActivity() {
|
||||
private fun AppScaffold(
|
||||
appNavController: NavHostController,
|
||||
mainNavStartRoute: String = BottomNavItem.SortedItems[0].route,
|
||||
windowSize: WindowSizeClass,
|
||||
preferences: AppPreferences = get(AppPreferences::class.java)
|
||||
) {
|
||||
val windowSize = rememberWindowSizeClass()
|
||||
|
||||
val navController = rememberNavController()
|
||||
val navBackStackEntry by navController.currentBackStackEntryAsState()
|
||||
val currentRoute = navBackStackEntry?.destination?.route
|
||||
@@ -363,11 +368,16 @@ class MainActivity : MonetCompatActivity() {
|
||||
startDestination: String = MainNavItem.MainView.route,
|
||||
mainNavStartRoute: String = MainNavItem.Items[0].route,
|
||||
appNavController: NavHostController,
|
||||
windowSize: WindowSizeClass,
|
||||
preferences: AppPreferences = get(AppPreferences::class.java)
|
||||
) {
|
||||
NavHost(navController = appNavController, startDestination = startDestination) {
|
||||
composable(MainNavItem.MainView.route) {
|
||||
AppScaffold(appNavController = appNavController, mainNavStartRoute = mainNavStartRoute)
|
||||
AppScaffold(
|
||||
appNavController = appNavController,
|
||||
mainNavStartRoute = mainNavStartRoute,
|
||||
windowSize = windowSize
|
||||
)
|
||||
}
|
||||
composable(
|
||||
MainNavItem.DetailView.route.plus("/{${NavConstants.TYPE_KEY}}/{${NavConstants.ID_KEY}}"),
|
||||
@@ -378,17 +388,27 @@ class MainActivity : MonetCompatActivity() {
|
||||
) { navBackStackEntry ->
|
||||
val args = navBackStackEntry.arguments
|
||||
val mediaType = args?.getSerializable(NavConstants.TYPE_KEY) as MediaViewType
|
||||
if (mediaType != MediaViewType.PERSON) {
|
||||
MediaDetailView(
|
||||
appNavController = appNavController,
|
||||
itemId = args.getInt(NavConstants.ID_KEY),
|
||||
type = mediaType
|
||||
)
|
||||
} else {
|
||||
PersonDetailView(
|
||||
appNavController = appNavController,
|
||||
personId = args.getInt(NavConstants.ID_KEY)
|
||||
)
|
||||
|
||||
when (mediaType) {
|
||||
MediaViewType.PERSON -> {
|
||||
PersonDetailView(
|
||||
appNavController = appNavController,
|
||||
personId = args.getInt(NavConstants.ID_KEY)
|
||||
)
|
||||
}
|
||||
MediaViewType.LIST -> {
|
||||
LocalContext.current.let {
|
||||
Toast.makeText(it, "It's a list!", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
MediaDetailView(
|
||||
appNavController = appNavController,
|
||||
itemId = args.getInt(NavConstants.ID_KEY),
|
||||
type = mediaType,
|
||||
windowSize = windowSize
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
composable(
|
||||
|
||||
@@ -9,34 +9,35 @@ import com.owenlejeune.tvtime.api.tmdb.api.v4.model.V4RatedTv
|
||||
import retrofit2.Response
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Path
|
||||
import retrofit2.http.Query
|
||||
|
||||
interface AccountV4Api {
|
||||
|
||||
@GET("account/{account_id}/lists")
|
||||
suspend fun getLists(@Path("account_id") accountId: String, page: Int = 1): Response<V4AccountResponse<V4AccountList>>
|
||||
suspend fun getLists(@Path("account_id") accountId: String, @Query("page") page: Int = 1): Response<V4AccountResponse<V4AccountList>>
|
||||
|
||||
@GET("account/{account_id}/movie/favorites")
|
||||
suspend fun getFavoriteMovies(@Path("account_id") accountId: String, page: Int = 1): Response<V4AccountResponse<FavoriteMovie>>
|
||||
suspend fun getFavoriteMovies(@Path("account_id") accountId: String, @Query("page") page: Int = 1): Response<V4AccountResponse<FavoriteMovie>>
|
||||
|
||||
@GET("account/{account_id}/tv/favorites")
|
||||
suspend fun getFavoriteTvShows(@Path("account_id") accountId: String, page: Int = 1): Response<V4AccountResponse<FavoriteTvSeries>>
|
||||
suspend fun getFavoriteTvShows(@Path("account_id") accountId: String, @Query("page") page: Int = 1): Response<V4AccountResponse<FavoriteTvSeries>>
|
||||
|
||||
@GET("account/{account_id}/movie/recommendations")
|
||||
suspend fun getMovieRecommendations(@Path("account_id") accountId: String, page: Int = 1): Response<V4AccountResponse<FavoriteMovie>>
|
||||
suspend fun getMovieRecommendations(@Path("account_id") accountId: String, @Query("page") page: Int = 1): Response<V4AccountResponse<FavoriteMovie>>
|
||||
|
||||
@GET("account/{account_id}/tv/recommendations")
|
||||
suspend fun getTvShowRecommendations(@Path("account_id") accountId: String, page: Int = 1): Response<V4AccountResponse<FavoriteTvSeries>>
|
||||
suspend fun getTvShowRecommendations(@Path("account_id") accountId: String, @Query("page") page: Int = 1): Response<V4AccountResponse<FavoriteTvSeries>>
|
||||
|
||||
@GET("account/{account_id}/movie/watchlist")
|
||||
suspend fun getMovieWatchlist(@Path("account_id") accountId: String, page: Int = 1): Response<V4AccountResponse<FavoriteMovie>>
|
||||
suspend fun getMovieWatchlist(@Path("account_id") accountId: String, @Query("page") page: Int = 1): Response<V4AccountResponse<FavoriteMovie>>
|
||||
|
||||
@GET("account/{account_id}/tv/watchlist")
|
||||
suspend fun getTvShowWatchlist(@Path("account_id") accountId: String, page: Int = 1): Response<V4AccountResponse<FavoriteTvSeries>>
|
||||
suspend fun getTvShowWatchlist(@Path("account_id") accountId: String, @Query("page") page: Int = 1): Response<V4AccountResponse<FavoriteTvSeries>>
|
||||
|
||||
@GET("account/{account_id}/movie/rated")
|
||||
suspend fun getRatedMovies(@Path("account_id") accountId: String, page: Int = 1): Response<V4AccountResponse<V4RatedMovie>>
|
||||
suspend fun getRatedMovies(@Path("account_id") accountId: String, @Query("page") page: Int = 1): Response<V4AccountResponse<V4RatedMovie>>
|
||||
|
||||
@GET("account/{account_id}/tv/rated")
|
||||
suspend fun getRatedTvShows(@Path("account_id") accountId: String, page: Int = 1): Response<V4AccountResponse<V4RatedTv>>
|
||||
suspend fun getRatedTvShows(@Path("account_id") accountId: String, @Query("page") page: Int = 1): Response<V4AccountResponse<V4RatedTv>>
|
||||
|
||||
}
|
||||
@@ -8,7 +8,7 @@ class ListV4Service {
|
||||
|
||||
private val service by lazy { TmdbClient().createV4ListService() }
|
||||
|
||||
suspend fun getLists(listId: Int, apiKey: String, page: Int = 1): Response<MediaList> {
|
||||
suspend fun getList(listId: Int, apiKey: String, page: Int = 1): Response<MediaList> {
|
||||
return service.getList(listId, apiKey, page)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,10 +6,12 @@ import com.google.gson.JsonDeserializer
|
||||
import com.owenlejeune.tvtime.BuildConfig
|
||||
import com.owenlejeune.tvtime.api.*
|
||||
import com.owenlejeune.tvtime.api.tmdb.TmdbClient
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.AccountService
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.deserializer.KnownForDeserializer
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.deserializer.SortableSearchResultDeserializer
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.KnownFor
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.SortableSearchResult
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v4.AccountV4Service
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v4.deserializer.ListItemDeserializer
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v4.model.ListItem
|
||||
import com.owenlejeune.tvtime.preferences.AppPreferences
|
||||
@@ -33,6 +35,9 @@ val networkModule = module {
|
||||
single { get<TmdbClient>().createSearchService() }
|
||||
single { get<TmdbClient>().createTvService() }
|
||||
|
||||
single { AccountService() }
|
||||
single { AccountV4Service() }
|
||||
|
||||
single<Map<Class<*>, JsonDeserializer<*>>> {
|
||||
mapOf(
|
||||
ListItem::class.java to ListItemDeserializer(),
|
||||
|
||||
@@ -4,6 +4,7 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.navigation.NavHostController
|
||||
import com.owenlejeune.tvtime.R
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.*
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v4.model.V4AccountList
|
||||
import com.owenlejeune.tvtime.ui.screens.main.MediaViewType
|
||||
import com.owenlejeune.tvtime.ui.screens.main.AccountTabContent
|
||||
import com.owenlejeune.tvtime.utils.ResourceUtils
|
||||
@@ -31,7 +32,10 @@ sealed class AccountTabNavItem(
|
||||
get() = listOf(RatedMovies, RatedTvShows, RatedTvEpisodes)
|
||||
|
||||
val AuthorizedItems
|
||||
get() = listOf(RatedMovies, RatedTvShows, RatedTvEpisodes, FavoriteMovies, FavoriteTvShows, MovieWatchlist, TvWatchlist).filter { it.ordinal > -1 }.sortedBy { it.ordinal }
|
||||
get() = listOf(
|
||||
RatedMovies, RatedTvShows, RatedTvEpisodes, FavoriteMovies, FavoriteTvShows,
|
||||
MovieWatchlist, TvWatchlist, UserLists
|
||||
).filter { it.ordinal > -1 }.sortedBy { it.ordinal }
|
||||
}
|
||||
|
||||
object RatedMovies: AccountTabNavItem(
|
||||
@@ -39,7 +43,8 @@ sealed class AccountTabNavItem(
|
||||
"rated_movies_route",
|
||||
R.string.no_rated_movies,
|
||||
MediaViewType.MOVIE,
|
||||
screenContent, { SessionManager.currentSession?.ratedMovies ?: emptyList() },
|
||||
screenContent,
|
||||
{ SessionManager.currentSession?.ratedMovies ?: emptyList() },
|
||||
RatedMovie::class,
|
||||
0
|
||||
)
|
||||
@@ -48,7 +53,8 @@ sealed class AccountTabNavItem(
|
||||
"rated_shows_route",
|
||||
R.string.no_rated_tv,
|
||||
MediaViewType.TV,
|
||||
screenContent, { SessionManager.currentSession?.ratedTvShows ?: emptyList() },
|
||||
screenContent,
|
||||
{ SessionManager.currentSession?.ratedTvShows ?: emptyList() },
|
||||
RatedTv::class,
|
||||
1
|
||||
)
|
||||
@@ -57,16 +63,18 @@ sealed class AccountTabNavItem(
|
||||
"rated_episodes_route",
|
||||
R.string.no_rated_episodes,
|
||||
MediaViewType.EPISODE,
|
||||
screenContent, { SessionManager.currentSession?.ratedTvEpisodes ?: emptyList() },
|
||||
screenContent,
|
||||
{ SessionManager.currentSession?.ratedTvEpisodes ?: emptyList() },
|
||||
RatedEpisode::class,
|
||||
2
|
||||
-1 //2
|
||||
)
|
||||
object FavoriteMovies: AccountTabNavItem(
|
||||
R.string.nav_favorite_movies_title,
|
||||
"favorite_movies_route",
|
||||
R.string.no_favorite_movies,
|
||||
MediaViewType.MOVIE,
|
||||
screenContent, { SessionManager.currentSession?.favoriteMovies ?: emptyList() },
|
||||
screenContent,
|
||||
{ SessionManager.currentSession?.favoriteMovies ?: emptyList() },
|
||||
FavoriteMovie::class,
|
||||
3
|
||||
)
|
||||
@@ -75,7 +83,8 @@ sealed class AccountTabNavItem(
|
||||
"favorite_shows_route",
|
||||
R.string.no_favorite_tv,
|
||||
MediaViewType.TV,
|
||||
screenContent, { SessionManager.currentSession?.favoriteTvShows ?: emptyList() },
|
||||
screenContent,
|
||||
{ SessionManager.currentSession?.favoriteTvShows ?: emptyList() },
|
||||
FavoriteTvSeries::class,
|
||||
4
|
||||
)
|
||||
@@ -84,7 +93,8 @@ sealed class AccountTabNavItem(
|
||||
"movie_watchlist_route",
|
||||
R.string.no_watchlist_movies,
|
||||
MediaViewType.MOVIE,
|
||||
screenContent, { SessionManager.currentSession?.movieWatchlist ?: emptyList() },
|
||||
screenContent,
|
||||
{ SessionManager.currentSession?.movieWatchlist ?: emptyList() },
|
||||
WatchlistMovie::class,
|
||||
5
|
||||
)
|
||||
@@ -93,10 +103,22 @@ sealed class AccountTabNavItem(
|
||||
"tv_watchlist_route",
|
||||
R.string.no_watchlist_tv,
|
||||
MediaViewType.TV,
|
||||
screenContent, { SessionManager.currentSession?.tvWatchlist ?: emptyList() },
|
||||
screenContent,
|
||||
{ SessionManager.currentSession?.tvWatchlist ?: emptyList() },
|
||||
WatchlistTvSeries::class,
|
||||
6
|
||||
)
|
||||
|
||||
object UserLists: AccountTabNavItem(
|
||||
R.string.nav_user_lists_title,
|
||||
"user_lists_route",
|
||||
R.string.no_lists,
|
||||
MediaViewType.LIST,
|
||||
screenContent,
|
||||
{ SessionManager.currentSession?.accountLists ?: emptyList() },
|
||||
V4AccountList::class,
|
||||
0//7
|
||||
)
|
||||
}
|
||||
|
||||
private val screenContent: AccountNavComposableFun = { noContentText, appNavController, mediaViewType, listFetchFun, clazz ->
|
||||
|
||||
@@ -37,6 +37,8 @@ import com.google.accompanist.pager.PagerState
|
||||
import com.google.accompanist.pager.rememberPagerState
|
||||
import com.owenlejeune.tvtime.R
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.*
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v4.model.V4AccountList
|
||||
import com.owenlejeune.tvtime.extensions.unlessEmpty
|
||||
import com.owenlejeune.tvtime.preferences.AppPreferences
|
||||
import com.owenlejeune.tvtime.ui.components.RoundedLetterImage
|
||||
import com.owenlejeune.tvtime.ui.components.SignInDialog
|
||||
@@ -238,6 +240,19 @@ fun <T: Any> AccountTabContent(
|
||||
description = item.overview
|
||||
)
|
||||
}
|
||||
V4AccountList::class -> {
|
||||
val item = contentItems[i] as V4AccountList
|
||||
MediaItemRow(
|
||||
appNavController = appNavController,
|
||||
mediaViewType = mediaViewType,
|
||||
id = item.id,
|
||||
name = item.name,
|
||||
date = item.createdAt,
|
||||
description = item.description.unlessEmpty(stringResource(R.string.no_description_provided)),
|
||||
posterPath = TmdbUtils.getFullPosterPath(item.posterPath),
|
||||
backdropPath = TmdbUtils.getFullBackdropPath(item.backdropPath)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import com.owenlejeune.tvtime.api.tmdb.api.v3.DetailService
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.MoviesService
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.TvService
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.*
|
||||
import com.owenlejeune.tvtime.extensions.WindowSizeClass
|
||||
import com.owenlejeune.tvtime.extensions.listItems
|
||||
import com.owenlejeune.tvtime.preferences.AppPreferences
|
||||
import com.owenlejeune.tvtime.ui.components.*
|
||||
@@ -57,6 +58,7 @@ fun MediaDetailView(
|
||||
appNavController: NavController,
|
||||
itemId: Int?,
|
||||
type: MediaViewType,
|
||||
windowSize: WindowSizeClass,
|
||||
preferences: AppPreferences = KoinJavaComponent.get(AppPreferences::class.java)
|
||||
) {
|
||||
val service = when (type) {
|
||||
@@ -104,51 +106,76 @@ fun MediaDetailView(
|
||||
}
|
||||
) { innerPadding ->
|
||||
Box(modifier = Modifier.padding(innerPadding)) {
|
||||
Column(
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.background(color = MaterialTheme.colorScheme.background)
|
||||
.verticalScroll(state = rememberScrollState())
|
||||
.padding(bottom = 16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
val images = remember { mutableStateOf<ImageCollection?>(null) }
|
||||
itemId?.let {
|
||||
if (preferences.showBackdropGallery && images.value == null) {
|
||||
fetchImages(itemId, service, images)
|
||||
}
|
||||
}
|
||||
|
||||
DetailHeader(
|
||||
posterUrl = TmdbUtils.getFullPosterPath(mediaItem.value?.posterPath),
|
||||
posterContentDescription = mediaItem.value?.title,
|
||||
backdropUrl = TmdbUtils.getFullBackdropPath(mediaItem.value?.backdropPath),
|
||||
rating = mediaItem.value?.voteAverage?.let { it / 10 },
|
||||
imageCollection = images.value
|
||||
)
|
||||
|
||||
Column(
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
modifier = Modifier
|
||||
.background(color = MaterialTheme.colorScheme.background)
|
||||
.weight(1f)
|
||||
.verticalScroll(state = rememberScrollState()),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
if (type == MediaViewType.MOVIE) {
|
||||
MiscMovieDetails(mediaItem = mediaItem, service as MoviesService)
|
||||
} else {
|
||||
MiscTvDetails(mediaItem = mediaItem, service as TvService)
|
||||
val images = remember { mutableStateOf<ImageCollection?>(null) }
|
||||
itemId?.let {
|
||||
if (preferences.showBackdropGallery && images.value == null) {
|
||||
fetchImages(itemId, service, images)
|
||||
}
|
||||
}
|
||||
|
||||
ActionsView(itemId = itemId, type = type, service = service)
|
||||
DetailHeader(
|
||||
posterUrl = TmdbUtils.getFullPosterPath(mediaItem.value?.posterPath),
|
||||
posterContentDescription = mediaItem.value?.title,
|
||||
backdropUrl = TmdbUtils.getFullBackdropPath(mediaItem.value?.backdropPath),
|
||||
rating = mediaItem.value?.voteAverage?.let { it / 10 },
|
||||
imageCollection = images.value
|
||||
)
|
||||
|
||||
OverviewCard(itemId = itemId, mediaItem = mediaItem, service = service)
|
||||
Column(
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
if (type == MediaViewType.MOVIE) {
|
||||
MiscMovieDetails(mediaItem = mediaItem, service as MoviesService)
|
||||
} else {
|
||||
MiscTvDetails(mediaItem = mediaItem, service as TvService)
|
||||
}
|
||||
|
||||
CastCard(itemId = itemId, service = service, appNavController = appNavController)
|
||||
ActionsView(itemId = itemId, type = type, service = service)
|
||||
|
||||
SimilarContentCard(itemId = itemId, service = service, mediaType = type, appNavController = appNavController)
|
||||
OverviewCard(itemId = itemId, mediaItem = mediaItem, service = service)
|
||||
|
||||
VideosCard(itemId = itemId, service = service)
|
||||
CastCard(itemId = itemId, service = service, appNavController = appNavController)
|
||||
|
||||
AdditionalDetailsCard(itemId = itemId, mediaItem = mediaItem, service = service, type = type)
|
||||
SimilarContentCard(itemId = itemId, service = service, mediaType = type, appNavController = appNavController)
|
||||
|
||||
ReviewsCard(itemId = itemId, service = service)
|
||||
VideosCard(itemId = itemId, service = service)
|
||||
|
||||
AdditionalDetailsCard(itemId = itemId, mediaItem = mediaItem, service = service, type = type)
|
||||
|
||||
if (windowSize != WindowSizeClass.Expanded) {
|
||||
ReviewsCard(itemId = itemId, service = service)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
|
||||
if (windowSize == WindowSizeClass.Expanded) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.background(color = MaterialTheme.colorScheme.background)
|
||||
.weight(1f)
|
||||
.padding(bottom = 16.dp)
|
||||
.verticalScroll(state = rememberScrollState())
|
||||
) {
|
||||
ReviewsCard(itemId = itemId, service = service)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1025,7 +1052,7 @@ private fun ReviewsCard(
|
||||
) {
|
||||
val reviews = reviewsResponse.value?.results ?: emptyList()
|
||||
if (reviews.isNotEmpty()) {
|
||||
reviews.reversed().forEach { review ->
|
||||
reviews.reversed().forEachIndexed { index, review ->
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@@ -1088,10 +1115,12 @@ private fun ReviewsCard(
|
||||
)
|
||||
}
|
||||
}
|
||||
Divider(
|
||||
color = MaterialTheme.colorScheme.secondary,
|
||||
modifier = Modifier.padding(vertical = 12.dp)
|
||||
)
|
||||
if (index != reviews.size - 1) {
|
||||
Divider(
|
||||
color = MaterialTheme.colorScheme.secondary,
|
||||
modifier = Modifier.padding(vertical = 12.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Text(
|
||||
|
||||
@@ -10,7 +10,8 @@ enum class MediaViewType {
|
||||
@SerializedName("person")
|
||||
PERSON,
|
||||
EPISODE,
|
||||
MIXED;
|
||||
MIXED,
|
||||
LIST;
|
||||
|
||||
companion object {
|
||||
const val JSON_KEY = "media_type"
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.owenlejeune.tvtime.ui.screens.main
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.*
|
||||
@@ -11,6 +12,7 @@ import androidx.compose.ui.draw.blur
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -19,6 +21,7 @@ import androidx.constraintlayout.compose.ConstraintLayout
|
||||
import androidx.constraintlayout.compose.Dimension
|
||||
import androidx.navigation.NavController
|
||||
import coil.compose.AsyncImage
|
||||
import com.owenlejeune.tvtime.R
|
||||
import com.owenlejeune.tvtime.ui.navigation.MainNavItem
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@@ -63,7 +66,7 @@ fun MediaResultCard(
|
||||
|
||||
Box(modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(Color.Black.copy(alpha = 0.7f))
|
||||
.background(Color.Black.copy(alpha = 0.4f))
|
||||
.blur(radius = 10.dp)
|
||||
)
|
||||
}
|
||||
@@ -83,8 +86,9 @@ fun MediaResultCard(
|
||||
bottom.linkTo(parent.bottom)
|
||||
height = Dimension.fillToConstraints
|
||||
}
|
||||
.aspectRatio(0.7f)
|
||||
.clip(RoundedCornerShape(10.dp)),
|
||||
model = posterPath,
|
||||
model = posterPath ?: R.drawable.placeholder,
|
||||
contentDescription = title
|
||||
)
|
||||
|
||||
@@ -101,9 +105,10 @@ fun MediaResultCard(
|
||||
height = Dimension.matchParent
|
||||
}
|
||||
) {
|
||||
val textColor = backdropPath?.let { Color.White } ?: if (isSystemInDarkTheme()) Color.White else Color.Black
|
||||
Text(
|
||||
text = title,
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
color = textColor,
|
||||
fontSize = 18.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
@@ -111,7 +116,7 @@ fun MediaResultCard(
|
||||
additionalDetails.forEach {
|
||||
Text(
|
||||
text = it,
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
color = textColor,
|
||||
fontSize = 14.sp,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.owenlejeune.tvtime.utils
|
||||
|
||||
import android.accounts.Account
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
@@ -10,11 +11,15 @@ import com.owenlejeune.tvtime.api.tmdb.api.v3.AccountService
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.AuthenticationService
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.GuestSessionService
|
||||
import com.owenlejeune.tvtime.api.tmdb.TmdbClient
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.AccountApi
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.*
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v4.AccountV4Api
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v4.AccountV4Service
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v4.AuthenticationV4Service
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v4.model.AuthAccessBody
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v4.model.AuthDeleteBody
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v4.model.AuthRequestBody
|
||||
import com.owenlejeune.tvtime.api.tmdb.api.v4.model.V4AccountList
|
||||
import com.owenlejeune.tvtime.preferences.AppPreferences
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -90,8 +95,8 @@ object SessionManager: KoinComponent {
|
||||
accessToken = values.accessToken,
|
||||
accountId = values.accountId
|
||||
)
|
||||
session.initialize()
|
||||
_currentSession = session
|
||||
session.initialize()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -207,8 +212,8 @@ object SessionManager: KoinComponent {
|
||||
val accountDetails: AccountDetails?
|
||||
get() = _accountDetails
|
||||
|
||||
protected open var _accountLists: List<AccountList> = emptyList()
|
||||
val accountLists: List<AccountList>
|
||||
protected open var _accountLists: List<V4AccountList> = emptyList()
|
||||
val accountLists: List<V4AccountList>
|
||||
get() = _accountLists
|
||||
|
||||
protected open var _favoriteMovies: List<FavoriteMovie> = emptyList()
|
||||
@@ -302,7 +307,8 @@ object SessionManager: KoinComponent {
|
||||
accessToken: String = "",
|
||||
accountId: String = ""
|
||||
): Session(sessionId, true, accessToken, accountId) {
|
||||
private val service by lazy { AccountService() }
|
||||
private val service: AccountService by inject()
|
||||
private val serviceV4: AccountV4Service by inject()
|
||||
|
||||
override suspend fun initialize() {
|
||||
refresh()
|
||||
@@ -325,7 +331,7 @@ object SessionManager: KoinComponent {
|
||||
|
||||
private suspend fun refreshWithAccountId(accountId: Int, changed: Array<Changed> = Changed.All) {
|
||||
if (changed.contains(Changed.Lists)) {
|
||||
service.getLists(accountId).apply {
|
||||
serviceV4.getLists(preferences.authorizedSessionValues?.accountId ?: "").apply {
|
||||
if (isSuccessful) {
|
||||
withContext(Dispatchers.Main) {
|
||||
_accountLists = body()?.results ?: _accountLists
|
||||
|
||||
@@ -15,7 +15,9 @@ object TmdbUtils {
|
||||
private const val DEF_REGION = "US"
|
||||
|
||||
fun getFullPosterPath(posterPath: String?): String? {
|
||||
return posterPath?.let { "${POSTER_BASE}${posterPath}" }
|
||||
return posterPath?.let {
|
||||
if (posterPath.isEmpty()) null else "${POSTER_BASE}${posterPath}"
|
||||
}
|
||||
}
|
||||
|
||||
fun getFullPosterPath(tmdbItem: TmdbItem?): String? {
|
||||
@@ -27,7 +29,9 @@ object TmdbUtils {
|
||||
}
|
||||
|
||||
fun getFullBackdropPath(backdropPath: String?): String? {
|
||||
return backdropPath?.let { "${BACKDROP_BASE}${backdropPath}" }
|
||||
return backdropPath?.let {
|
||||
if (backdropPath.isEmpty()) null else "${BACKDROP_BASE}${backdropPath}"
|
||||
}
|
||||
}
|
||||
|
||||
fun getFullBackdropPath(detailItem: DetailedItem?): String? {
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
<string name="nav_favorite_tv_show_title">Favorite TV Shows</string>
|
||||
<string name="nav_movie_watchlist_title">Movie Watchlist</string>
|
||||
<string name="nav_tv_watchlist_title">TV Watchlist</string>
|
||||
<string name="nav_user_lists_title">Lists</string>
|
||||
|
||||
<!-- Headings -->
|
||||
<string name="cast_label">Cast</string>
|
||||
@@ -180,4 +181,6 @@
|
||||
<string name="no_favorite_tv">No Favorite TV</string>
|
||||
<string name="no_watchlist_movies">No Watchlisted Movies</string>
|
||||
<string name="no_watchlist_tv">No Watchlisted TV</string>
|
||||
<string name="no_lists">No Lists</string>
|
||||
<string name="no_description_provided">No description provided</string>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user