show keywords

This commit is contained in:
Owen LeJeune
2022-02-28 22:51:20 -05:00
parent eebd5342ae
commit 3b7355892b
9 changed files with 152 additions and 19 deletions

View File

@@ -21,4 +21,6 @@ interface DetailService {
suspend fun deleteRating(id: Int): Response<RatingResponse>
suspend fun getKeywords(id: Int): Response<KeywordsResponse>
}

View File

@@ -39,6 +39,9 @@ interface MoviesApi {
@GET("movie/{id}/reviews")
suspend fun getReviews(@Path("id") id: Int): Response<ReviewResponse>
@GET("movie/{id}/keywords")
suspend fun getKeywords(@Path("id") id: Int): Response<KeywordsResponse>
@POST("movie/{id}/rating")
suspend fun postMovieRatingAsGuest(
@Path("id") id: Int,

View File

@@ -71,4 +71,8 @@ class MoviesService: KoinComponent, DetailService, HomePageService {
}
}
override suspend fun getKeywords(id: Int): Response<KeywordsResponse> {
return movieService.getKeywords(id)
}
}

View File

@@ -39,6 +39,9 @@ interface TvApi {
@GET("tv/{id}/reviews")
suspend fun getReviews(@Path("id") id: Int): Response<ReviewResponse>
@GET("tv/{id}/keywords")
suspend fun getKeywords(@Path("id") id: Int): Response<KeywordsResponse>
@POST("tv/{id}/rating")
suspend fun postTvRatingAsGuest(
@Path("id") id: Int,

View File

@@ -71,4 +71,8 @@ class TvService: KoinComponent, DetailService, HomePageService {
}
}
override suspend fun getKeywords(id: Int): Response<KeywordsResponse> {
return service.getKeywords(id)
}
}

View File

@@ -0,0 +1,8 @@
package com.owenlejeune.tvtime.api.tmdb.model
import com.google.gson.annotations.SerializedName
class Keyword(
@SerializedName("id") val id: Int,
@SerializedName("name") val name: String
)

View File

@@ -0,0 +1,8 @@
package com.owenlejeune.tvtime.api.tmdb.model
import com.google.gson.annotations.SerializedName
class KeywordsResponse(
@SerializedName("id") val id: Int,
@SerializedName("keywords") val keywords: List<Keyword>?
)

View File

@@ -33,6 +33,7 @@ import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.painter.BrushPainter
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.input.pointer.pointerInput
@@ -267,15 +268,21 @@ fun MinLinesText(
)
}
sealed class ChipStyle(val mainAxisSpacing: Dp, val crossAxisSpacing: Dp) {
object Boxy: ChipStyle(8.dp, 4.dp)
object Rounded: ChipStyle(4.dp, 4.dp)
class Mixed(val predicate: (String) -> ChipStyle): ChipStyle(8.dp, 4.dp)
}
@Composable
fun Chip(
fun BoxyChip(
text: String,
style: TextStyle = MaterialTheme.typography.bodySmall,
isSelected: Boolean = true,
onSelectionChanged: (String) -> Unit = {}
) {
Surface(
modifier = Modifier.padding(4.dp),
// modifier = Modifier.padding(4.dp),
shadowElevation = 8.dp,
shape = RoundedCornerShape(5.dp),
color = if (isSelected) MaterialTheme.colorScheme.secondaryContainer else MaterialTheme.colorScheme.secondary
@@ -299,20 +306,75 @@ fun Chip(
}
}
@Composable
fun RoundedChip(
text: String,
style: TextStyle = MaterialTheme.typography.bodySmall,
isSelected: Boolean = false,
onSelectionChanged: (String) -> Unit = {}
) {
val borderColor = if (isSelected) MaterialTheme.colorScheme.inverseSurface else MaterialTheme.colorScheme.onSurfaceVariant
val radius = style.fontSize.value.dp * 2
Surface(
border = BorderStroke(width = 1.dp, borderColor),
shape = RoundedCornerShape(radius),
color = MaterialTheme.colorScheme.surfaceVariant
) {
Row(
modifier = Modifier
.toggleable(
value = isSelected,
onValueChange = {
onSelectionChanged(text)
}
)
.padding(8.dp)
) {
Text(
text = text,
style = style,
color = if (isSelected) MaterialTheme.colorScheme.inverseSurface else MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
}
@Composable
fun ChipGroup(
modifier: Modifier = Modifier,
chips: List<String> = emptyList(),
onSelectedChanged: (String) -> Unit = {},
chipStyle: ChipStyle = ChipStyle.Boxy
) {
@Composable
fun DrawChip(chipStyle: ChipStyle, chip: String) {
when (chipStyle) {
ChipStyle.Boxy -> {
BoxyChip(
text = chip,
onSelectionChanged = onSelectedChanged
)
}
ChipStyle.Rounded -> {
RoundedChip(
text = chip,
onSelectionChanged = onSelectedChanged
)
}
is ChipStyle.Mixed -> {
DrawChip(chipStyle = chipStyle.predicate(chip), chip = chip)
}
}
}
FlowRow(
modifier = modifier
modifier = modifier,
crossAxisSpacing = 4.dp,
mainAxisSpacing = chipStyle.mainAxisSpacing
) {
chips.forEach { chip ->
Chip(
text = chip,
onSelectionChanged = onSelectedChanged
)
DrawChip(chipStyle = chipStyle, chip = chip)
}
}
}
@@ -320,7 +382,7 @@ fun ChipGroup(
@Preview
@Composable
fun ChipPreview() {
Chip("Test Chip")
BoxyChip("Test Chip")
}
/**
@@ -558,7 +620,9 @@ fun CircleBackgroundColorImage(
.background(color = backgroundColor)
) {
val mod = if (imageHeight != null) {
Modifier.align(imageAlignment).height(height = imageHeight)
Modifier
.align(imageAlignment)
.height(height = imageHeight)
} else {
Modifier.align(imageAlignment)
}
@@ -596,7 +660,9 @@ fun AvatarImage(
.background(color = MaterialTheme.colorScheme.tertiary)
) {
Text(
modifier = Modifier.fillMaxSize().padding(top = size/5),
modifier = Modifier
.fillMaxSize()
.padding(top = size / 5),
text = if (author.name.isNotEmpty()) author.name[0].uppercase() else author.username[0].toString(),
color = MaterialTheme.colorScheme.onTertiary,
textAlign = TextAlign.Center,

View File

@@ -401,10 +401,8 @@ private fun ContentColumn(
MiscTvDetails(mediaItem = mediaItem, service as TvService)
}
ActionsView(itemId = itemId, type = mediaType, service = service)
if (mediaItem.value?.overview?.isNotEmpty() == true) {
OverviewCard(mediaItem = mediaItem)
OverviewCard(itemId = itemId!!, mediaItem.value!!.overview!!, service)
}
CastCard(itemId = itemId, service = service, appNavController = appNavController)
@@ -412,6 +410,8 @@ private fun ContentColumn(
SimilarContentCard(itemId = itemId, service = service, mediaType = mediaType, appNavController = appNavController)
VideosCard(itemId = itemId, service = service)
ActionsView(itemId = itemId, type = mediaType, service = service)
ReviewsCard(itemId = itemId, service = service)
}
@@ -653,19 +653,43 @@ private fun RatingDialog(showDialog: MutableState<Boolean>, onValueConfirmed: (F
}
@Composable
private fun OverviewCard(mediaItem: MutableState<DetailedItem?>, modifier: Modifier = Modifier) {
private fun OverviewCard(itemId: Int, overview: String, service: DetailService, modifier: Modifier = Modifier) {
val keywordResponse = remember { mutableStateOf<KeywordsResponse?>(null) }
if (keywordResponse.value == null) {
fetchKeywords(itemId, service, keywordResponse)
}
val context = LocalContext.current
ContentCard(
modifier = modifier
) {
Text(
Column(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(vertical = 12.dp, horizontal = 16.dp),
text = mediaItem.value?.overview ?: "",
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.bodyMedium
)
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
Text(
text = overview,
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.bodyMedium
)
keywordResponse.value?.keywords?.let { keywords ->
val names = keywords.map { it.name }
ChipGroup(
chips = names,
chipStyle = ChipStyle.Rounded,
onSelectedChanged = { chip ->
if (service is MoviesService) {
// Toast.makeText(context, chip, Toast.LENGTH_SHORT).show()
}
}
)
}
}
}
}
@@ -1085,4 +1109,15 @@ private fun fetchReviews(id: Int, service: DetailService, reviewResponse: Mutabl
}
}
}
}
private fun fetchKeywords(id: Int, service: DetailService, keywordsResponse: MutableState<KeywordsResponse?>) {
CoroutineScope(Dispatchers.IO).launch {
val result = service.getKeywords(id)
if (result.isSuccessful) {
withContext(Dispatchers.Main) {
keywordsResponse.value = result.body()
}
}
}
}