From 5abc03c4cf43b45651fbed2dc5a22d6621bf494f Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Mon, 27 Jan 2025 07:35:41 +0530 Subject: [PATCH] Extract thumbnail into common composable --- .../ui/components/items/common/Thumbnail.kt | 70 +++++++++++++++++++ .../items/playlist/PlaylistThumbnail.kt | 58 ++++----------- .../items/stream/StreamThumbnail.kt | 50 +++++-------- app/src/main/res/values/strings.xml | 2 + 4 files changed, 100 insertions(+), 80 deletions(-) create mode 100644 app/src/main/java/org/schabi/newpipe/ui/components/items/common/Thumbnail.kt diff --git a/app/src/main/java/org/schabi/newpipe/ui/components/items/common/Thumbnail.kt b/app/src/main/java/org/schabi/newpipe/ui/components/items/common/Thumbnail.kt new file mode 100644 index 000000000..27c8915f2 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/ui/components/items/common/Thumbnail.kt @@ -0,0 +1,70 @@ +package org.schabi.newpipe.ui.components.items.common + +import androidx.annotation.DrawableRes +import androidx.compose.foundation.background +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.layout.size +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import coil3.compose.AsyncImage +import org.schabi.newpipe.extractor.Image +import org.schabi.newpipe.util.image.ImageStrategy + +@Composable +fun Thumbnail( + images: List, + imageDescription: String, + @DrawableRes imagePlaceholder: Int, + cornerBackgroundColor: Color, + cornerIcon: ImageVector?, + cornerText: String, + contentScale: ContentScale, + modifier: Modifier = Modifier +) { + Box(contentAlignment = Alignment.BottomEnd) { + AsyncImage( + model = ImageStrategy.choosePreferredImage(images), + contentDescription = imageDescription, + placeholder = painterResource(imagePlaceholder), + error = painterResource(imagePlaceholder), + contentScale = contentScale, + modifier = modifier + ) + + Row( + modifier = Modifier + .padding(2.dp) + .background(cornerBackgroundColor) + .padding(2.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(4.dp) + ) { + if (cornerIcon != null) { + Icon( + imageVector = cornerIcon, + contentDescription = null, + tint = Color.White, + modifier = Modifier.size(18.dp) + ) + } + + Text( + text = cornerText, + color = Color.White, + style = MaterialTheme.typography.bodySmall + ) + } + } +} diff --git a/app/src/main/java/org/schabi/newpipe/ui/components/items/playlist/PlaylistThumbnail.kt b/app/src/main/java/org/schabi/newpipe/ui/components/items/playlist/PlaylistThumbnail.kt index 859ee1533..e11c089aa 100644 --- a/app/src/main/java/org/schabi/newpipe/ui/components/items/playlist/PlaylistThumbnail.kt +++ b/app/src/main/java/org/schabi/newpipe/ui/components/items/playlist/PlaylistThumbnail.kt @@ -1,28 +1,17 @@ package org.schabi.newpipe.ui.components.items.playlist -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.PlaylistPlay -import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.unit.dp -import coil3.compose.AsyncImage +import androidx.compose.ui.res.stringResource import org.schabi.newpipe.R import org.schabi.newpipe.ui.components.items.Playlist +import org.schabi.newpipe.ui.components.items.common.Thumbnail import org.schabi.newpipe.util.Localization -import org.schabi.newpipe.util.image.ImageStrategy @Composable fun PlaylistThumbnail( @@ -30,37 +19,14 @@ fun PlaylistThumbnail( modifier: Modifier = Modifier, contentScale: ContentScale = ContentScale.Fit ) { - Box(contentAlignment = Alignment.BottomEnd) { - AsyncImage( - model = ImageStrategy.choosePreferredImage(playlist.thumbnails), - contentDescription = null, - placeholder = painterResource(R.drawable.placeholder_thumbnail_playlist), - error = painterResource(R.drawable.placeholder_thumbnail_playlist), - contentScale = contentScale, - modifier = modifier - ) - - Row( - modifier = Modifier - .padding(2.dp) - .background(Color.Black.copy(alpha = 0.5f)) - .padding(2.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Icon( - imageVector = Icons.AutoMirrored.Default.PlaylistPlay, - contentDescription = null, - tint = Color.White, - modifier = Modifier.size(18.dp) - ) - - val context = LocalContext.current - Text( - text = Localization.localizeStreamCountMini(context, playlist.streamCount), - color = Color.White, - style = MaterialTheme.typography.bodySmall, - modifier = Modifier.padding(start = 4.dp) - ) - } - } + Thumbnail( + images = playlist.thumbnails, + imageDescription = stringResource(R.string.playlist_content_description, playlist.name), + imagePlaceholder = R.drawable.placeholder_thumbnail_playlist, + cornerBackgroundColor = Color.Black.copy(alpha = 0.5f), + cornerIcon = Icons.AutoMirrored.Default.PlaylistPlay, + cornerText = Localization.localizeStreamCountMini(LocalContext.current, playlist.streamCount), + contentScale = contentScale, + modifier = modifier + ) } diff --git a/app/src/main/java/org/schabi/newpipe/ui/components/items/stream/StreamThumbnail.kt b/app/src/main/java/org/schabi/newpipe/ui/components/items/stream/StreamThumbnail.kt index b029841cf..28a5af6ae 100644 --- a/app/src/main/java/org/schabi/newpipe/ui/components/items/stream/StreamThumbnail.kt +++ b/app/src/main/java/org/schabi/newpipe/ui/components/items/stream/StreamThumbnail.kt @@ -1,33 +1,25 @@ package org.schabi.newpipe.ui.components.items.stream -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.requiredHeight import androidx.compose.material3.LinearProgressIndicator -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableLongStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel -import coil3.compose.AsyncImage import org.schabi.newpipe.R import org.schabi.newpipe.ui.components.items.Stream +import org.schabi.newpipe.ui.components.items.common.Thumbnail import org.schabi.newpipe.util.Localization import org.schabi.newpipe.util.StreamTypeUtil -import org.schabi.newpipe.util.image.ImageStrategy import org.schabi.newpipe.viewmodels.StreamViewModel import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds @@ -40,31 +32,21 @@ fun StreamThumbnail( contentScale: ContentScale = ContentScale.Fit ) { Column(modifier = modifier) { - Box(contentAlignment = Alignment.BottomEnd) { - AsyncImage( - model = ImageStrategy.choosePreferredImage(stream.thumbnails), - contentDescription = null, - placeholder = painterResource(R.drawable.placeholder_thumbnail_video), - error = painterResource(R.drawable.placeholder_thumbnail_video), - contentScale = contentScale, - modifier = modifier - ) - - val isLive = StreamTypeUtil.isLiveStream(stream.type) - Text( - modifier = Modifier - .padding(2.dp) - .background(if (isLive) Color.Red else Color.Black.copy(alpha = 0.5f)) - .padding(2.dp), - text = if (isLive) { - stringResource(R.string.duration_live) - } else { - Localization.getDurationString(stream.duration) - }, - color = Color.White, - style = MaterialTheme.typography.bodySmall - ) - } + val isLive = StreamTypeUtil.isLiveStream(stream.type) + Thumbnail( + images = stream.thumbnails, + imageDescription = stringResource(R.string.stream_content_description, stream.name), + imagePlaceholder = R.drawable.placeholder_thumbnail_video, + cornerBackgroundColor = if (isLive) Color.Red else Color.Black.copy(alpha = 0.5f), + cornerIcon = null, + cornerText = if (isLive) { + stringResource(R.string.duration_live) + } else { + Localization.getDurationString(stream.duration) + }, + contentScale = contentScale, + modifier = modifier + ) if (showProgress) { val streamViewModel = viewModel() diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 786ce3cc4..5d08a84fd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -861,6 +861,8 @@ NewPipeExtractor is a library for extracting things from streaming sites. It is a core component of NewPipe, but could be used independently. Sort by Button to clear watch history + Thumbnail for playlist %1$s + Thumbnail for stream %1$s %d comment %d comments