mirror of
https://github.com/owenlejeune/TVTime.git
synced 2025-11-18 09:40:53 -05:00
display cast and overview on details screen
This commit is contained in:
@@ -15,8 +15,8 @@
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.TVTime">
|
||||
android:theme="@style/Theme.TVTime"
|
||||
android:screenOrientation="portrait">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
|
||||
@@ -1,28 +1,20 @@
|
||||
package com.owenlejeune.tvtime
|
||||
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.animation.rememberSplineBasedDecay
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.owenlejeune.tvtime.ui.navigation.BottomNavItem
|
||||
import com.owenlejeune.tvtime.ui.navigation.BottomNavigationRoutes
|
||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||
import com.owenlejeune.tvtime.ui.navigation.MainNavigationRoutes
|
||||
import com.owenlejeune.tvtime.ui.theme.TVTimeTheme
|
||||
|
||||
@@ -31,7 +23,14 @@ class MainActivity : ComponentActivity() {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
val displayUnderStatusBar = remember { mutableStateOf(false) }
|
||||
WindowCompat.setDecorFitsSystemWindows(window, !displayUnderStatusBar.value)
|
||||
// WindowCompat.setDecorFitsSystemWindows(window, !displayUnderStatusBar.value)
|
||||
// val statusBarColor = if (displayUnderStatusBar.value) {
|
||||
// Color.Transparent
|
||||
// } else {
|
||||
// MaterialTheme.colorScheme.background
|
||||
// }
|
||||
// val systemUiController = rememberSystemUiController()
|
||||
// systemUiController.setStatusBarColor(statusBarColor, !isSystemInDarkTheme())
|
||||
MyApp(displayUnderStatusBar = displayUnderStatusBar)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.owenlejeune.tvtime.api.tmdb
|
||||
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.CastAndCrew
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.ImageCollection
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.DetailedItem
|
||||
import retrofit2.Response
|
||||
@@ -10,4 +11,6 @@ interface DetailService {
|
||||
|
||||
suspend fun getImages(id: Int): Response<ImageCollection>
|
||||
|
||||
suspend fun getCastAndCrew(id: Int): Response<CastAndCrew>
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.owenlejeune.tvtime.api.tmdb
|
||||
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.CastAndCrew
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.ImageCollection
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.DetailedMovie
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.PopularMoviesResponse
|
||||
@@ -19,4 +20,7 @@ interface MoviesApi {
|
||||
@GET("movie/{id}/images")
|
||||
suspend fun getMovieImages(@Path("id") id: Int): Response<ImageCollection>
|
||||
|
||||
@GET("movie/{id}/credits")
|
||||
suspend fun getCastAndCrew(@Path("id") id: Int): Response<CastAndCrew>
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.owenlejeune.tvtime.api.tmdb
|
||||
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.CastAndCrew
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.ImageCollection
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.DetailedItem
|
||||
import org.koin.core.component.KoinComponent
|
||||
@@ -19,4 +20,8 @@ class MoviesService: KoinComponent, DetailService {
|
||||
return service.getMovieImages(id)
|
||||
}
|
||||
|
||||
override suspend fun getCastAndCrew(id: Int): Response<CastAndCrew> {
|
||||
return service.getCastAndCrew(id)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,10 +2,15 @@ package com.owenlejeune.tvtime.api.tmdb
|
||||
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.DetailedItem
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.Image
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.Person
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.TmdbItem
|
||||
|
||||
object TmdbUtils {
|
||||
|
||||
private const val POSTER_BASE = "https://image.tmdb.org/t/p/original"
|
||||
private const val BACKDROP_BASE = "https://www.themoviedb.org/t/p/original"
|
||||
private const val PERSON_BASE = "https://www.themoviedb.org/t/p/w600_and_h900_bestv2"
|
||||
|
||||
fun getFullPosterPath(posterPath: String?): String? {
|
||||
return posterPath?.let { "https://image.tmdb.org/t/p/original${posterPath}" }
|
||||
}
|
||||
@@ -30,4 +35,12 @@ object TmdbUtils {
|
||||
return getFullBackdropPath(image.filePath)
|
||||
}
|
||||
|
||||
fun getFullPersonImagePath(path: String?): String? {
|
||||
return path?.let { "https://www.themoviedb.org/t/p/w600_and_h900_bestv2${path}" }
|
||||
}
|
||||
|
||||
fun getFullPersonImagePath(person: Person): String? {
|
||||
return getFullPersonImagePath(person.profilePath)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.owenlejeune.tvtime.api.tmdb
|
||||
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.CastAndCrew
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.ImageCollection
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.PopularTvResponse
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.DetailedTv
|
||||
@@ -19,4 +20,7 @@ interface TvApi {
|
||||
@GET("tv/{id}/images")
|
||||
suspend fun getTvImages(@Path("id") id: Int): Response<ImageCollection>
|
||||
|
||||
@GET("tv/{id}/credits")
|
||||
suspend fun getCastAndCrew(@Path("id") id: Int): Response<CastAndCrew>
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.owenlejeune.tvtime.api.tmdb
|
||||
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.CastAndCrew
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.ImageCollection
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.DetailedItem
|
||||
import org.koin.core.component.KoinComponent
|
||||
@@ -18,4 +19,8 @@ class TvService: KoinComponent, DetailService {
|
||||
override suspend fun getImages(id: Int): Response<ImageCollection> {
|
||||
return service.getTvImages(id)
|
||||
}
|
||||
|
||||
override suspend fun getCastAndCrew(id: Int): Response<CastAndCrew> {
|
||||
return service.getCastAndCrew(id)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.owenlejeune.tvtime.api.tmdb.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
class CastAndCrew(
|
||||
@SerializedName("cast") val cast: List<CastMember>,
|
||||
@SerializedName("crew") val crew: List<CrewMember>
|
||||
)
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.owenlejeune.tvtime.api.tmdb.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
class CastMember(
|
||||
@SerializedName("character") val character: String,
|
||||
@SerializedName("order") val order: Int,
|
||||
id: Int,
|
||||
creditId: String,
|
||||
name: String,
|
||||
gender: Int,
|
||||
profilePath: String?
|
||||
): Person(id, creditId, name, gender, profilePath)
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.owenlejeune.tvtime.api.tmdb.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
class CrewMember(
|
||||
@SerializedName("department") val department: String,
|
||||
@SerializedName("job") val job: String,
|
||||
id: Int,
|
||||
creditId: String,
|
||||
name: String,
|
||||
gender: Int,
|
||||
profilePath: String?
|
||||
): Person(id, creditId, name, gender, profilePath)
|
||||
@@ -4,7 +4,8 @@ import com.google.gson.annotations.SerializedName
|
||||
|
||||
open class Person(
|
||||
@SerializedName("id") val id: Int,
|
||||
@SerializedName("credit_id") val creditId: Int,
|
||||
@SerializedName("credit_id") val creditId: String,
|
||||
@SerializedName("name") val name: String,
|
||||
@SerializedName("gender") val gender: Int
|
||||
@SerializedName("gender") val gender: Int,
|
||||
@SerializedName("profile_path") val profilePath: String?
|
||||
)
|
||||
|
||||
@@ -11,6 +11,8 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.GridCells
|
||||
import androidx.compose.foundation.lazy.LazyVerticalGrid
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Card
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -67,28 +69,35 @@ fun PosterItem(
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val poster = mediaItem?.let { TmdbUtils.getFullPosterPath(mediaItem) }
|
||||
Image(
|
||||
painter = if (mediaItem != null) {
|
||||
rememberImagePainter(
|
||||
data = poster,
|
||||
builder = {
|
||||
transformations(RoundedCornersTransformation(5f.dpToPx(context)))
|
||||
placeholder(R.drawable.placeholder)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
rememberImagePainter(ContextCompat.getDrawable(context, R.drawable.placeholder))
|
||||
},
|
||||
contentDescription = mediaItem?.title,
|
||||
Card(
|
||||
elevation = 8.dp,
|
||||
modifier = modifier
|
||||
.size(width = width, height = height)
|
||||
.padding(5.dp)
|
||||
.clickable {
|
||||
mediaItem?.let {
|
||||
onClick(mediaItem.id)
|
||||
.padding(5.dp),
|
||||
shape = RoundedCornerShape(5.dp)
|
||||
) {
|
||||
Image(
|
||||
painter = if (mediaItem != null) {
|
||||
rememberImagePainter(
|
||||
data = poster,
|
||||
builder = {
|
||||
transformations(RoundedCornersTransformation(5f.dpToPx(context)))
|
||||
placeholder(R.drawable.placeholder)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
rememberImagePainter(ContextCompat.getDrawable(context, R.drawable.placeholder))
|
||||
},
|
||||
contentDescription = mediaItem?.title,
|
||||
modifier = Modifier
|
||||
.size(width = width, height = height)
|
||||
.clickable {
|
||||
mediaItem?.let {
|
||||
onClick(mediaItem.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("CoroutineCreationDuringComposition")
|
||||
|
||||
@@ -26,8 +26,6 @@ fun MainNavigationRoutes(navController: NavHostController, displayUnderStatusBar
|
||||
NavHost(navController = navController, startDestination = MainNavItem.MainView.route) {
|
||||
composable(MainNavItem.MainView.route) {
|
||||
displayUnderStatusBar.value = false
|
||||
val systemUiController = rememberSystemUiController()
|
||||
systemUiController.setStatusBarColor(MaterialTheme.colorScheme.background, !isSystemInDarkTheme())
|
||||
MainAppView(appNavController = navController)
|
||||
}
|
||||
composable(
|
||||
@@ -38,8 +36,6 @@ fun MainNavigationRoutes(navController: NavHostController, displayUnderStatusBar
|
||||
)
|
||||
) { navBackStackEntry ->
|
||||
displayUnderStatusBar.value = true
|
||||
val systemUiController = rememberSystemUiController()
|
||||
systemUiController.setStatusBarColor(Color.Transparent, !isSystemInDarkTheme())
|
||||
val args = navBackStackEntry.arguments
|
||||
DetailView(
|
||||
appNavController = navController,
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
package com.owenlejeune.tvtime.ui.screens
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.Card
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material3.Icon
|
||||
@@ -16,17 +22,23 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.constraintlayout.compose.ConstraintLayout
|
||||
import androidx.navigation.NavController
|
||||
import coil.compose.rememberImagePainter
|
||||
import coil.transform.RoundedCornersTransformation
|
||||
import com.owenlejeune.tvtime.R
|
||||
import com.owenlejeune.tvtime.api.tmdb.DetailService
|
||||
import com.owenlejeune.tvtime.api.tmdb.MoviesService
|
||||
import com.owenlejeune.tvtime.api.tmdb.TmdbUtils
|
||||
import com.owenlejeune.tvtime.api.tmdb.TvService
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.CastAndCrew
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.DetailedItem
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.Image
|
||||
import com.owenlejeune.tvtime.api.tmdb.model.ImageCollection
|
||||
import com.owenlejeune.tvtime.extensions.dpToPx
|
||||
import com.owenlejeune.tvtime.ui.components.BackdropImage
|
||||
import com.owenlejeune.tvtime.ui.components.PosterItem
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -48,24 +60,32 @@ fun DetailView(
|
||||
|
||||
val mediaItem = remember { mutableStateOf<DetailedItem?>(null) }
|
||||
itemId?.let {
|
||||
fetchMediaItem(itemId, service, mediaItem)
|
||||
if (mediaItem.value == null) {
|
||||
fetchMediaItem(itemId, service, mediaItem)
|
||||
}
|
||||
}
|
||||
|
||||
val images = remember { mutableStateOf<ImageCollection?>(null) }
|
||||
itemId?.let {
|
||||
fetchImages(itemId, service, images)
|
||||
if (images.value == null) {
|
||||
fetchImages(itemId, service, images)
|
||||
}
|
||||
}
|
||||
|
||||
val scrollState = rememberScrollState()
|
||||
|
||||
ConstraintLayout(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(color = MaterialTheme.colorScheme.background)
|
||||
.verticalScroll(state = scrollState)
|
||||
) {
|
||||
val (
|
||||
backButton,
|
||||
backdropImage,
|
||||
posterImage,
|
||||
title
|
||||
titleText,
|
||||
contentColumn
|
||||
) = createRefs()
|
||||
|
||||
BackdropImage(
|
||||
@@ -75,18 +95,18 @@ fun DetailView(
|
||||
start.linkTo(parent.start)
|
||||
}
|
||||
.fillMaxWidth()
|
||||
.size(0.dp, 280.dp),
|
||||
.height(280.dp),
|
||||
imageUrl = TmdbUtils.getFullBackdropPath(mediaItem.value),
|
||||
collection = images.value
|
||||
// collection = images.value
|
||||
)
|
||||
|
||||
PosterItem(
|
||||
mediaItem = mediaItem.value,
|
||||
modifier = Modifier
|
||||
.constrainAs(posterImage) {
|
||||
bottom.linkTo(title.top, margin = 8.dp)
|
||||
bottom.linkTo(backdropImage.bottom)
|
||||
start.linkTo(parent.start, margin = 16.dp)
|
||||
top.linkTo(backButton.bottom, margin = 8.dp)
|
||||
top.linkTo(backButton.bottom)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -94,14 +114,14 @@ fun DetailView(
|
||||
text = mediaItem.value?.title ?: "",
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier
|
||||
.constrainAs(title) {
|
||||
bottom.linkTo(backdropImage.bottom, margin = 8.dp)
|
||||
start.linkTo(parent.start, margin = 20.dp)
|
||||
.constrainAs(titleText) {
|
||||
bottom.linkTo(posterImage.bottom)
|
||||
start.linkTo(posterImage.end, margin = 8.dp)
|
||||
end.linkTo(parent.end, margin = 16.dp)
|
||||
}
|
||||
.padding(start = 16.dp, end = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
.fillMaxWidth(.6f),
|
||||
style = MaterialTheme.typography.headlineMedium,
|
||||
textAlign = TextAlign.Start,
|
||||
softWrap = true
|
||||
)
|
||||
@@ -110,10 +130,18 @@ fun DetailView(
|
||||
onClick = { appNavController.popBackStack() },
|
||||
modifier = Modifier
|
||||
.constrainAs(backButton) {
|
||||
top.linkTo(parent.top, 16.dp)
|
||||
top.linkTo(parent.top)//, 8.dp)
|
||||
start.linkTo(parent.start, 12.dp)
|
||||
bottom.linkTo(posterImage.top)
|
||||
}
|
||||
.background(brush = Brush.radialGradient(colors = listOf(Color.Black, Color.Transparent)))
|
||||
.background(
|
||||
brush = Brush.radialGradient(
|
||||
colors = listOf(
|
||||
Color.Black,
|
||||
Color.Transparent
|
||||
)
|
||||
)
|
||||
)
|
||||
.wrapContentSize()
|
||||
) {
|
||||
Icon(
|
||||
@@ -122,6 +150,108 @@ fun DetailView(
|
||||
tint = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
}
|
||||
|
||||
val castAndCrew = remember { mutableStateOf<CastAndCrew?>(null) }
|
||||
itemId?.let {
|
||||
if (castAndCrew.value == null) {
|
||||
fetchCastAndCrew(itemId, service, castAndCrew)
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.padding(horizontal = 16.dp)
|
||||
.constrainAs(contentColumn) {
|
||||
top.linkTo(backdropImage.bottom, margin = 8.dp)
|
||||
}
|
||||
) {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.padding(bottom = 12.dp),
|
||||
shape = RoundedCornerShape(10.dp),
|
||||
backgroundColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||
elevation = 8.dp
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.padding(vertical = 12.dp, horizontal = 16.dp),
|
||||
text = mediaItem.value?.overview ?: "",
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
style = MaterialTheme.typography.bodyMedium
|
||||
)
|
||||
}
|
||||
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight(),
|
||||
shape = RoundedCornerShape(10.dp),
|
||||
backgroundColor = MaterialTheme.colorScheme.primary,
|
||||
elevation = 8.dp
|
||||
) {
|
||||
LazyRow(modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(12.dp)
|
||||
) {
|
||||
items(castAndCrew.value?.cast?.size ?: 0) { i ->
|
||||
val castMember = castAndCrew.value!!.cast[i]
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.width(124.dp)
|
||||
.wrapContentHeight()
|
||||
.padding(end = 12.dp)
|
||||
) {
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.size(width = 120.dp, height = 180.dp),
|
||||
painter = rememberImagePainter(
|
||||
data = TmdbUtils.getFullPersonImagePath(castMember),
|
||||
builder = {
|
||||
transformations(RoundedCornersTransformation(5f.dpToPx(context)))
|
||||
placeholder(R.drawable.placeholder)
|
||||
}
|
||||
),
|
||||
contentDescription = ""
|
||||
)
|
||||
val nameLineHeight = MaterialTheme.typography.bodyMedium.fontSize*4/3
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 5.dp)
|
||||
.sizeIn(
|
||||
minHeight = with(LocalDensity.current) {
|
||||
(nameLineHeight * 2).toDp()
|
||||
}
|
||||
),
|
||||
text = castMember.name,
|
||||
color = MaterialTheme.colorScheme.onPrimary,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
lineHeight = nameLineHeight
|
||||
)
|
||||
val characterLineHeight = MaterialTheme.typography.bodySmall.fontSize*4/3
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.sizeIn(
|
||||
minHeight = with(LocalDensity.current) {
|
||||
(characterLineHeight * 2).toDp()
|
||||
}
|
||||
),
|
||||
text = castMember.character,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
lineHeight = characterLineHeight
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,6 +277,17 @@ private fun fetchImages(id: Int, service: DetailService, images: MutableState<Im
|
||||
}
|
||||
}
|
||||
|
||||
private fun fetchCastAndCrew(id: Int, service: DetailService, castAndCrew: MutableState<CastAndCrew?>) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val response = service.getCastAndCrew(id)
|
||||
if (response.isSuccessful) {
|
||||
withContext(Dispatchers.Main) {
|
||||
castAndCrew.value = response.body()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class DetailViewType {
|
||||
MOVIE,
|
||||
TV
|
||||
|
||||
@@ -14,6 +14,7 @@ import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.owenlejeune.tvtime.preferences.AppPreferences
|
||||
import com.owenlejeune.tvtime.ui.components.PaletteView
|
||||
@@ -67,7 +68,7 @@ private fun PaletteDialog(showDialog: MutableState<Boolean>) {
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = { showDialog.value = false }
|
||||
) {
|
||||
Text(text = "Dismiss")
|
||||
Text(text = "Dismiss", color = Color.White)
|
||||
}
|
||||
},
|
||||
confirmButton = {},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="5dp" />
|
||||
<corners android:radius="20dp" />
|
||||
<solid android:color="@android:color/darker_gray" />
|
||||
</shape>
|
||||
Reference in New Issue
Block a user