diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/UiConstants.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/UiConstants.kt index 39b2048b..5af35e03 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/UiConstants.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/UiConstants.kt @@ -1,7 +1,6 @@ package com.github.damontecres.wholphin.ui import android.content.res.Configuration.UI_MODE_TYPE_TELEVISION -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.Font @@ -66,14 +65,6 @@ val SlimItemFields = ItemFields.SORT_NAME, ) -val DefaultButtonPadding = - PaddingValues( - start = 12.dp / 2, - top = 10.dp / 2, - end = 16.dp / 2, - bottom = 10.dp / 2, - ) - object Cards { val height2x3 = 172.dp val playedPercentHeight = 6.dp diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/Button.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/Button.kt new file mode 100644 index 00000000..c65069bd --- /dev/null +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/Button.kt @@ -0,0 +1,173 @@ +// This file was inspired by related Button source files from +// https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-main/tv/tv-material/src/main/java/androidx/tv/material3 + +package com.github.damontecres.wholphin.ui.components + +import androidx.annotation.StringRes +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.runtime.Composable +import androidx.compose.runtime.NonRestartableComposable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.semantics.role +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.tv.material3.Border +import androidx.tv.material3.ClickableSurfaceBorder +import androidx.tv.material3.ClickableSurfaceColors +import androidx.tv.material3.ClickableSurfaceDefaults +import androidx.tv.material3.ClickableSurfaceGlow +import androidx.tv.material3.ClickableSurfaceScale +import androidx.tv.material3.ClickableSurfaceShape +import androidx.tv.material3.MaterialTheme +import androidx.tv.material3.ProvideTextStyle +import androidx.tv.material3.Surface +import androidx.tv.material3.Text + +@Composable +fun Button( + onClick: () -> Unit, + modifier: Modifier = Modifier, + onLongClick: (() -> Unit)? = null, + enabled: Boolean = true, + scale: ClickableSurfaceScale = ClickableSurfaceDefaults.scale(), + glow: ClickableSurfaceGlow = ClickableSurfaceDefaults.glow(), + shape: ClickableSurfaceShape = + ClickableSurfaceDefaults.shape( + shape = CircleShape, + ), + colors: ClickableSurfaceColors = + ClickableSurfaceDefaults.colors( + containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.8f), + contentColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.8f), + focusedContainerColor = MaterialTheme.colorScheme.onSurface, + focusedContentColor = MaterialTheme.colorScheme.inverseOnSurface, + pressedContainerColor = MaterialTheme.colorScheme.onSurface, + pressedContentColor = MaterialTheme.colorScheme.inverseOnSurface, + disabledContainerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.4f), + disabledContentColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.4f), + ), + tonalElevation: Dp = 0.dp, + border: ClickableSurfaceBorder = + ClickableSurfaceDefaults.border( + border = Border.None, + focusedBorder = Border.None, + pressedBorder = Border.None, + disabledBorder = Border.None, + focusedDisabledBorder = + Border( + border = + BorderStroke( + width = 1.5.dp, + color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.2f), + ), + shape = CircleShape, + ), + ), + contentPadding: PaddingValues = DefaultButtonPadding, + contentHeight: Dp = MinButtonSize, + interactionSource: MutableInteractionSource? = null, + content: @Composable RowScope.() -> Unit, +) { + Surface( + modifier = modifier.semantics { role = Role.Button }, + onClick = onClick, + onLongClick = onLongClick, + enabled = enabled, + scale = scale, + glow = glow, + shape = shape, + colors = colors, + tonalElevation = tonalElevation, + border = border, + interactionSource = interactionSource, + ) { + ProvideTextStyle(value = MaterialTheme.typography.labelLarge) { + Row( + modifier = + Modifier + .padding(contentPadding) + .height(contentHeight), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically, + content = content, + ) + } + } +} + +@Composable +@NonRestartableComposable +fun TextButton( + onClick: () -> Unit, + modifier: Modifier = Modifier, + onLongClick: (() -> Unit)? = null, + enabled: Boolean = true, + contentPadding: PaddingValues = + PaddingValues( + start = 8.dp, + top = 4.dp, + end = 8.dp, + bottom = 4.dp, + ), + contentHeight: Dp = 32.dp, + interactionSource: MutableInteractionSource? = null, + content: @Composable RowScope.() -> Unit, +) = Button( + onClick = onClick, + modifier = modifier, + onLongClick = onLongClick, + enabled = enabled, + contentPadding = contentPadding, + contentHeight = contentHeight, + interactionSource = interactionSource, + content = content, +) + +@Composable +fun TextButton( + @StringRes stringRes: Int, + onClick: () -> Unit, + modifier: Modifier = Modifier, + onLongClick: (() -> Unit)? = null, + enabled: Boolean = true, + contentPadding: PaddingValues = + PaddingValues( + start = 8.dp, + top = 4.dp, + end = 8.dp, + bottom = 4.dp, + ), + contentHeight: Dp = 32.dp, + interactionSource: MutableInteractionSource? = null, +) = Button( + onClick = onClick, + modifier = modifier, + onLongClick = onLongClick, + enabled = enabled, + contentPadding = contentPadding, + contentHeight = contentHeight, + interactionSource = interactionSource, + content = { + Text(text = stringResource(stringRes)) + }, +) + +val DefaultButtonPadding = + PaddingValues( + start = 4.dp, + top = 4.dp, + end = 4.dp, + bottom = 4.dp, + ) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/Dialogs.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/Dialogs.kt index b2363059..e6af6443 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/Dialogs.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/Dialogs.kt @@ -45,7 +45,6 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties -import androidx.tv.material3.Button import androidx.tv.material3.Icon import androidx.tv.material3.ListItem import androidx.tv.material3.LocalContentColor @@ -443,20 +442,14 @@ fun ConfirmDialogContent( horizontalArrangement = Arrangement.SpaceEvenly, modifier = Modifier.fillMaxWidth(), ) { - Button( + TextButton( + stringRes = R.string.cancel, onClick = onCancel, - ) { - Text( - text = stringResource(R.string.cancel), - ) - } - Button( + ) + TextButton( + stringRes = R.string.confirm, onClick = onConfirm, - ) { - Text( - text = stringResource(R.string.confirm), - ) - } + ) } } } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/ErrorMessage.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/ErrorMessage.kt index f833e228..76c9e097 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/ErrorMessage.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/ErrorMessage.kt @@ -10,7 +10,6 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.ViewModel -import androidx.tv.material3.Button import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text import com.github.damontecres.wholphin.R @@ -56,15 +55,12 @@ fun ErrorMessage( color = MaterialTheme.colorScheme.error, style = MaterialTheme.typography.titleMedium, ) - Button( + TextButton( + stringRes = R.string.send_app_logs, onClick = { viewModel.sendLogs() }, - ) { - Text( - text = stringResource(R.string.send_app_logs), - ) - } + ) message?.let { Text( text = it, diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/FilterByButton.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/FilterByButton.kt index b6dd6474..7f8553ac 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/FilterByButton.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/FilterByButton.kt @@ -4,9 +4,13 @@ import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.collectIsFocusedAsState import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredSizeIn import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.widthIn import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.Delete @@ -18,17 +22,16 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalResources import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.tv.material3.Button import androidx.tv.material3.Icon import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text @@ -46,8 +49,9 @@ import com.github.damontecres.wholphin.data.filter.PlayedFilter import com.github.damontecres.wholphin.data.filter.VideoTypeFilter import com.github.damontecres.wholphin.data.filter.YearFilter import com.github.damontecres.wholphin.data.model.GetItemsFilter -import com.github.damontecres.wholphin.ui.DefaultButtonPadding import com.github.damontecres.wholphin.ui.FontAwesome +import com.github.damontecres.wholphin.ui.PreviewTvSpec +import com.github.damontecres.wholphin.ui.theme.WholphinTheme import com.github.damontecres.wholphin.ui.tryRequestFocus import java.util.UUID @@ -353,35 +357,64 @@ fun ExpandableFilterButton( interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, iconColor: Color = Color.Unspecified, ) { - val resources = LocalResources.current val isFocused = interactionSource.collectIsFocusedAsState().value Button( onClick = onClick, - modifier = modifier.heightIn(min = 40.dp), - contentPadding = DefaultButtonPadding, + modifier = + modifier.requiredSizeIn( + minWidth = MinButtonSize, + minHeight = MinButtonSize, + maxHeight = MinButtonSize, + ), + contentPadding = PaddingValues(0.dp), // DefaultButtonPadding, interactionSource = interactionSource, ) { - Text( - text = stringResource(R.string.fa_filter), - style = MaterialTheme.typography.titleSmall, - color = iconColor, - fontSize = 16.sp, - fontFamily = FontAwesome, - textAlign = TextAlign.Center, - modifier = Modifier, - ) + Box( + modifier = + Modifier + .fillMaxHeight() + .widthIn(min = if (filterCount > 0 || isFocused) (MinButtonSize - 12.dp) else MinButtonSize), + ) { + Text( + text = stringResource(R.string.fa_filter), + style = MaterialTheme.typography.titleSmall, + color = iconColor, + fontSize = 16.sp, + fontFamily = FontAwesome, + textAlign = TextAlign.Center, + modifier = Modifier.align(Alignment.Center), + ) + } AnimatedVisibility(filterCount > 0) { Text( text = filterCount.toString(), style = MaterialTheme.typography.titleSmall, - modifier = Modifier.padding(start = 4.dp), + modifier = Modifier.padding(end = 4.dp), ) } AnimatedVisibility(isFocused) { Text( text = stringResource(R.string.filter), style = MaterialTheme.typography.titleSmall, - modifier = Modifier.padding(start = 4.dp), + modifier = Modifier.padding(start = 4.dp, end = 4.dp), + ) + } + } +} + +@PreviewTvSpec +@Composable +private fun ExpandableFilterButtonPreview() { + WholphinTheme { + Column { + ExpandableFilterButton( + filterCount = 2, + onClick = {}, + ) + + ExpandableFilterButton( + filterCount = 0, + onClick = {}, ) } } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/PlayButtons.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/PlayButtons.kt index 6790e627..6a14fdbf 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/PlayButtons.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/PlayButtons.kt @@ -6,10 +6,14 @@ import androidx.compose.foundation.focusGroup import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.collectIsFocusedAsState import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredSizeIn import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyRow import androidx.compose.material.icons.Icons @@ -18,6 +22,7 @@ import androidx.compose.material.icons.filled.PlayArrow import androidx.compose.material.icons.filled.Refresh import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.FocusState @@ -31,16 +36,18 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.tv.material3.Button import androidx.tv.material3.Icon import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text import com.github.damontecres.wholphin.R -import com.github.damontecres.wholphin.ui.DefaultButtonPadding import com.github.damontecres.wholphin.ui.FontAwesome import com.github.damontecres.wholphin.ui.PreviewTvSpec +import com.github.damontecres.wholphin.ui.data.SortAndDirection import com.github.damontecres.wholphin.ui.ifElse +import com.github.damontecres.wholphin.ui.theme.PreviewInteractionSource import com.github.damontecres.wholphin.ui.theme.WholphinTheme +import org.jellyfin.sdk.model.api.ItemSortBy +import org.jellyfin.sdk.model.api.SortOrder import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds @@ -77,7 +84,8 @@ fun ExpandablePlayButtons( playOnClick, Modifier .onFocusChanged(buttonOnFocusChanged) - .focusRequester(firstFocus), + .focusRequester(firstFocus) + .animateItem(), ) } item("restart") { @@ -86,7 +94,9 @@ fun ExpandablePlayButtons( Duration.ZERO, Icons.Default.Refresh, playOnClick, - Modifier.onFocusChanged(buttonOnFocusChanged), + Modifier + .onFocusChanged(buttonOnFocusChanged) + .animateItem(), mirrorIcon = true, ) } @@ -99,7 +109,8 @@ fun ExpandablePlayButtons( playOnClick, Modifier .onFocusChanged(buttonOnFocusChanged) - .focusRequester(firstFocus), + .focusRequester(firstFocus) + .animateItem(), ) } } @@ -110,7 +121,10 @@ fun ExpandablePlayButtons( title = if (watched) R.string.mark_unwatched else R.string.mark_watched, iconStringRes = if (watched) R.string.fa_eye else R.string.fa_eye_slash, onClick = watchOnClick, - modifier = Modifier.onFocusChanged(buttonOnFocusChanged), + modifier = + Modifier + .onFocusChanged(buttonOnFocusChanged) + .animateItem(), ) } @@ -121,7 +135,10 @@ fun ExpandablePlayButtons( iconStringRes = R.string.fa_heart, onClick = favoriteOnClick, iconColor = if (favorite) Color.Red else Color.Unspecified, - modifier = Modifier.onFocusChanged(buttonOnFocusChanged), + modifier = + Modifier + .onFocusChanged(buttonOnFocusChanged) + .animateItem(), ) } @@ -132,12 +149,16 @@ fun ExpandablePlayButtons( Duration.ZERO, Icons.Default.MoreVert, { moreOnClick.invoke() }, - Modifier.onFocusChanged(buttonOnFocusChanged), + Modifier + .onFocusChanged(buttonOnFocusChanged) + .animateItem(), ) } } } +val MinButtonSize = 40.dp + /** * An icon button typically used in a row for playing media * @@ -156,20 +177,36 @@ fun ExpandablePlayButton( val isFocused = interactionSource.collectIsFocusedAsState().value Button( onClick = { onClick.invoke(resume) }, - modifier = modifier, + modifier = + modifier.requiredSizeIn( + minWidth = MinButtonSize, + minHeight = MinButtonSize, + maxHeight = MinButtonSize, + ), contentPadding = DefaultButtonPadding, interactionSource = interactionSource, ) { - Icon( - imageVector = icon, - contentDescription = null, - modifier = Modifier.ifElse(mirrorIcon, Modifier.graphicsLayer { scaleX = -1f }), - ) + Box( + modifier = + Modifier + .padding(start = 2.dp, top = 2.dp) + .height(MinButtonSize), + ) { + Icon( + imageVector = icon, + contentDescription = null, + modifier = + Modifier + .size(28.dp) + .ifElse(mirrorIcon, Modifier.graphicsLayer { scaleX = -1f }), + ) + } AnimatedVisibility(isFocused) { Spacer(Modifier.size(8.dp)) Text( text = stringResource(title), style = MaterialTheme.typography.titleSmall, + modifier = Modifier.padding(end = 4.dp), ) } } @@ -190,24 +227,35 @@ fun ExpandableFaButton( val isFocused = interactionSource.collectIsFocusedAsState().value Button( onClick = onClick, - modifier = modifier.heightIn(min = 40.dp), + modifier = + modifier.requiredSizeIn( + minWidth = MinButtonSize, + minHeight = MinButtonSize, + maxHeight = MinButtonSize, + ), contentPadding = DefaultButtonPadding, interactionSource = interactionSource, ) { - Text( - text = stringResource(iconStringRes), - style = MaterialTheme.typography.titleSmall, - color = iconColor, - fontSize = 16.sp, - fontFamily = FontAwesome, - textAlign = TextAlign.Center, - modifier = Modifier, - ) + Box( + modifier = + Modifier + .size(32.dp), + ) { + Text( + text = stringResource(iconStringRes), + style = MaterialTheme.typography.titleSmall, + color = iconColor, + fontSize = 16.sp, + fontFamily = FontAwesome, + textAlign = TextAlign.Center, + modifier = Modifier.align(Alignment.Center), + ) + } AnimatedVisibility(isFocused) { Text( text = stringResource(title), style = MaterialTheme.typography.titleSmall, - modifier = Modifier.padding(start = 4.dp), + modifier = Modifier.padding(end = 4.dp), ) } } @@ -230,3 +278,44 @@ private fun ExpandablePlayButtonsPreview() { ) } } + +@PreviewTvSpec +@Composable +private fun ViewOptionsPreview() { + val source = remember { PreviewInteractionSource() } + WholphinTheme { + Column( + verticalArrangement = Arrangement.spacedBy(16.dp), + modifier = Modifier.padding(16.dp), + ) { + ExpandablePlayButton( + title = R.string.play, + resume = Duration.ZERO, + icon = Icons.Default.PlayArrow, + onClick = {}, + interactionSource = source, + ) + ExpandableFaButton( + title = R.string.play, + iconStringRes = R.string.fa_eye, + onClick = {}, + modifier = Modifier, + interactionSource = source, + ) + + Row { + ExpandableFaButton( + title = R.string.mark_unwatched, + iconStringRes = R.string.fa_eye, + onClick = {}, + modifier = Modifier, + ) + SortByButton( + sortOptions = listOf(), + current = SortAndDirection(ItemSortBy.DEFAULT, SortOrder.ASCENDING), + onSortChange = {}, + ) + } + } + } +} diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/SortByButton.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/SortByButton.kt index d63842c1..405e0fb6 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/SortByButton.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/SortByButton.kt @@ -13,13 +13,14 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.withStyle -import androidx.tv.material3.Button import androidx.tv.material3.Text import com.github.damontecres.wholphin.R import com.github.damontecres.wholphin.ui.FontAwesome +import com.github.damontecres.wholphin.ui.PreviewTvSpec import com.github.damontecres.wholphin.ui.data.SortAndDirection import com.github.damontecres.wholphin.ui.data.flip import com.github.damontecres.wholphin.ui.data.getStringRes +import com.github.damontecres.wholphin.ui.theme.WholphinTheme import org.jellyfin.sdk.model.api.ItemSortBy import org.jellyfin.sdk.model.api.SortOrder @@ -42,7 +43,7 @@ fun SortByButton( val context = LocalContext.current Box(modifier = modifier) { - Button( + TextButton( onClick = { sortByDropDown = true }, onLongClick = { onSortChange.invoke(current.flip()) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/CardGrid.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/CardGrid.kt index b83ee031..633ba5bc 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/CardGrid.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/CardGrid.kt @@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width @@ -45,9 +46,9 @@ import androidx.compose.ui.input.key.type import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp -import androidx.tv.material3.Button import androidx.tv.material3.LocalContentColor import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text @@ -56,6 +57,8 @@ import com.github.damontecres.wholphin.data.model.BaseItem import com.github.damontecres.wholphin.ui.AppColors import com.github.damontecres.wholphin.ui.FontAwesome import com.github.damontecres.wholphin.ui.cards.GridCard +import com.github.damontecres.wholphin.ui.components.Button +import com.github.damontecres.wholphin.ui.components.TextButton import com.github.damontecres.wholphin.ui.ifElse import com.github.damontecres.wholphin.ui.playback.isBackwardButton import com.github.damontecres.wholphin.ui.playback.isForwardButton @@ -438,6 +441,7 @@ fun AlphabetButtons( } val focusRequesters = remember { List(letters.length) { FocusRequester() } } LazyColumn( + contentPadding = PaddingValues(4.dp), state = listState, modifier = modifier.focusProperties { @@ -452,7 +456,7 @@ fun AlphabetButtons( ) { index -> val interactionSource = remember { MutableInteractionSource() } val focused by interactionSource.collectIsFocusedAsState() - Button( + TextButton( modifier = Modifier .size(24.dp) @@ -472,6 +476,8 @@ fun AlphabetButtons( Text( text = letters[index].toString(), color = color, + textAlign = TextAlign.Center, + modifier = Modifier.fillMaxWidth(), ) } } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/PlaylistList.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/PlaylistList.kt index 8bea4a89..b68d425e 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/PlaylistList.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/PlaylistList.kt @@ -38,7 +38,6 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties -import androidx.tv.material3.Button import androidx.tv.material3.Icon import androidx.tv.material3.ListItem import androidx.tv.material3.MaterialTheme @@ -47,6 +46,7 @@ import androidx.tv.material3.surfaceColorAtElevation import com.github.damontecres.wholphin.R import com.github.damontecres.wholphin.data.model.PlaylistInfo import com.github.damontecres.wholphin.ui.components.BasicDialog +import com.github.damontecres.wholphin.ui.components.Button import com.github.damontecres.wholphin.ui.components.EditTextBox import com.github.damontecres.wholphin.ui.components.ErrorMessage import com.github.damontecres.wholphin.ui.isNotNullOrBlank diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/livetv/ProgramDialog.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/livetv/ProgramDialog.kt index 9f1d5215..54ebf864 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/livetv/ProgramDialog.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/livetv/ProgramDialog.kt @@ -28,15 +28,16 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog -import androidx.tv.material3.Button import androidx.tv.material3.Icon import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text import androidx.tv.material3.surfaceColorAtElevation import com.github.damontecres.wholphin.R import com.github.damontecres.wholphin.data.model.BaseItem +import com.github.damontecres.wholphin.ui.components.Button import com.github.damontecres.wholphin.ui.components.CircularProgress import com.github.damontecres.wholphin.ui.components.ErrorMessage +import com.github.damontecres.wholphin.ui.components.TextButton import com.github.damontecres.wholphin.ui.ifElse import com.github.damontecres.wholphin.ui.isNotNullOrBlank import com.github.damontecres.wholphin.ui.seasonEpisode @@ -145,7 +146,7 @@ fun ProgramDialog( .fillMaxWidth(), ) { if (now.isAfter(dto.startDate!!) && now.isBefore(dto.endDate!!)) { - Button( + TextButton( onClick = onWatch, modifier = Modifier, ) { @@ -179,7 +180,7 @@ fun ProgramDialog( ) { if (dto.isSeries ?: false) { item { - Button( + TextButton( onClick = { if (isSeriesRecording) { onCancelRecord.invoke(true) @@ -221,7 +222,7 @@ fun ProgramDialog( if (dto.endDate?.isAfter(LocalDateTime.now()) ?: true) { // Only show program specific recording button if it hasn't finished yet item { - Button( + TextButton( onClick = { if (isRecording) { onCancelRecord.invoke(false) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackControls.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackControls.kt index 8e17d2a7..8cb05699 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackControls.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackControls.kt @@ -45,15 +45,13 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import androidx.compose.ui.window.DialogWindowProvider import androidx.media3.common.Player import androidx.media3.common.util.UnstableApi -import androidx.tv.material3.Button -import androidx.tv.material3.ButtonDefaults +import androidx.tv.material3.ClickableSurfaceDefaults import androidx.tv.material3.Icon import androidx.tv.material3.ListItem import androidx.tv.material3.LocalContentColor @@ -62,10 +60,14 @@ import androidx.tv.material3.Text import com.github.damontecres.wholphin.R import com.github.damontecres.wholphin.preferences.AppThemeColors import com.github.damontecres.wholphin.ui.AppColors +import com.github.damontecres.wholphin.ui.PreviewTvSpec +import com.github.damontecres.wholphin.ui.components.Button +import com.github.damontecres.wholphin.ui.components.TextButton import com.github.damontecres.wholphin.ui.seekBack import com.github.damontecres.wholphin.ui.seekForward import com.github.damontecres.wholphin.ui.skipStringRes import com.github.damontecres.wholphin.ui.theme.LocalTheme +import com.github.damontecres.wholphin.ui.theme.WholphinTheme import com.github.damontecres.wholphin.ui.tryRequestFocus import com.github.damontecres.wholphin.util.ExceptionHandler import kotlinx.coroutines.delay @@ -192,7 +194,8 @@ fun PlaybackControls( modifier = Modifier.align(Alignment.CenterEnd), ) { currentSegment?.let { segment -> - Button( + TextButton( + stringRes = segment.type.skipStringRes, onClick = { playerControls.seekTo(segment.endTicks.ticks.inWholeMilliseconds) }, @@ -200,11 +203,7 @@ fun PlaybackControls( Modifier .align(Alignment.CenterVertically) .padding(end = 32.dp), - ) { - Text( - text = stringResource(segment.type.skipStringRes), - ) - } + ) } RightPlaybackButtons( captionFocusRequester = captionFocusRequester, @@ -286,7 +285,7 @@ fun SeekBar( } } -private val buttonSpacing = 4.dp +private val buttonSpacing = 12.dp @Composable fun LeftPlaybackButtons( @@ -435,9 +434,9 @@ fun PlaybackButton( Button( enabled = enabled, onClick = onClick, - shape = ButtonDefaults.shape(CircleShape), +// shape = ButtonDefaults.shape(CircleShape), colors = - ButtonDefaults.colors( + ClickableSurfaceDefaults.colors( containerColor = AppColors.TransparentBlack25, focusedContainerColor = selectedColor, ), @@ -445,8 +444,7 @@ fun PlaybackButton( interactionSource = interactionSource, modifier = modifier - .padding(4.dp) - .size(44.dp, 44.dp) + .size(36.dp, 36.dp) .onFocusChanged { onControllerInteraction.invoke() }, ) { Icon( @@ -543,3 +541,17 @@ fun BottomDialog( data class MoreButtonOptions( val options: Map, ) + +@PreviewTvSpec +@Composable +private fun ButtonPreview() { + WholphinTheme { + Row { + PlaybackButton( + iconRes = R.drawable.baseline_play_arrow_24, + onClick = {}, + onControllerInteraction = {}, + ) + } + } +} diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackOverlay.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackOverlay.kt index 1e19ce3d..f92b21f3 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackOverlay.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackOverlay.kt @@ -144,38 +144,72 @@ fun PlaybackOverlay( } else { null } - Controller( - title = item?.title, - subtitle = item?.subtitleLong, - playerControls = playerControls, - controllerViewState = controllerViewState, - showPlay = showPlay, - showClock = showClock, - previousEnabled = previousEnabled, - nextEnabled = nextEnabled, - seekEnabled = seekEnabled, - seekBack = seekBack, - skipBackOnResume = skipBackOnResume, - seekForward = seekForward, - onPlaybackActionClick = onPlaybackActionClick, - onClickPlaybackDialogType = onClickPlaybackDialogType, - onSeekProgress = { - onSeekBarChange(it) - seekProgressMs = it - }, - seekBarInteractionSource = seekBarInteractionSource, - nextState = nextState, - onNextStateFocus = { - nextState?.let { state = it } - }, - currentSegment = currentSegment, + Column( + verticalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier - // Don't use key events because this control has vertical items so up/down is tough to manage + .padding(bottom = 8.dp) .onGloballyPositioned { controllerHeight = with(density) { it.size.height.toDp() } }, - ) + ) { + Controller( + title = item?.title, + subtitle = item?.subtitleLong, + playerControls = playerControls, + controllerViewState = controllerViewState, + showPlay = showPlay, + showClock = showClock, + previousEnabled = previousEnabled, + nextEnabled = nextEnabled, + seekEnabled = seekEnabled, + seekBack = seekBack, + skipBackOnResume = skipBackOnResume, + seekForward = seekForward, + onPlaybackActionClick = onPlaybackActionClick, + onClickPlaybackDialogType = onClickPlaybackDialogType, + onSeekProgress = { + onSeekBarChange(it) + seekProgressMs = it + }, + seekBarInteractionSource = seekBarInteractionSource, + nextState = nextState, + onNextStateFocus = { + nextState?.let { state = it } + }, + currentSegment = currentSegment, + modifier = + Modifier, + // Don't use key events because this control has vertical items so up/down is tough to manage + ) + when (nextState) { + OverlayViewState.CHAPTERS -> + Text( + text = stringResource(R.string.chapters), + style = MaterialTheme.typography.titleLarge, + modifier = + Modifier + .padding(start = 16.dp, top = 0.dp) + .onFocusChanged { + if (it.isFocused) state = nextState + }.focusable(), + ) + + OverlayViewState.QUEUE -> + Text( + text = stringResource(R.string.queue), + style = MaterialTheme.typography.titleLarge, + modifier = + Modifier + .padding(start = 16.dp, top = 0.dp) + .onFocusChanged { + if (it.isFocused) state = nextState + }.focusable(), + ) + + else -> Spacer(Modifier.height(32.dp)) + } + } } AnimatedVisibility( state == OverlayViewState.CHAPTERS, @@ -189,8 +223,8 @@ fun PlaybackOverlay( verticalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier + .padding(horizontal = 8.dp) .fillMaxWidth() - .padding(8.dp) .onPreviewKeyEvent { e -> if (e.type == KeyEventType.KeyUp && isUp(e)) { state = OverlayViewState.CONTROLLER @@ -247,7 +281,7 @@ fun PlaybackOverlay( style = MaterialTheme.typography.titleLarge, modifier = Modifier - .padding(start = 16.dp, top = 16.dp) + .padding(bottom = 8.dp) .onFocusChanged { if (it.isFocused) state = OverlayViewState.QUEUE }.focusable(), @@ -269,8 +303,8 @@ fun PlaybackOverlay( verticalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier - .fillMaxWidth() .padding(8.dp) + .fillMaxWidth() .onPreviewKeyEvent { e -> if (e.type == KeyEventType.KeyUp && isUp(e)) { if (chapters.isNotEmpty()) { @@ -291,7 +325,7 @@ fun PlaybackOverlay( style = MaterialTheme.typography.titleLarge, ) LazyRow( - contentPadding = PaddingValues(16.dp), + contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp), horizontalArrangement = Arrangement.spacedBy(16.dp), modifier = Modifier @@ -538,32 +572,5 @@ fun Controller( captionFocusRequester = captionFocusRequester, settingsFocusRequester = settingsFocusRequester, ) - when (nextState) { - OverlayViewState.CHAPTERS -> - Text( - text = stringResource(R.string.chapters), - style = MaterialTheme.typography.titleLarge, - modifier = - Modifier - .padding(start = 16.dp, top = 16.dp) - .onFocusChanged { - if (it.isFocused) onNextStateFocus.invoke() - }.focusable(), - ) - - OverlayViewState.QUEUE -> - Text( - text = stringResource(R.string.queue), - style = MaterialTheme.typography.titleLarge, - modifier = - Modifier - .padding(start = 16.dp, top = 16.dp) - .onFocusChanged { - if (it.isFocused) onNextStateFocus.invoke() - }.focusable(), - ) - - else -> Spacer(Modifier.height(32.dp)) - } } } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackPage.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackPage.kt index c697a5b0..82bd604f 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackPage.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackPage.kt @@ -42,7 +42,6 @@ import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.input.key.onKeyEvent import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.intl.Locale import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView @@ -57,9 +56,7 @@ import androidx.media3.ui.compose.SURFACE_TYPE_SURFACE_VIEW import androidx.media3.ui.compose.modifiers.resizeWithContentScale import androidx.media3.ui.compose.state.rememberPlayPauseButtonState import androidx.media3.ui.compose.state.rememberPresentationState -import androidx.tv.material3.Button import androidx.tv.material3.MaterialTheme -import androidx.tv.material3.Text import androidx.tv.material3.surfaceColorAtElevation import com.github.damontecres.wholphin.data.model.ItemPlayback import com.github.damontecres.wholphin.data.model.Playlist @@ -71,6 +68,7 @@ import com.github.damontecres.wholphin.ui.LocalImageUrlService import com.github.damontecres.wholphin.ui.OneTimeLaunchedEffect import com.github.damontecres.wholphin.ui.components.ErrorMessage import com.github.damontecres.wholphin.ui.components.LoadingPage +import com.github.damontecres.wholphin.ui.components.TextButton import com.github.damontecres.wholphin.ui.nav.Destination import com.github.damontecres.wholphin.ui.preferences.subtitle.SubtitleSettings.applyToMpv import com.github.damontecres.wholphin.ui.preferences.subtitle.SubtitleSettings.calculateEdgeSize @@ -403,17 +401,14 @@ fun PlaybackPage( delay(10.seconds) segmentCancelled = true } - Button( + TextButton( + stringRes = segment.type.skipStringRes, onClick = { segmentCancelled = true player.seekTo(segment.endTicks.ticks.inWholeMilliseconds) }, modifier = Modifier.focusRequester(focusRequester), - ) { - Text( - text = stringResource(segment.type.skipStringRes), - ) - } + ) } } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/preferences/StringInputDialog.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/preferences/StringInputDialog.kt index a5e0468f..4229f78d 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/preferences/StringInputDialog.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/preferences/StringInputDialog.kt @@ -22,13 +22,13 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties -import androidx.tv.material3.Button import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text import androidx.tv.material3.surfaceColorAtElevation import com.github.damontecres.wholphin.R import com.github.damontecres.wholphin.ui.components.ConfirmDialog import com.github.damontecres.wholphin.ui.components.EditTextBox +import com.github.damontecres.wholphin.ui.components.TextButton @Composable fun StringInputDialog( @@ -95,22 +95,16 @@ fun StringInputDialog( horizontalArrangement = Arrangement.SpaceAround, modifier = Modifier.fillMaxWidth(), ) { - Button( + TextButton( + stringRes = R.string.cancel, onClick = onDismissRequest, modifier = Modifier, - ) { - Text( - text = stringResource(R.string.cancel), - ) - } - Button( + ) + TextButton( + stringRes = R.string.save, onClick = onDone, modifier = Modifier, - ) { - Text( - text = stringResource(R.string.save), - ) - } + ) } } } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/setup/InstallUpdatePage.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/setup/InstallUpdatePage.kt index e81fbce1..dad19712 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/setup/InstallUpdatePage.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/setup/InstallUpdatePage.kt @@ -42,7 +42,6 @@ import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import androidx.tv.material3.Button import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text import androidx.tv.material3.surfaceColorAtElevation @@ -54,8 +53,10 @@ import com.github.damontecres.wholphin.services.Release import com.github.damontecres.wholphin.services.UpdateChecker import com.github.damontecres.wholphin.ui.PreviewTvSpec import com.github.damontecres.wholphin.ui.components.BasicDialog +import com.github.damontecres.wholphin.ui.components.Button import com.github.damontecres.wholphin.ui.components.ErrorMessage import com.github.damontecres.wholphin.ui.components.LoadingPage +import com.github.damontecres.wholphin.ui.components.TextButton import com.github.damontecres.wholphin.ui.dimAndBlur import com.github.damontecres.wholphin.ui.formatBytes import com.github.damontecres.wholphin.ui.setValueOnMain @@ -299,20 +300,14 @@ fun InstallUpdatePageContent( style = MaterialTheme.typography.titleLarge, color = MaterialTheme.colorScheme.onSurface, ) - Button( + TextButton( + stringRes = R.string.download_and_update, onClick = onInstallRelease, - ) { - Text( - text = stringResource(R.string.download_and_update), - ) - } - Button( + ) + TextButton( + stringRes = R.string.cancel, onClick = onCancel, - ) { - Text( - text = stringResource(R.string.cancel), - ) - } + ) } } } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/setup/PinEntry.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/setup/PinEntry.kt index e6ca52a0..e0d49631 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/setup/PinEntry.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/setup/PinEntry.kt @@ -27,13 +27,14 @@ import androidx.compose.ui.input.key.type import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.tv.material3.Button import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text import com.github.damontecres.wholphin.R import com.github.damontecres.wholphin.ui.FontAwesome import com.github.damontecres.wholphin.ui.PreviewTvSpec import com.github.damontecres.wholphin.ui.components.BasicDialog +import com.github.damontecres.wholphin.ui.components.Button +import com.github.damontecres.wholphin.ui.components.TextButton import com.github.damontecres.wholphin.ui.playback.isEnterKey import com.github.damontecres.wholphin.ui.theme.WholphinTheme @@ -57,7 +58,7 @@ fun PinEntry( PinArrowRow(Modifier.align(Alignment.CenterHorizontally)) PinEntryDots(input.length, Modifier.align(Alignment.CenterHorizontally)) - Button( + TextButton( onClick = onClickServerAuth, modifier = Modifier diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/setup/SwitchServerContent.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/setup/SwitchServerContent.kt index b8682b0a..c1bc542e 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/setup/SwitchServerContent.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/setup/SwitchServerContent.kt @@ -29,7 +29,6 @@ import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp import androidx.compose.ui.window.DialogProperties import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.tv.material3.Button import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text import androidx.tv.material3.surfaceColorAtElevation @@ -37,6 +36,7 @@ import com.github.damontecres.wholphin.R import com.github.damontecres.wholphin.ui.components.BasicDialog import com.github.damontecres.wholphin.ui.components.CircularProgress import com.github.damontecres.wholphin.ui.components.EditTextBox +import com.github.damontecres.wholphin.ui.components.TextButton import com.github.damontecres.wholphin.ui.dimAndBlur import com.github.damontecres.wholphin.ui.isNotNullOrBlank import com.github.damontecres.wholphin.ui.tryRequestFocus @@ -224,7 +224,7 @@ fun SwitchServerContent( else -> {} } - Button( + TextButton( onClick = { submit.invoke() }, enabled = url.text.isNotNullOrBlank() && state == LoadingState.Pending, modifier = Modifier, diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/setup/SwitchUserContent.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/setup/SwitchUserContent.kt index 8099b4e4..e0aeb5a1 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/setup/SwitchUserContent.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/setup/SwitchUserContent.kt @@ -34,7 +34,6 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.window.DialogProperties import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.tv.material3.Button import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text import androidx.tv.material3.surfaceColorAtElevation @@ -44,6 +43,7 @@ import com.github.damontecres.wholphin.data.model.JellyfinUser import com.github.damontecres.wholphin.ui.components.BasicDialog import com.github.damontecres.wholphin.ui.components.CircularProgress import com.github.damontecres.wholphin.ui.components.EditTextBox +import com.github.damontecres.wholphin.ui.components.TextButton import com.github.damontecres.wholphin.ui.dimAndBlur import com.github.damontecres.wholphin.ui.isNotNullOrBlank import com.github.damontecres.wholphin.ui.nav.Destination @@ -203,16 +203,15 @@ fun SwitchUserContent( ) } UserStateError(userState) - Button( + TextButton( + stringRes = R.string.username_or_password, onClick = { viewModel.cancelQuickConnect() viewModel.clearSwitchUserState() useQuickConnect = false }, modifier = Modifier.align(Alignment.CenterHorizontally), - ) { - Text(text = "Use username/password") - } + ) } else { val username = rememberTextFieldState() val password = rememberTextFieldState() @@ -282,27 +281,25 @@ fun SwitchUserContent( modifier = Modifier.focusRequester(passwordFocusRequester), ) } - Button( + TextButton( + stringRes = R.string.login, onClick = { onSubmit.invoke() }, enabled = username.text.isNotNullOrBlank() && password.text.isNotNullOrBlank(), modifier = Modifier.align(Alignment.CenterHorizontally), - ) { - Text("Login") - } + ) } if (loginAttempts > 2) { Text( text = "Trouble logging in?", modifier = Modifier.align(Alignment.CenterHorizontally), ) - Button( + TextButton( + stringRes = R.string.show_debug_info, onClick = { viewModel.navigationManager.navigateTo(Destination.Debug) }, modifier = Modifier.align(Alignment.CenterHorizontally), - ) { - Text("Show debug info") - } + ) } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 40a88eda..6c54c7fb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -350,6 +350,8 @@ Guest stars Edge size + Use username/password + Login