mirror of
https://github.com/owenlejeune/TVTime.git
synced 2025-11-08 12:42:44 -05:00
add in infrastructure for authorized session account tab lists
This commit is contained in:
@@ -695,7 +695,7 @@ fun RoundedLetterImage(
|
||||
topPadding: Dp = size / 5
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
modifier = modifier
|
||||
.clip(CircleShape)
|
||||
.size(size)
|
||||
.background(color = MaterialTheme.colorScheme.tertiary)
|
||||
|
||||
@@ -3,31 +3,38 @@ package com.owenlejeune.tvtime.ui.navigation
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.navigation.NavHostController
|
||||
import com.owenlejeune.tvtime.R
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.RatedMedia
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.*
|
||||
import com.owenlejeune.tvtime.ui.screens.MediaViewType
|
||||
import com.owenlejeune.tvtime.ui.screens.tabs.bottom.AccountTabContent
|
||||
import com.owenlejeune.tvtime.utils.ResourceUtils
|
||||
import com.owenlejeune.tvtime.utils.SessionManager
|
||||
import org.koin.core.component.inject
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
sealed class AccountTabNavItem(stringRes: Int, route: String, val mediaType: MediaViewType, val screen: AccountNavComposableFun, val listFetchFun: ListFetchFun): TabNavItem(route) {
|
||||
sealed class AccountTabNavItem(stringRes: Int, route: String, val mediaType: MediaViewType, val screen: AccountNavComposableFun, val listFetchFun: ListFetchFun, val listType: KClass<*>): TabNavItem(route) {
|
||||
private val resourceUtils: ResourceUtils by inject()
|
||||
|
||||
override val name = resourceUtils.getString(stringRes)
|
||||
|
||||
companion object {
|
||||
val GuestItems = listOf(RatedMovies, RatedTvShows, RatedTvEpisodes)
|
||||
val AuthorizedItems = listOf(RatedMovies, RatedTvShows, RatedTvEpisodes, FavoriteMovies, FavoriteTvShows, MovieWatchlist, TvWatchlist)
|
||||
}
|
||||
|
||||
object RatedMovies: AccountTabNavItem(R.string.nav_rated_movies_title, "rated_movies_route", MediaViewType.MOVIE, screenContent, { SessionManager.currentSession?.ratedMovies ?: emptyList() } )
|
||||
object RatedTvShows: AccountTabNavItem(R.string.nav_rated_shows_title, "rated_shows_route", MediaViewType.TV, screenContent, { SessionManager.currentSession?.ratedTvShows ?: emptyList() } )
|
||||
object RatedTvEpisodes: AccountTabNavItem(R.string.nav_rated_episodes_title, "rated_episodes_route", MediaViewType.EPISODE, screenContent, { SessionManager.currentSession?.ratedTvEpisodes ?: emptyList() } )
|
||||
object RatedMovies: AccountTabNavItem(R.string.nav_rated_movies_title, "rated_movies_route", MediaViewType.MOVIE, screenContent, { SessionManager.currentSession?.ratedMovies ?: emptyList() }, RatedMovie::class)
|
||||
object RatedTvShows: AccountTabNavItem(R.string.nav_rated_shows_title, "rated_shows_route", MediaViewType.TV, screenContent, { SessionManager.currentSession?.ratedTvShows ?: emptyList() }, RatedTv::class)
|
||||
object RatedTvEpisodes: AccountTabNavItem(R.string.nav_rated_episodes_title, "rated_episodes_route", MediaViewType.EPISODE, screenContent, { SessionManager.currentSession?.ratedTvEpisodes ?: emptyList() }, RatedEpisode::class)
|
||||
// object Lists
|
||||
object FavoriteMovies: AccountTabNavItem(R.string.nav_favorite_movies_title, "favorite_movies_route", MediaViewType.MOVIE, screenContent, { SessionManager.currentSession?.favoriteMovies ?: emptyList() }, FavoriteMovie::class)
|
||||
object FavoriteTvShows: AccountTabNavItem(R.string.nav_favorite_tv_show_title, "favorite_shows_route", MediaViewType.TV, screenContent, { SessionManager.currentSession?.favoriteMovies ?: emptyList() }, FavoriteTvSeries::class)
|
||||
object MovieWatchlist: AccountTabNavItem(R.string.nav_movie_watchlist_title, "movie_watchlist_route", MediaViewType.MOVIE, screenContent, { SessionManager.currentSession?.movieWatchlist ?: emptyList() }, WatchlistMovie::class)
|
||||
object TvWatchlist: AccountTabNavItem(R.string.nav_tv_watchlist_title, "tv_watchlist_route", MediaViewType.TV, screenContent, { SessionManager.currentSession?.tvWatchlist ?: emptyList() }, WatchlistTvSeries::class)
|
||||
}
|
||||
|
||||
private val screenContent: AccountNavComposableFun = { appNavController, mediaViewType, listFetchFun ->
|
||||
AccountTabContent(appNavController = appNavController, mediaViewType = mediaViewType, listFetchFun = listFetchFun)
|
||||
private val screenContent: AccountNavComposableFun = { appNavController, mediaViewType, listFetchFun, clazz ->
|
||||
AccountTabContent(appNavController = appNavController, mediaViewType = mediaViewType, listFetchFun = listFetchFun, clazz = clazz)
|
||||
}
|
||||
|
||||
typealias ListFetchFun = () -> List<RatedMedia>
|
||||
typealias ListFetchFun = () -> List<Any>
|
||||
|
||||
typealias AccountNavComposableFun = @Composable (NavHostController, MediaViewType, ListFetchFun) -> Unit
|
||||
typealias AccountNavComposableFun = @Composable (NavHostController, MediaViewType, ListFetchFun, KClass<*>) -> Unit
|
||||
@@ -25,21 +25,20 @@ import com.google.accompanist.pager.HorizontalPager
|
||||
import com.google.accompanist.pager.PagerState
|
||||
import com.google.accompanist.pager.rememberPagerState
|
||||
import com.owenlejeune.tvtime.R
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.RatedMovie
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.RatedTopLevelMedia
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.RatedTv
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.*
|
||||
import com.owenlejeune.tvtime.ui.components.*
|
||||
import com.owenlejeune.tvtime.ui.navigation.AccountTabNavItem
|
||||
import com.owenlejeune.tvtime.ui.navigation.ListFetchFun
|
||||
import com.owenlejeune.tvtime.ui.navigation.MainNavItem
|
||||
import com.owenlejeune.tvtime.ui.screens.MediaViewType
|
||||
import com.owenlejeune.tvtime.ui.screens.tabs.top.Tabs
|
||||
import com.owenlejeune.tvtime.ui.screens.tabs.top.ScrollableTabs
|
||||
import com.owenlejeune.tvtime.utils.SessionManager
|
||||
import com.owenlejeune.tvtime.utils.TmdbUtils
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
private const val GUEST_SIGN_IN = "guest_sign_in"
|
||||
private const val SIGN_OUT = "sign_out"
|
||||
@@ -69,14 +68,14 @@ fun AccountTab(
|
||||
if (lastSelectedOption.value.isNotBlank() || lastSelectedOption.value.isBlank()) {
|
||||
SessionManager.currentSession?.let { session ->
|
||||
val tabs = if (session.isAuthorized) {
|
||||
AccountTabNavItem.GuestItems
|
||||
AccountTabNavItem.AuthorizedItems
|
||||
} else {
|
||||
AccountTabNavItem.GuestItems
|
||||
}
|
||||
|
||||
Column {
|
||||
val pagerState = rememberPagerState()
|
||||
Tabs(tabs = tabs, pagerState = pagerState)
|
||||
ScrollableTabs(tabs = tabs, pagerState = pagerState)
|
||||
AccountTabs(
|
||||
appNavController = appNavController,
|
||||
tabs = tabs,
|
||||
@@ -88,10 +87,11 @@ fun AccountTab(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AccountTabContent(
|
||||
fun <T: Any> AccountTabContent(
|
||||
appNavController: NavHostController,
|
||||
mediaViewType: MediaViewType,
|
||||
listFetchFun: ListFetchFun
|
||||
listFetchFun: ListFetchFun,
|
||||
clazz: KClass<T>
|
||||
) {
|
||||
val contentItems = listFetchFun()
|
||||
|
||||
@@ -112,51 +112,85 @@ fun AccountTabContent(
|
||||
}
|
||||
} else {
|
||||
items(contentItems.size) { i ->
|
||||
val ratedItem = contentItems[i] as RatedTopLevelMedia
|
||||
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
modifier = Modifier.clickable(
|
||||
onClick = {
|
||||
appNavController.navigate(
|
||||
"${MainNavItem.DetailView.route}/${mediaViewType}/${ratedItem.id}"
|
||||
)
|
||||
}
|
||||
)
|
||||
) {
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.width(60.dp)
|
||||
.height(80.dp),
|
||||
painter = rememberImagePainter(
|
||||
data = TmdbUtils.getFullPosterPath(ratedItem.posterPath)
|
||||
),
|
||||
contentDescription = ""
|
||||
)
|
||||
|
||||
Column(
|
||||
modifier = Modifier.height(80.dp),
|
||||
verticalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Text(
|
||||
text = ratedItem.name,
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
fontSize = 18.sp
|
||||
when (clazz) {
|
||||
RatedMovie::class -> {
|
||||
val item = contentItems[i] as RatedMovie
|
||||
MediaItemRow(
|
||||
appNavController = appNavController,
|
||||
mediaViewType = mediaViewType,
|
||||
id = item.id,
|
||||
posterPath = TmdbUtils.getFullPosterPath(item.posterPath),
|
||||
name = item.name,
|
||||
date = item.releaseDate,
|
||||
rating = item.rating
|
||||
)
|
||||
|
||||
val date = when (ratedItem) {
|
||||
is RatedMovie -> ratedItem.releaseDate
|
||||
is RatedTv -> ratedItem.firstAirDate
|
||||
else -> ""
|
||||
}
|
||||
Text(
|
||||
text = date,
|
||||
color = MaterialTheme.colorScheme.onBackground
|
||||
}
|
||||
RatedTv::class -> {
|
||||
val item = contentItems[i] as RatedTv
|
||||
MediaItemRow(
|
||||
appNavController = appNavController,
|
||||
mediaViewType = mediaViewType,
|
||||
id = item.id,
|
||||
posterPath = TmdbUtils.getFullPosterPath(item.posterPath),
|
||||
name = item.name,
|
||||
date = item.firstAirDate,
|
||||
rating = item.rating
|
||||
)
|
||||
|
||||
Text(
|
||||
text = stringResource(id = R.string.rating_test, (ratedItem.rating * 10).toInt()),
|
||||
color = MaterialTheme.colorScheme.onBackground
|
||||
}
|
||||
RatedEpisode::class -> {
|
||||
val item = contentItems[i] as RatedEpisode
|
||||
MediaItemRow(
|
||||
appNavController = appNavController,
|
||||
mediaViewType = mediaViewType,
|
||||
id = item.id,
|
||||
posterPath = null,
|
||||
name = item.name,
|
||||
date = item.airDate,
|
||||
rating = item.rating
|
||||
)
|
||||
}
|
||||
FavoriteMovie::class -> {
|
||||
val item = contentItems[i] as FavoriteMovie
|
||||
MediaItemRow(
|
||||
appNavController = appNavController,
|
||||
mediaViewType = mediaViewType,
|
||||
id = item.id,
|
||||
posterPath = TmdbUtils.getFullPosterPath(item.posterPath),
|
||||
name = item.title,
|
||||
date = item.releaseDate
|
||||
)
|
||||
}
|
||||
FavoriteTvSeries::class -> {
|
||||
val item = contentItems[i] as FavoriteTvSeries
|
||||
MediaItemRow(
|
||||
appNavController = appNavController,
|
||||
mediaViewType = mediaViewType,
|
||||
id = item.id,
|
||||
posterPath = TmdbUtils.getFullPosterPath(item.posterPath),
|
||||
name = item.title,
|
||||
date = item.releaseDate
|
||||
)
|
||||
}
|
||||
WatchlistMovie::class -> {
|
||||
val item = contentItems[i] as WatchlistMovie
|
||||
MediaItemRow(
|
||||
appNavController = appNavController,
|
||||
mediaViewType = mediaViewType,
|
||||
id = item.id,
|
||||
posterPath = TmdbUtils.getFullPosterPath(item.posterPath),
|
||||
name = item.title,
|
||||
date = item.releaseDate
|
||||
)
|
||||
}
|
||||
WatchlistTvSeries::class -> {
|
||||
val item = contentItems[i] as WatchlistTvSeries
|
||||
MediaItemRow(
|
||||
appNavController = appNavController,
|
||||
mediaViewType = mediaViewType,
|
||||
id = item.id,
|
||||
posterPath = TmdbUtils.getFullPosterPath(item.posterPath),
|
||||
name = item.title,
|
||||
date = item.releaseDate
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -165,6 +199,61 @@ fun AccountTabContent(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MediaItemRow(
|
||||
appNavController: NavHostController,
|
||||
mediaViewType: MediaViewType,
|
||||
id: Int,
|
||||
posterPath: String?,
|
||||
name: String,
|
||||
date: String,
|
||||
rating: Float? = null
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
modifier = Modifier.clickable(
|
||||
onClick = {
|
||||
appNavController.navigate(
|
||||
"${MainNavItem.DetailView.route}/${mediaViewType}/${id}"
|
||||
)
|
||||
}
|
||||
)
|
||||
) {
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.width(60.dp)
|
||||
.height(80.dp),
|
||||
painter = rememberImagePainter(
|
||||
data = posterPath
|
||||
),
|
||||
contentDescription = ""
|
||||
)
|
||||
|
||||
Column(
|
||||
modifier = Modifier.height(80.dp),
|
||||
verticalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Text(
|
||||
text = name,
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
fontSize = 18.sp
|
||||
)
|
||||
|
||||
Text(
|
||||
text = date,
|
||||
color = MaterialTheme.colorScheme.onBackground
|
||||
)
|
||||
|
||||
if (rating != null) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.rating_test, (rating * 10).toInt()),
|
||||
color = MaterialTheme.colorScheme.onBackground
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AccountDropdownMenu(
|
||||
session: SessionManager.Session?,
|
||||
@@ -266,7 +355,7 @@ private fun GuestSessionMenuItems(
|
||||
@Composable
|
||||
private fun GuestSessionIcon() {
|
||||
val guestName = stringResource(id = R.string.account_name_guest)
|
||||
RoundedLetterImage(size = 40.dp, character = guestName[0], modifier = Modifier.padding(end = 8.dp), topPadding = 40.dp / 8)
|
||||
RoundedLetterImage(size = 40.dp, character = guestName[0], topPadding = 40.dp / 8)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -311,6 +400,6 @@ fun AccountTabs(
|
||||
appNavController: NavHostController
|
||||
) {
|
||||
HorizontalPager(count = tabs.size, state = pagerState) { page ->
|
||||
tabs[page].screen(appNavController, tabs[page].mediaType, tabs[page].listFetchFun)
|
||||
tabs[page].screen(appNavController, tabs[page].mediaType, tabs[page].listFetchFun, tabs[page].listType)
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,10 @@
|
||||
<string name="nav_rated_episodes_title">Rated TV Episodes</string>
|
||||
<string name="nav_people_title">People</string>
|
||||
<string name="nav_popular_people_title">Popular People</string>
|
||||
<string name="nav_favorite_movies_title">Favorite Movies</string>
|
||||
<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>
|
||||
|
||||
<!-- Headings -->
|
||||
<string name="cast_label">Cast</string>
|
||||
@@ -84,7 +88,7 @@
|
||||
<string name="account_not_logged_in">Not logged in</string>
|
||||
|
||||
<string name="no_rated_content_message">No rated content</string>
|
||||
<string name="rating_test">Rating: $1%d</string>
|
||||
<string name="rating_test">Rating: %1$d</string>
|
||||
<string name="action_sign_in_as_guest">Sign In as Guest</string>
|
||||
<string name="account_menu_content_description">Account Menu</string>
|
||||
<string name="action_sign_out">Sign Out</string>
|
||||
|
||||
Reference in New Issue
Block a user