add crew to movie/tv details

This commit is contained in:
Owen LeJeune
2023-07-08 23:02:19 -04:00
parent 1ff35387c8
commit 32bf5c3494
3 changed files with 197 additions and 15 deletions

View File

@@ -20,6 +20,7 @@ import com.owenlejeune.tvtime.extensions.safeGetSerializable
import com.owenlejeune.tvtime.preferences.AppPreferences
import com.owenlejeune.tvtime.ui.screens.AboutScreen
import com.owenlejeune.tvtime.ui.screens.AccountScreen
import com.owenlejeune.tvtime.ui.screens.CastCrewListScreen
import com.owenlejeune.tvtime.ui.screens.GalleryView
import com.owenlejeune.tvtime.ui.screens.HomeScreen
import com.owenlejeune.tvtime.ui.screens.KeywordResultsScreen
@@ -211,6 +212,18 @@ fun AppNavigationHost(
SeasonListScreen(id = id, appNavController = appNavController)
}
composable(
route = AppNavItem.CaseCrewListView.route.plus("/{${NavConstants.TYPE_KEY}}/{${NavConstants.ID_KEY}}"),
arguments = listOf(
navArgument(NavConstants.TYPE_KEY) { type = NavType.EnumType(MediaViewType::class.java) },
navArgument(NavConstants.ID_KEY) { type = NavType.IntType }
)
) { navBackStackEntry ->
val type = navBackStackEntry.arguments?.safeGetSerializable(NavConstants.TYPE_KEY, MediaViewType::class.java)!!
val id = navBackStackEntry.arguments?.getInt(NavConstants.ID_KEY)!!
CastCrewListScreen(appNavController = appNavController, type = type, id = id)
}
}
}
@@ -247,5 +260,8 @@ sealed class AppNavItem(val route: String) {
object SeasonListView: AppNavItem("season_list_route") {
fun withArgs(id: Int) = route.plus("/$id")
}
object CaseCrewListView: AppNavItem("cast_crew_list_route") {
fun withArgs(type: MediaViewType, id: Int) = route.plus("/$type/$id")
}
}

View File

@@ -0,0 +1,153 @@
package com.owenlejeune.tvtime.ui.screens
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.owenlejeune.tvtime.R
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.CrewMember
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.DetailCrew
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.MovieCast
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.MovieCastMember
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.TvCast
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.TvCastMember
import com.owenlejeune.tvtime.extensions.getCalendarYear
import com.owenlejeune.tvtime.ui.components.MediaResultCard
import com.owenlejeune.tvtime.ui.components.SelectableTextChip
import com.owenlejeune.tvtime.ui.viewmodel.MainViewModel
import com.owenlejeune.tvtime.utils.TmdbUtils
import com.owenlejeune.tvtime.utils.types.MediaViewType
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CastCrewListScreen(
appNavController: NavController,
type: MediaViewType,
id: Int
) {
val mainViewModel = viewModel<MainViewModel>()
val systemUiController = rememberSystemUiController()
systemUiController.setStatusBarColor(color = MaterialTheme.colorScheme.background)
systemUiController.setNavigationBarColor(color = MaterialTheme.colorScheme.background)
val topAppBarScrollState = rememberTopAppBarState()
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(topAppBarScrollState)
val details = mainViewModel.produceDetailsFor(type)[id]
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
TopAppBar(
scrollBehavior = scrollBehavior,
colors = TopAppBarDefaults
.topAppBarColors(
scrolledContainerColor = MaterialTheme.colorScheme.background,
titleContentColor = MaterialTheme.colorScheme.primary
),
title = { Text(text = details?.title ?: "") },
navigationIcon = {
IconButton(onClick = { appNavController.popBackStack() }) {
Icon(
imageVector = Icons.Filled.ArrowBack,
contentDescription = stringResource(id = R.string.content_description_back_button),
tint = MaterialTheme.colorScheme.primary
)
}
}
)
}
) { innerPadding ->
Box(modifier = Modifier.padding(innerPadding)) {
val castMap = remember { mainViewModel.produceCastFor(type) }
val crewMap = remember { mainViewModel.produceCrewFor(type) }
val cast = castMap[id]
val crew = crewMap[id]
var castSelected by remember { mutableStateOf(true) }
val items = if (castSelected) cast else crew
LazyColumn(
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
item {
Row(
modifier = Modifier.padding(start = 16.dp, top = 12.dp, bottom = 12.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
SelectableTextChip(
selected = castSelected,
onSelected = { castSelected = true },
text = stringResource(id = R.string.actor_label),
selectedColor = MaterialTheme.colorScheme.tertiary,
unselectedColor = MaterialTheme.colorScheme.background
)
SelectableTextChip(
selected = !castSelected,
onSelected = { castSelected = false },
text = stringResource(id = R.string.production_label),
selectedColor = MaterialTheme.colorScheme.tertiary,
unselectedColor = MaterialTheme.colorScheme.background
)
}
}
items(items!!) { item ->
val additionalDetails = emptyList<String>().toMutableList()
when (item) {
is MovieCastMember -> additionalDetails.add(stringResource(id = R.string.cast_character_template, item.character))
is TvCastMember -> {
item.roles.forEach { role ->
additionalDetails.add(stringResource(id = R.string.cast_tv_character_template, role.role, role.episodeCount))
}
}
is CrewMember -> additionalDetails.add(stringResource(id = R.string.crew_template, item.department))
}
MediaResultCard(
appNavController = appNavController,
mediaViewType = type,
id = item.id,
backdropPath = null,
posterPath = TmdbUtils.getFullPosterPath(item.profilePath),
title = item.name,
additionalDetails = additionalDetails,
modifier = Modifier.padding(horizontal = 12.dp)
)
}
}
}
}
}

View File

@@ -602,23 +602,36 @@ private fun CastCard(
backgroundColor = MaterialTheme.colorScheme.primary,
textColor = MaterialTheme.colorScheme.background
) {
LazyRow(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 16.dp),
horizontalArrangement = Arrangement.spacedBy(4.dp)
) {
item {
Spacer(modifier = Modifier.width(8.dp))
}
items(cast?.size ?: 0) { i ->
cast?.get(i)?.let {
CastCrewCard(appNavController = appNavController, person = it)
Column {
LazyRow(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 16.dp),
horizontalArrangement = Arrangement.spacedBy(4.dp)
) {
item {
Spacer(modifier = Modifier.width(8.dp))
}
items(cast?.size ?: 0) { i ->
cast?.get(i)?.let {
CastCrewCard(appNavController = appNavController, person = it)
}
}
item {
Spacer(modifier = Modifier.width(8.dp))
}
}
item {
Spacer(modifier = Modifier.width(8.dp))
}
Text(
text = "See all cast and crew",
fontSize = 12.sp,
color = MaterialTheme.colorScheme.inversePrimary,
modifier = Modifier
.padding(start = 12.dp, bottom = 12.dp)
.clickable {
appNavController.navigate(AppNavItem.CaseCrewListView.withArgs(type, itemId))
}
)
}
}
}