mirror of
https://github.com/owenlejeune/TVTime.git
synced 2025-11-22 11:40:54 -05:00
add video card to details screen
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package com.owenlejeune.tvtime.api.tmdb.model
|
package com.owenlejeune.tvtime.api.tmdb.model
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
|
import com.owenlejeune.tvtime.R
|
||||||
|
|
||||||
class Video(
|
class Video(
|
||||||
@SerializedName("iso_639_1") val language: String,
|
@SerializedName("iso_639_1") val language: String,
|
||||||
@@ -9,6 +10,19 @@ class Video(
|
|||||||
@SerializedName("key") val key: String,
|
@SerializedName("key") val key: String,
|
||||||
@SerializedName("site") val site: String,
|
@SerializedName("site") val site: String,
|
||||||
@SerializedName("size") val size: Int,
|
@SerializedName("size") val size: Int,
|
||||||
@SerializedName("type") val type: String,
|
@SerializedName("type") val type: Type,
|
||||||
@SerializedName("official") val isOfficial: Boolean
|
@SerializedName("official") val isOfficial: Boolean
|
||||||
)
|
) {
|
||||||
|
enum class Type(val stringRes: Int) {
|
||||||
|
@SerializedName("Clip")
|
||||||
|
CLIP(R.string.video_type_clip),
|
||||||
|
@SerializedName("Behind the Scenes")
|
||||||
|
BEHIND_THE_SCENES(R.string.video_type_behind_the_scenes),
|
||||||
|
@SerializedName("Featurette")
|
||||||
|
FEATURETTE(R.string.video_type_featureette),
|
||||||
|
@SerializedName("Teaser")
|
||||||
|
TEASER(R.string.video_type_teaser),
|
||||||
|
@SerializedName("Trailer")
|
||||||
|
TRAILER(R.string.video_type_trailer)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +1,22 @@
|
|||||||
package com.owenlejeune.tvtime.ui.components
|
package com.owenlejeune.tvtime.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.animation.animateContentSize
|
||||||
|
import androidx.compose.animation.core.LinearOutSlowInEasing
|
||||||
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.Card
|
import androidx.compose.material.Card
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
import coil.compose.rememberImagePainter
|
import coil.compose.rememberImagePainter
|
||||||
import coil.transform.RoundedCornersTransformation
|
import coil.transform.RoundedCornersTransformation
|
||||||
import com.owenlejeune.tvtime.R
|
import com.owenlejeune.tvtime.R
|
||||||
@@ -46,6 +52,51 @@ fun ContentCard(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ExpandableContentCard(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
backgroundColor: Color = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
title: @Composable () -> Unit = {},
|
||||||
|
collapsedText: String = stringResource(id = R.string.expandable_see_more),
|
||||||
|
expandedText: String = stringResource(id = R.string.expandable_see_less),
|
||||||
|
toggleTextColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
content: @Composable (Boolean) -> Unit = {}
|
||||||
|
) {
|
||||||
|
var expandedState by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
Card(
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.wrapContentHeight()
|
||||||
|
.animateContentSize(
|
||||||
|
animationSpec = tween(
|
||||||
|
durationMillis = 300,
|
||||||
|
easing = LinearOutSlowInEasing
|
||||||
|
)
|
||||||
|
),
|
||||||
|
shape = RoundedCornerShape(10.dp),
|
||||||
|
backgroundColor = backgroundColor,
|
||||||
|
elevation = 8.dp
|
||||||
|
) {
|
||||||
|
Column(modifier = Modifier.fillMaxSize()) {
|
||||||
|
title()
|
||||||
|
content(expandedState)
|
||||||
|
Text(
|
||||||
|
text = if (expandedState) expandedText else collapsedText,
|
||||||
|
color = toggleTextColor,
|
||||||
|
fontSize = 12.sp,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 12.dp, vertical = 8.dp)
|
||||||
|
.clickable(
|
||||||
|
onClick = {
|
||||||
|
expandedState = !expandedState
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ImageTextCard(
|
fun ImageTextCard(
|
||||||
title: String,
|
title: String,
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
package com.owenlejeune.tvtime.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import kotlin.math.ceil
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun StaticGridInternal(
|
||||||
|
columns: Int,
|
||||||
|
itemCount: Int,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
horizontalSpacing: Dp = 4.dp,
|
||||||
|
verticalSpacing: Dp = 4.dp,
|
||||||
|
content: @Composable (Int) -> Unit
|
||||||
|
) {
|
||||||
|
val numRows = ceil(itemCount.toFloat() / columns.toFloat()).toInt()
|
||||||
|
Column(
|
||||||
|
modifier = modifier,
|
||||||
|
verticalArrangement = Arrangement.spacedBy(verticalSpacing)
|
||||||
|
) {
|
||||||
|
for (i in 0 until numRows) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(horizontalSpacing)
|
||||||
|
) {
|
||||||
|
for (j in 0 until columns) {
|
||||||
|
if ((columns*i)+j < itemCount) {
|
||||||
|
content((columns*i)+j)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class StaticGridCells {
|
||||||
|
class Fixed(val count: Int): StaticGridCells()
|
||||||
|
class Dynamic(val minSize: Dp): StaticGridCells()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun StaticGrid(
|
||||||
|
cells: StaticGridCells,
|
||||||
|
itemCount: Int,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
content: @Composable (Int) -> Unit
|
||||||
|
) {
|
||||||
|
when (cells) {
|
||||||
|
is StaticGridCells.Fixed -> {
|
||||||
|
StaticGridInternal(
|
||||||
|
columns = cells.count,
|
||||||
|
itemCount = itemCount,
|
||||||
|
verticalSpacing = 4.dp,
|
||||||
|
horizontalSpacing = 4.dp,
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
is StaticGridCells.Dynamic -> {
|
||||||
|
BoxWithConstraints(modifier = modifier) {
|
||||||
|
val nColumns = maxOf((maxWidth / cells.minSize).toInt(), 1)
|
||||||
|
val spacing = maxWidth - (cells.minSize * nColumns)
|
||||||
|
StaticGridInternal(
|
||||||
|
columns = nColumns,
|
||||||
|
itemCount = itemCount,
|
||||||
|
verticalSpacing = 4.dp,
|
||||||
|
horizontalSpacing = spacing,
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.owenlejeune.tvtime.ui.components
|
package com.owenlejeune.tvtime.ui.components
|
||||||
|
|
||||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||||
import android.util.SparseArray
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.compose.animation.core.animateFloatAsState
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
import androidx.compose.foundation.Canvas
|
import androidx.compose.foundation.Canvas
|
||||||
@@ -20,11 +19,9 @@ import androidx.compose.material.icons.Icons
|
|||||||
import androidx.compose.material.icons.filled.Search
|
import androidx.compose.material.icons.filled.Search
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.rotate
|
|
||||||
import androidx.compose.ui.draw.scale
|
import androidx.compose.ui.draw.scale
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
@@ -51,19 +48,11 @@ import androidx.compose.ui.unit.sp
|
|||||||
import androidx.compose.ui.viewinterop.AndroidView
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
import androidx.compose.ui.window.Dialog
|
import androidx.compose.ui.window.Dialog
|
||||||
import androidx.compose.ui.window.DialogProperties
|
import androidx.compose.ui.window.DialogProperties
|
||||||
import at.huber.youtubeExtractor.VideoMeta
|
|
||||||
import at.huber.youtubeExtractor.YouTubeExtractor
|
|
||||||
import at.huber.youtubeExtractor.YtFile
|
|
||||||
import coil.compose.rememberImagePainter
|
import coil.compose.rememberImagePainter
|
||||||
import com.google.accompanist.flowlayout.FlowRow
|
import com.google.accompanist.flowlayout.FlowRow
|
||||||
import com.google.android.exoplayer2.ExoPlayer
|
|
||||||
import com.google.android.exoplayer2.MediaItem
|
|
||||||
import com.google.android.exoplayer2.SimpleExoPlayer
|
|
||||||
import com.google.android.exoplayer2.ui.PlayerView
|
|
||||||
import com.owenlejeune.tvtime.R
|
import com.owenlejeune.tvtime.R
|
||||||
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.YouTubePlayer
|
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.YouTubePlayer
|
||||||
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.AbstractYouTubePlayerListener
|
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.AbstractYouTubePlayerListener
|
||||||
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.YouTubePlayerFullScreenListener
|
|
||||||
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView
|
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -441,9 +430,13 @@ fun FullScreenThumbnailVideoPlayer(
|
|||||||
onDismissRequest = { showFullscreenView.value = false },
|
onDismissRequest = { showFullscreenView.value = false },
|
||||||
properties = DialogProperties(usePlatformDefaultWidth = false)
|
properties = DialogProperties(usePlatformDefaultWidth = false)
|
||||||
) {
|
) {
|
||||||
Surface(modifier = Modifier.fillMaxWidth().wrapContentHeight()) {
|
Surface(modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.wrapContentHeight()) {
|
||||||
AndroidView(
|
AndroidView(
|
||||||
modifier = Modifier.wrapContentHeight().fillMaxWidth(),
|
modifier = Modifier
|
||||||
|
.wrapContentHeight()
|
||||||
|
.fillMaxWidth(),
|
||||||
factory = {
|
factory = {
|
||||||
YouTubePlayerView(context).apply {
|
YouTubePlayerView(context).apply {
|
||||||
addYouTubePlayerListener(object : AbstractYouTubePlayerListener() {
|
addYouTubePlayerListener(object : AbstractYouTubePlayerListener() {
|
||||||
@@ -454,87 +447,7 @@ fun FullScreenThumbnailVideoPlayer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
// Text("big dialog")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// AndroidView(
|
|
||||||
// modifier = modifier,
|
|
||||||
// factory = {
|
|
||||||
// val player = YouTubePlayerView(context).apply {
|
|
||||||
// var ytPlayer: YouTubePlayer? = null
|
|
||||||
// addYouTubePlayerListener(object : AbstractYouTubePlayerListener() {
|
|
||||||
// override fun onReady(youTubePlayer: YouTubePlayer) {
|
|
||||||
// ytPlayer = youTubePlayer
|
|
||||||
// youTubePlayer.loadVideo(key, 0f)
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// addFullScreenListener(object : YouTubePlayerFullScreenListener {
|
|
||||||
// override fun onYouTubePlayerEnterFullScreen() {
|
|
||||||
// ytPlayer?.play()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun onYouTubePlayerExitFullScreen() {
|
|
||||||
// ytPlayer?.pause()
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// player.enterFullScreen()
|
|
||||||
//
|
|
||||||
// player
|
|
||||||
// }
|
|
||||||
// )
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// val lifecyclerOwner = LocalLifecycleOwner.current
|
|
||||||
// val showFullscreenView = remember { mutableStateOf(false) }
|
|
||||||
//
|
|
||||||
// if (!showFullscreenView.value) {
|
|
||||||
// Image(
|
|
||||||
// modifier = modifier
|
|
||||||
// .clickable(
|
|
||||||
// onClick = {
|
|
||||||
// showFullscreenView.value = true
|
|
||||||
// }
|
|
||||||
// ),
|
|
||||||
// painter = rememberImagePainter(
|
|
||||||
// data = "https://img.youtube.com/vi/${key}/hqdefault.jpg",
|
|
||||||
// builder = {
|
|
||||||
// placeholder(R.drawable.placeholder)
|
|
||||||
// }
|
|
||||||
// ),
|
|
||||||
// contentDescription = ""
|
|
||||||
// )
|
|
||||||
// } else {
|
|
||||||
// AndroidView(
|
|
||||||
// modifier = modifier,
|
|
||||||
// factory = { context ->
|
|
||||||
// val p = YouTubePlayerView(context).apply {
|
|
||||||
// var player: YouTubePlayer? = null
|
|
||||||
//// lifecyclerOwner.lifecycle.addObserver(this)
|
|
||||||
// addYouTubePlayerListener(object : AbstractYouTubePlayerListener() {
|
|
||||||
// override fun onReady(youTubePlayer: YouTubePlayer) {
|
|
||||||
// player = youTubePlayer
|
|
||||||
// youTubePlayer.loadVideo(key, 0f)
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// addFullScreenListener(object : YouTubePlayerFullScreenListener {
|
|
||||||
// override fun onYouTubePlayerEnterFullScreen() {
|
|
||||||
// player?.play()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun onYouTubePlayerExitFullScreen() {
|
|
||||||
// showFullscreenView.value = false
|
|
||||||
// player?.pause()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// p.enterFullScreen()
|
|
||||||
//
|
|
||||||
// p
|
|
||||||
// }
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.owenlejeune.tvtime.ui.screens
|
package com.owenlejeune.tvtime.ui.screens
|
||||||
|
|
||||||
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.lazy.LazyRow
|
import androidx.compose.foundation.lazy.LazyRow
|
||||||
@@ -348,7 +349,7 @@ fun SimilarContentCard(itemId: Int?, service: DetailService, modifier: Modifier
|
|||||||
|
|
||||||
ContentCard(
|
ContentCard(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
title = "Recommended"
|
title = stringResource(id = R.string.recommended_label)
|
||||||
) {
|
) {
|
||||||
LazyRow(modifier = Modifier
|
LazyRow(modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
@@ -370,6 +371,7 @@ fun SimilarContentCard(itemId: Int?, service: DetailService, modifier: Modifier
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun VideosCard(itemId: Int?, service: DetailService, modifier: Modifier = Modifier) {
|
fun VideosCard(itemId: Int?, service: DetailService, modifier: Modifier = Modifier) {
|
||||||
val videoResponse = remember { mutableStateOf<VideoResponse?>(null) }
|
val videoResponse = remember { mutableStateOf<VideoResponse?>(null) }
|
||||||
@@ -379,45 +381,58 @@ fun VideosCard(itemId: Int?, service: DetailService, modifier: Modifier = Modifi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentCard(
|
if (videoResponse.value != null) {
|
||||||
modifier = modifier,
|
val results = videoResponse.value!!.results
|
||||||
title = "Trailers"
|
ExpandableContentCard(
|
||||||
) {
|
modifier = modifier,
|
||||||
LazyRow(
|
title = {
|
||||||
modifier = Modifier
|
Text(
|
||||||
.fillMaxWidth()
|
text = stringResource(id = R.string.videos_label),
|
||||||
.wrapContentHeight()
|
style = MaterialTheme.typography.titleLarge,
|
||||||
.padding(vertical = 12.dp, horizontal = 8.dp)
|
modifier = Modifier.padding(start = 12.dp, top = 8.dp),
|
||||||
) {
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
val videos = videoResponse.value?.results?.filter { it.isOfficial && it.type.lowercase() in listOf("trailer"/*, "teaser"*/) }
|
)
|
||||||
val types = videos?.map { it.type }
|
},
|
||||||
items(videos?.size ?: 0) { i ->
|
toggleTextColor = MaterialTheme.colorScheme.primary
|
||||||
val video = videos!![i]
|
) { isExpanded ->
|
||||||
|
VideoGroup(results = results, type = Video.Type.TRAILER, title = stringResource(id = Video.Type.TRAILER.stringRes))
|
||||||
|
|
||||||
Column(
|
if (isExpanded) {
|
||||||
modifier = Modifier.wrapContentHeight().width(152.dp)
|
Video.Type.values().filter { it != Video.Type.TRAILER}.forEach { type ->
|
||||||
) {
|
VideoGroup(results = results, type = type, title = stringResource(id = type.stringRes))
|
||||||
FullScreenThumbnailVideoPlayer(
|
|
||||||
key = video.key,
|
|
||||||
modifier = Modifier
|
|
||||||
.size(width = 152.dp, height = 108.dp)
|
|
||||||
.padding(end = 4.dp)
|
|
||||||
)
|
|
||||||
MinLinesText(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(top = 5.dp),
|
|
||||||
minLines = 2,
|
|
||||||
text = video.name,
|
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
|
||||||
style = MaterialTheme.typography.bodyMedium
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
|
@Composable
|
||||||
|
private fun VideoGroup(results: List<Video>, type: Video.Type, title: String) {
|
||||||
|
val videos = results.filter { it.isOfficial && it.type == type }
|
||||||
|
if (videos.isNotEmpty()) {
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
color = MaterialTheme.colorScheme.primary,
|
||||||
|
modifier = Modifier.padding(start = 12.dp, top = 8.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
StaticGrid(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 12.dp, vertical = 8.dp),
|
||||||
|
cells = StaticGridCells.Dynamic(110.dp),
|
||||||
|
itemCount = videos.size
|
||||||
|
) { i ->
|
||||||
|
val video = videos[i]
|
||||||
|
FullScreenThumbnailVideoPlayer(
|
||||||
|
key = video.key,
|
||||||
|
modifier = Modifier.size(110.dp, 80.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun fetchMediaItem(id: Int, service: DetailService, mediaItem: MutableState<DetailedItem?>) {
|
private fun fetchMediaItem(id: Int, service: DetailService, mediaItem: MutableState<DetailedItem?>) {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
val response = service.getById(id)
|
val response = service.getById(id)
|
||||||
|
|||||||
@@ -15,6 +15,11 @@
|
|||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
<string name="cast_label">Cast</string>
|
<string name="cast_label">Cast</string>
|
||||||
|
<string name="recommended_label">Recommended</string>
|
||||||
|
<string name="videos_label">Videos</string>
|
||||||
|
|
||||||
|
<string name="expandable_see_more">See more</string>
|
||||||
|
<string name="expandable_see_less">See less</string>
|
||||||
|
|
||||||
<!-- preferences -->
|
<!-- preferences -->
|
||||||
<string name="preference_heading_search">Search</string>
|
<string name="preference_heading_search">Search</string>
|
||||||
@@ -23,4 +28,11 @@
|
|||||||
<string name="preferences_hide_heading_title">Expanded search bar</string>
|
<string name="preferences_hide_heading_title">Expanded search bar</string>
|
||||||
<string name="preferences_hide_heading_subtitle">Keep search bar expanded at all times</string>
|
<string name="preferences_hide_heading_subtitle">Keep search bar expanded at all times</string>
|
||||||
<string name="preferences_debug_title">Developer options</string>
|
<string name="preferences_debug_title">Developer options</string>
|
||||||
|
|
||||||
|
<!-- video type -->
|
||||||
|
<string name="video_type_clip">Clips</string>
|
||||||
|
<string name="video_type_trailer">Trailers</string>
|
||||||
|
<string name="video_type_teaser">Teasers</string>
|
||||||
|
<string name="video_type_behind_the_scenes">Behind the Scenes</string>
|
||||||
|
<string name="video_type_featureette">Featurettes</string>
|
||||||
</resources>
|
</resources>
|
||||||
Reference in New Issue
Block a user