diff --git a/Jetcaster/core/designsystem/src/main/java/com/example/jetcaster/designsystem/component/HtmlTextContainer.kt b/Jetcaster/core/designsystem/src/main/java/com/example/jetcaster/designsystem/component/HtmlTextContainer.kt index e0e91040fe..1002127c98 100644 --- a/Jetcaster/core/designsystem/src/main/java/com/example/jetcaster/designsystem/component/HtmlTextContainer.kt +++ b/Jetcaster/core/designsystem/src/main/java/com/example/jetcaster/designsystem/component/HtmlTextContainer.kt @@ -31,7 +31,7 @@ fun HtmlTextContainer( text: String, content: @Composable (AnnotatedString) -> Unit ) { - val annotatedString = remember(key1 = text) { + val annotatedString = remember(text) { AnnotatedString.fromHtml(htmlString = text) } SelectionContainer { diff --git a/Jetcaster/glancewidget/src/main/java/com/example/jetcaster/glancewidget/JetcasterAppWidget.kt b/Jetcaster/glancewidget/src/main/java/com/example/jetcaster/glancewidget/JetcasterAppWidget.kt index 0fa21520e8..d39f0064fd 100644 --- a/Jetcaster/glancewidget/src/main/java/com/example/jetcaster/glancewidget/JetcasterAppWidget.kt +++ b/Jetcaster/glancewidget/src/main/java/com/example/jetcaster/glancewidget/JetcasterAppWidget.kt @@ -255,7 +255,7 @@ private fun WidgetAsyncImage( val context = LocalContext.current val scope = rememberCoroutineScope() - LaunchedEffect(key1 = uri) { + LaunchedEffect(uri) { val request = ImageRequest.Builder(context) .data(uri) .size(200, 200) diff --git a/Jetcaster/gradle/libs.versions.toml b/Jetcaster/gradle/libs.versions.toml index c9043348c6..095effcff4 100644 --- a/Jetcaster/gradle/libs.versions.toml +++ b/Jetcaster/gradle/libs.versions.toml @@ -7,10 +7,10 @@ accompanist = "0.36.0" androidGradlePlugin = "8.7.0" androidx-activity-compose = "1.9.2" androidx-appcompat = "1.7.0" -androidx-benchmark = "1.2.4" -androidx-benchmark-junit4 = "1.2.4" +androidx-benchmark = "1.3.1" +androidx-benchmark-junit4 = "1.3.1" androidx-compose-bom = "2024.09.03" -androidx-constraintlayout = "1.1.0-alpha13" +androidx-constraintlayout = "1.1.0-beta01" androidx-core-splashscreen = "1.0.1" androidx-corektx = "1.13.1" androidx-glance = "1.1.0" @@ -22,10 +22,10 @@ androidx-palette = "1.0.0" androidx-test = "1.6.1" androidx-test-espresso = "3.6.1" androidx-test-ext-junit = "1.2.1" -androidx-test-ext-truth = "1.5.0" +androidx-test-ext-truth = "1.6.0" androidx-tv-foundation = "1.0.0-alpha11" androidx-tv-material = "1.0.0" -androidx-wear-compose = "1.3.1" +androidx-wear-compose = "1.4.0" androidx-window = "1.3.0" androidxHiltNavigationCompose = "1.2.0" androix-test-uiautomator = "2.3.0" @@ -33,13 +33,13 @@ coil = "2.6.0" # @keep compileSdk = "34" coroutines = "1.9.0" -google-maps = "18.2.0" +google-maps = "19.0.0" gradle-versions = "0.51.0" hilt = "2.51.1" hiltExt = "1.2.0" horologist = "0.6.19" # @pin When updating to AGP 7.4.0-alpha10 and up we can update this https://developer.android.com/studio/write/java8-support#library-desugaring-versions -jdkDesugar = "1.2.2" +jdkDesugar = "2.1.2" junit = "4.13.2" kotlin = "2.0.20" kotlinx-serialization-json = "1.7.3" @@ -48,12 +48,12 @@ ksp = "2.0.20-1.0.24" maps-compose = "3.1.1" # @keep minSdk = "21" -okhttp = "4.11.0" -play-services-wearable = "18.1.0" +okhttp = "4.12.0" +play-services-wearable = "18.2.0" robolectric = "4.13" roborazzi = "1.12.0" rome = "1.18.0" -room = "2.6.0" +room = "2.6.1" secrets = "2.0.1" # @keep targetSdk = "33" diff --git a/Jetcaster/mobile/src/main/java/com/example/jetcaster/ui/home/Home.kt b/Jetcaster/mobile/src/main/java/com/example/jetcaster/ui/home/Home.kt index 46a0cffbf0..5b626e675e 100644 --- a/Jetcaster/mobile/src/main/java/com/example/jetcaster/ui/home/Home.kt +++ b/Jetcaster/mobile/src/main/java/com/example/jetcaster/ui/home/Home.kt @@ -83,6 +83,7 @@ import androidx.compose.material3.adaptive.occludingVerticalHingeBounds import androidx.compose.material3.adaptive.separatingVerticalHingeBounds import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope @@ -378,22 +379,27 @@ private fun HomeAppBar( isExpanded: Boolean, modifier: Modifier = Modifier, ) { + val viewModel: HomeViewModel = hiltViewModel() + + val searchText by viewModel.searchText.collectAsState() + val isSearching by viewModel.isSearching.collectAsState() + Row( horizontalArrangement = Arrangement.End, modifier = modifier .fillMaxWidth() .background(Color.Transparent) - .padding(end = 16.dp, top = 8.dp, bottom = 8.dp) + .padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 8.dp) ) { SearchBar( - query = "", - onQueryChange = {}, + query = searchText, + onQueryChange = { viewModel.onSearchTextChange(it) }, placeholder = { Text(stringResource(id = R.string.search_for_a_podcast)) }, - onSearch = {}, + onSearch = { viewModel.onSearchTextChange(it) }, active = false, - onActiveChange = {}, + onActiveChange = { viewModel.onToggleSearch() }, leadingIcon = { Icon( imageVector = Icons.Default.Search, @@ -436,7 +442,7 @@ private fun HomeScreen( modifier: Modifier = Modifier ) { // Effect that changes the home category selection when there are no subscribed podcasts - LaunchedEffect(key1 = homeState.featuredPodcasts) { + LaunchedEffect(homeState.featuredPodcasts) { if (homeState.featuredPodcasts.isEmpty()) { homeState.onHomeCategorySelected(HomeCategory.Discover) } diff --git a/Jetcaster/mobile/src/main/java/com/example/jetcaster/ui/home/HomeViewModel.kt b/Jetcaster/mobile/src/main/java/com/example/jetcaster/ui/home/HomeViewModel.kt index 3d5450464d..2e0422140a 100644 --- a/Jetcaster/mobile/src/main/java/com/example/jetcaster/ui/home/HomeViewModel.kt +++ b/Jetcaster/mobile/src/main/java/com/example/jetcaster/ui/home/HomeViewModel.kt @@ -43,6 +43,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.shareIn @@ -72,6 +73,14 @@ class HomeViewModel @Inject constructor( // Holds the view state if the UI is refreshing for new data private val refreshing = MutableStateFlow(false) + //first state whether the search is happening or not + private val _isSearching = MutableStateFlow(false) + val isSearching = _isSearching.asStateFlow() + + //second state the text typed by the user + private val _searchText = MutableStateFlow("") + val searchText = _searchText.asStateFlow() + private val subscribedPodcasts = podcastStore.followedPodcastsSortedByLastEpisode(limit = 10) .shareIn(viewModelScope, SharingStarted.WhileSubscribed()) @@ -149,6 +158,17 @@ class HomeViewModel @Inject constructor( } } + fun onSearchTextChange(text: String) { + _searchText.value = text + } + + fun onToggleSearch() { + _isSearching.value = !_isSearching.value + if (!_isSearching.value) { + onSearchTextChange("") + } + } + fun onCategorySelected(category: CategoryInfo) { _selectedCategory.value = category } diff --git a/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/component/Background.kt b/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/component/Background.kt index 4cdd5ccb52..30c05b5399 100644 --- a/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/component/Background.kt +++ b/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/component/Background.kt @@ -70,7 +70,7 @@ private fun Background( ) { ImageBackgroundRadialGradientScrim( url = imageUrl, - colors = listOf(Color.Black, Color.Transparent), + colors = listOf(Color(0xE0000000), Color(0xB0000000)), modifier = modifier, ) } diff --git a/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/component/ButtonWithIcon.kt b/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/component/ButtonWithIcon.kt index b5fa71653c..f72f456523 100644 --- a/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/component/ButtonWithIcon.kt +++ b/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/component/ButtonWithIcon.kt @@ -16,6 +16,7 @@ package com.example.jetcaster.tv.ui.component +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.width import androidx.compose.runtime.Composable @@ -36,10 +37,10 @@ internal fun ButtonWithIcon( modifier: Modifier = Modifier, scale: ButtonScale = ButtonDefaults.scale(), ) { - Button(onClick = onClick, modifier = modifier, scale = scale) { + Button(onClick = onClick, contentPadding = PaddingValues(start = 6.dp, end = 16.dp), modifier = modifier, scale = scale) { Icon( icon, - contentDescription = null, + contentDescription = null ) Spacer(modifier = Modifier.width(6.dp)) Text(text = label) diff --git a/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/component/EpisodeCard.kt b/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/component/EpisodeCard.kt index ddde4bcb56..75a6cf7f12 100644 --- a/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/component/EpisodeCard.kt +++ b/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/component/EpisodeCard.kt @@ -30,9 +30,9 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp +import androidx.tv.material3.Border import androidx.tv.material3.Card import androidx.tv.material3.CardDefaults -import androidx.tv.material3.CardScale import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text import androidx.tv.material3.WideCardContainer @@ -72,8 +72,18 @@ private fun EpisodeThumbnail( Card( onClick = onClick, interactionSource = interactionSource, - scale = CardScale.None, + scale = CardDefaults.scale(scale = 0.85f, focusedScale = 1.0f), shape = CardDefaults.shape(RoundedCornerShape(12.dp)), + border = CardDefaults.border( + focusedBorder = Border( + border = _root_ide_package_.androidx.compose.foundation.BorderStroke( + 3.dp, + color = MaterialTheme.colorScheme.border + ), + inset = 3.dp, + shape = RoundedCornerShape(15.dp) + ) + ), modifier = modifier, ) { Thumbnail(episode = playerEpisode, size = JetcasterAppDefaults.thumbnailSize.episode) diff --git a/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/component/EpisodeDateAndDuration.kt b/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/component/EpisodeDateAndDuration.kt index 0ce6dbeaf7..72a30b10cc 100644 --- a/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/component/EpisodeDateAndDuration.kt +++ b/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/component/EpisodeDateAndDuration.kt @@ -37,7 +37,7 @@ internal fun EpisodeDataAndDuration( offsetDateTime: OffsetDateTime, duration: Duration, modifier: Modifier = Modifier, - style: TextStyle = MaterialTheme.typography.bodySmall, + style: TextStyle = MaterialTheme.typography.bodyMedium, ) { Text( text = stringResource( diff --git a/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/component/PodcastCard.kt b/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/component/PodcastCard.kt index 3524cae812..ac6bb4902c 100644 --- a/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/component/PodcastCard.kt +++ b/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/component/PodcastCard.kt @@ -21,9 +21,10 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import androidx.tv.material3.Border import androidx.tv.material3.Card import androidx.tv.material3.CardDefaults -import androidx.tv.material3.CardScale +import androidx.tv.material3.MaterialTheme import androidx.tv.material3.StandardCardContainer import androidx.tv.material3.Text import com.example.jetcaster.core.model.PodcastInfo @@ -40,8 +41,18 @@ internal fun PodcastCard( Card( onClick = onClick, interactionSource = it, - scale = CardScale.None, - shape = CardDefaults.shape(RoundedCornerShape(12.dp)) + scale = CardDefaults.scale(scale = 0.9f, focusedScale = 1.0f), + shape = CardDefaults.shape(RoundedCornerShape(16.dp)), + border = CardDefaults.border( + focusedBorder = Border( + border = _root_ide_package_.androidx.compose.foundation.BorderStroke( + 3.dp, + color = MaterialTheme.colorScheme.border + ), + inset = 3.dp, + shape = RoundedCornerShape(19.dp) + ), + ) ) { Thumbnail( podcastInfo = podcastInfo, diff --git a/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/discover/DiscoverScreen.kt b/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/discover/DiscoverScreen.kt index a0727cd559..55941f0007 100644 --- a/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/discover/DiscoverScreen.kt +++ b/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/discover/DiscoverScreen.kt @@ -87,7 +87,6 @@ fun DiscoverScreen( private fun CatalogWithCategorySelection( categoryInfoList: CategoryInfoList, podcastList: PodcastList, - selectedCategory: CategoryInfo, latestEpisodeList: EpisodeList, onPodcastSelected: (PodcastInfo) -> Unit, diff --git a/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/player/PlayerScreen.kt b/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/player/PlayerScreen.kt index bf81680771..5f210d000b 100644 --- a/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/player/PlayerScreen.kt +++ b/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/player/PlayerScreen.kt @@ -17,7 +17,7 @@ package com.example.jetcaster.tv.ui.player import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.focusable +import androidx.compose.foundation.focusGroup import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -40,15 +40,19 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment +import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.draw.drawWithCache import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusProperties import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.focus.focusRestorer import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.graphics.BlendMode import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.drawscope.DrawScope +import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.Dp @@ -63,6 +67,7 @@ import com.example.jetcaster.core.player.EpisodePlayerState import com.example.jetcaster.core.player.model.PlayerEpisode import com.example.jetcaster.tv.R import com.example.jetcaster.tv.model.EpisodeList +import com.example.jetcaster.tv.ui.Screen import com.example.jetcaster.tv.ui.component.BackgroundContainer import com.example.jetcaster.tv.ui.component.EnqueueButton import com.example.jetcaster.tv.ui.component.EpisodeDetails @@ -76,10 +81,11 @@ import com.example.jetcaster.tv.ui.component.RewindButton import com.example.jetcaster.tv.ui.component.Seekbar import com.example.jetcaster.tv.ui.component.SkipButton import com.example.jetcaster.tv.ui.theme.JetcasterAppDefaults -import java.time.Duration import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch +import java.time.Duration +@OptIn(ExperimentalComposeUiApi::class) @Composable fun PlayerScreen( backToHome: () -> Unit, @@ -106,12 +112,13 @@ fun PlayerScreen( rewind = playScreenViewModel::rewind, enqueue = playScreenViewModel::enqueue, playEpisode = playScreenViewModel::play, - showDetails = showDetails, + showDetails = showDetails ) } } } +@ExperimentalComposeUiApi @Composable private fun Player( episodePlayerState: EpisodePlayerState, @@ -127,7 +134,7 @@ private fun Player( modifier: Modifier = Modifier, autoStart: Boolean = true ) { - LaunchedEffect(key1 = autoStart) { + LaunchedEffect(autoStart) { if (autoStart && !episodePlayerState.isPlaying) { play() } @@ -155,6 +162,7 @@ private fun Player( } } +@ExperimentalComposeUiApi @OptIn(ExperimentalFoundationApi::class) @Composable private fun EpisodePlayerWithBackground( @@ -173,18 +181,11 @@ private fun EpisodePlayerWithBackground( playEpisode: (PlayerEpisode) -> Unit, modifier: Modifier = Modifier ) { - val episodePlayer = remember { FocusRequester() } - - LaunchedEffect(Unit) { - episodePlayer.requestFocus() - } - BackgroundContainer( playerEpisode = playerEpisode, modifier = modifier, contentAlignment = Alignment.Center ) { - EpisodePlayer( playerEpisode = playerEpisode, isPlaying = isPlaying, @@ -197,7 +198,6 @@ private fun EpisodePlayerWithBackground( rewind = rewind, enqueue = enqueue, showDetails = showDetails, - focusRequester = episodePlayer, modifier = Modifier .padding(JetcasterAppDefaults.overScanMargin.player.intoPaddingValues()) ) @@ -213,6 +213,7 @@ private fun EpisodePlayerWithBackground( } } +@ExperimentalComposeUiApi @OptIn(ExperimentalFoundationApi::class) @Composable private fun EpisodePlayer( @@ -229,8 +230,7 @@ private fun EpisodePlayer( showDetails: (PlayerEpisode) -> Unit, modifier: Modifier = Modifier, bringIntoViewRequester: BringIntoViewRequester = remember { BringIntoViewRequester() }, - coroutineScope: CoroutineScope = rememberCoroutineScope(), - focusRequester: FocusRequester = remember { FocusRequester() } + coroutineScope: CoroutineScope = rememberCoroutineScope() ) { Column( verticalArrangement = Arrangement.spacedBy(JetcasterAppDefaults.gap.section), @@ -264,8 +264,7 @@ private fun EpisodePlayer( previous = previous, next = next, skip = skip, - rewind = rewind, - focusRequester = focusRequester + rewind = rewind ) } } @@ -291,6 +290,7 @@ private fun EpisodeControl( } } +@ExperimentalComposeUiApi @Composable private fun PlayerControl( isPlaying: Boolean, @@ -302,11 +302,13 @@ private fun PlayerControl( next: () -> Unit, skip: () -> Unit, rewind: () -> Unit, - modifier: Modifier = Modifier, - focusRequester: FocusRequester = remember { FocusRequester() } + modifier: Modifier = Modifier ) { val playPauseButton = remember { FocusRequester() } + // Flag to determine if it is safe to set initial focus or not + var isSafeToSetInitialFocus by remember { mutableStateOf(false) } + Column( verticalArrangement = Arrangement.spacedBy(JetcasterAppDefaults.gap.item), modifier = modifier, @@ -318,14 +320,13 @@ private fun PlayerControl( ), verticalAlignment = Alignment.CenterVertically, modifier = Modifier - .fillMaxWidth() - .focusRequester(focusRequester) - .onFocusChanged { - if (it.isFocused) { - playPauseButton.requestFocus() + .focusProperties { + enter = { + playPauseButton } } - .focusable(), + .focusGroup() + .fillMaxWidth(), ) { PreviousButton( onClick = previous, @@ -347,6 +348,10 @@ private fun PlayerControl( modifier = Modifier .size(JetcasterAppDefaults.iconButtonSize.large.intoDpSize()) .focusRequester(playPauseButton) + .onGloballyPositioned { + // Set the flag true if the element is in the viewport + isSafeToSetInitialFocus = true + } ) SkipButton( onClick = skip, @@ -361,6 +366,12 @@ private fun PlayerControl( ElapsedTimeIndicator(timeElapsed, length, skip, rewind) } } + LaunchedEffect(isSafeToSetInitialFocus) { + // Your app should set initial focus only if the UI element is in viewport + if (isSafeToSetInitialFocus) { + playPauseButton.requestFocus() + } + } } @Composable diff --git a/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/podcast/PodcastDetailsScreen.kt b/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/podcast/PodcastDetailsScreen.kt index 26e84b7dc8..0d9e0a7f9e 100644 --- a/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/podcast/PodcastDetailsScreen.kt +++ b/Jetcaster/tv/src/main/java/com/example/jetcaster/tv/ui/podcast/PodcastDetailsScreen.kt @@ -26,6 +26,7 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape @@ -201,13 +202,16 @@ private fun PodcastInfo( ) Text( text = podcastInfo.title, + maxLines = 2, style = MaterialTheme.typography.headlineSmall, ) Text( text = podcastInfo.description, - maxLines = 2, + maxLines = 3, overflow = TextOverflow.Ellipsis, - style = MaterialTheme.typography.bodyMedium + style = MaterialTheme.typography.bodyMedium, + modifier = Modifier + .padding(top = JetcasterAppDefaults.gap.paragraph) ) ToggleSubscriptionButton( podcastInfo, @@ -283,8 +287,8 @@ private fun EpisodeListItem( onInfoClicked: () -> Unit, onEnqueueClicked: () -> Unit, modifier: Modifier = Modifier, - borderWidth: Dp = 2.dp, - cornerRadius: Dp = 12.dp, + borderWidth: Dp = 3.dp, + cornerRadius: Dp = 32.dp, ) { var hasFocus by remember { mutableStateOf(false) @@ -321,7 +325,7 @@ private fun EpisodeListItem( .border(borderWidth, borderColor, shape) .background(backgroundColor) .shadow(elevation, shape) - .padding(start = 12.dp, top = 12.dp, bottom = 12.dp, end = 16.dp) + .padding(start = 18.dp, top = 16.dp, bottom = 16.dp, end = 16.dp) ) } @@ -339,7 +343,6 @@ private fun EpisodeListItemContentLayer( contentAlignment = Alignment.CenterStart, modifier = modifier ) { - Column( verticalArrangement = Arrangement.spacedBy(JetcasterAppDefaults.gap.tiny), ) { @@ -352,14 +355,14 @@ private fun EpisodeListItemContentLayer( ) { PlayButton( onClick = onEpisodeSelected, - modifier = Modifier.focusRequester(playButton) + modifier = Modifier.focusRequester(playButton).height(36.dp) ) if (duration != null) { EpisodeDataAndDuration(playerEpisode.published, duration) } Spacer(modifier = Modifier.weight(1f)) - EnqueueButton(onClick = onEnqueueClicked) - InfoButton(onClick = onInfoClicked) + EnqueueButton(onClick = onEnqueueClicked, modifier = Modifier.size(36.dp)) + InfoButton(onClick = onInfoClicked, modifier = Modifier.size(36.dp)) } } }