Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusProperties
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.tv.material3.MaterialTheme
import androidx.tv.material3.Text
Expand All @@ -30,20 +31,23 @@ import kotlinx.coroutines.flow.first

@Composable
internal fun TvPodcastGridScaffold(
title: String,
itemKeys: List<Any>,
modifier: Modifier = Modifier,
title: String? = null,
horizontalContentPadding: Dp = 32.dp,
autoFocusFirstItem: Boolean = false,
restoreFocusTrigger: Int = 0,
itemContent: @Composable (index: Int, itemModifier: Modifier) -> Unit,
) {
Column(modifier = modifier) {
Text(
text = title,
style = MaterialTheme.tvTypography.title3,
color = MaterialTheme.tvColors.textPrimary,
modifier = Modifier.padding(start = 32.dp, top = 8.dp, bottom = 10.dp),
)
if (title != null) {
Text(
text = title,
style = MaterialTheme.tvTypography.title3,
color = MaterialTheme.tvColors.textPrimary,
modifier = Modifier.padding(start = horizontalContentPadding, top = 8.dp, bottom = 10.dp),
)
}
Comment thread
sztomek marked this conversation as resolved.
val gridState = rememberLazyGridState()
var lastFocusedKey by rememberSaveable { mutableStateOf<String?>(null) }
val focusRequesters = remember(itemKeys.size) { List(itemKeys.size) { FocusRequester() } }
Expand Down Expand Up @@ -72,7 +76,7 @@ internal fun TvPodcastGridScaffold(
columns = GridCells.Fixed(GRID_COLUMNS),
horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(start = 32.dp, top = 16.dp, end = 32.dp, bottom = 32.dp),
contentPadding = PaddingValues(start = horizontalContentPadding, top = 16.dp, end = horizontalContentPadding, bottom = 32.dp),
modifier = Modifier
.focusRequester(gridFocusRequester)
.focusGroup()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ fun TvTabBar(
currentTabPosition = currentTabPosition,
doesTabRowHaveFocus = doesTabRowHaveFocus,
activeColor = MaterialTheme.tvColors.backgroundActive,
inactiveColor = MaterialTheme.tvColors.backgroundActive,
inactiveColor = MaterialTheme.tvColors.backgroundBase,
Comment thread
sztomek marked this conversation as resolved.
)
}
},
Expand All @@ -107,7 +107,7 @@ fun TvTabBar(
.then(if (index == selectedTabIndex) Modifier.focusRequester(focusRequester) else Modifier),
colors = TabDefaults.pillIndicatorTabColors(
contentColor = MaterialTheme.tvColors.textPrimary,
selectedContentColor = MaterialTheme.tvColors.textPrimaryActive,
selectedContentColor = MaterialTheme.tvColors.textPrimary,
focusedContentColor = MaterialTheme.tvColors.textPrimary,
focusedSelectedContentColor = MaterialTheme.tvColors.textPrimaryActive,
inactiveContentColor = MaterialTheme.tvColors.textPrimary,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,11 @@ internal fun TvSearchEpisodeRow(
}

@Composable
private fun TvSearchEpisodeCard(
internal fun TvSearchEpisodeCard(
episode: ImprovedSearchResultItem.EpisodeItem,
onClick: () -> Unit,
modifier: Modifier = Modifier,
onLongClick: (() -> Unit)? = null,
) {
var isFocused by remember { mutableStateOf(false) }
val textPrimary = if (isFocused) MaterialTheme.tvColors.textPrimaryActive else MaterialTheme.tvColors.textPrimary
Expand All @@ -79,6 +80,7 @@ private fun TvSearchEpisodeCard(

TvTile(
onClick = onClick,
onLongClick = onLongClick,
scale = CardDefaults.scale(focusedScale = 1.02f),
shape = CardDefaults.shape(shape = RoundedCornerShape(12.dp)),
colors = CardDefaults.colors(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package au.com.shiftyjelly.pocketcasts.search

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.focusRestorer
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Devices
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.tv.material3.LocalContentColor
import androidx.tv.material3.MaterialTheme
import androidx.tv.material3.Tab
import androidx.tv.material3.TabDefaults
import androidx.tv.material3.TabRow
import androidx.tv.material3.TabRowDefaults
import androidx.tv.material3.Text
import au.com.shiftyjelly.pocketcasts.theme.TvTheme
import au.com.shiftyjelly.pocketcasts.theme.tvColors
import au.com.shiftyjelly.pocketcasts.theme.tvTypography

@Composable
internal fun TvSearchFilters(
selected: TvSearchFilter,
onFilterSelect: (TvSearchFilter) -> Unit,
modifier: Modifier = Modifier,
) {
Row(
modifier = modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
) {
FilterDivider(modifier = Modifier.weight(1f))
Spacer(modifier = Modifier.width(20.dp))
TvSearchFilterPills(selected = selected, onFilterSelect = onFilterSelect)
Spacer(modifier = Modifier.width(20.dp))
FilterDivider(modifier = Modifier.weight(1f))
}
}

@Composable
private fun TvSearchFilterPills(
selected: TvSearchFilter,
onFilterSelect: (TvSearchFilter) -> Unit,
) {
val selectedIndex = TvSearchFilter.entries.indexOf(selected)
Box(
modifier = Modifier
.background(MaterialTheme.tvColors.backgroundSunken, RoundedCornerShape(percent = 50))
.padding(3.dp),
) {
TabRow(
selectedTabIndex = selectedIndex,
modifier = Modifier.focusRestorer(),
containerColor = Color.Transparent,
indicator = @Composable { tabPositions, doesTabRowHaveFocus ->
tabPositions.getOrNull(selectedIndex)?.let { currentTabPosition ->
TabRowDefaults.PillIndicator(
currentTabPosition = currentTabPosition,
doesTabRowHaveFocus = doesTabRowHaveFocus,
activeColor = MaterialTheme.tvColors.backgroundActive,
inactiveColor = MaterialTheme.tvColors.backgroundBase,
)
}
},
) {
TvSearchFilter.entries.forEachIndexed { index, filter ->
Tab(
selected = index == selectedIndex,
onFocus = { onFilterSelect(filter) },
onClick = { onFilterSelect(filter) },
modifier = Modifier
.height(44.dp)
.padding(horizontal = 21.dp),
colors = TabDefaults.pillIndicatorTabColors(
contentColor = MaterialTheme.tvColors.textPrimary,
selectedContentColor = MaterialTheme.tvColors.textPrimary,
focusedContentColor = MaterialTheme.tvColors.textPrimary,
focusedSelectedContentColor = MaterialTheme.tvColors.textPrimaryActive,
inactiveContentColor = MaterialTheme.tvColors.textPrimary,
),
) {
Box(
modifier = Modifier.fillMaxHeight(),
contentAlignment = Alignment.Center,
) {
Text(
text = stringResource(filter.labelRes),
color = LocalContentColor.current,
style = MaterialTheme.tvTypography.caption1,
)
}
}
}
}
}
Comment thread
sztomek marked this conversation as resolved.
}

@Composable
private fun FilterDivider(modifier: Modifier = Modifier) {
Box(
modifier = modifier
.height(1.dp)
.background(MaterialTheme.tvColors.overlayBorder),
)
}

@Preview(device = Devices.TV_1080p)
@Composable
private fun TvSearchFiltersPreview() {
TvTheme {
TvSearchFilters(
selected = TvSearchFilter.Podcasts,
onFilterSelect = {},
modifier = Modifier
.background(MaterialTheme.tvColors.backgroundSunken)
.padding(48.dp),
)
}
}
Loading