Add a small glow effect to the segment skip button (#1228)

## Description
Adds a small glow to the border of the segment skip buttons, ie "Skip
Intro", etc. Since this button appears as focused immediately, there's
no contrast and it can be missed sometimes. So this glowing border draws
the eye a bit better.

Also a small change to reduce the minimum skip forward amount to 5
seconds .

### Related issues
Skip forward: #1203

### Testing
Emulator. But this needs some "real world" testing on a TV, too, so this
may need tweaking

## Screenshots


https://github.com/user-attachments/assets/5488d468-aee4-4448-a823-6326ccb003da

## AI or LLM usage
None
This commit is contained in:
Ray 2026-04-15 17:49:54 -04:00 committed by GitHub
parent 923a3713af
commit 95859be3c6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 95 additions and 5 deletions

View file

@ -60,7 +60,7 @@ sealed interface AppPreference<Pref, T> {
AppSliderPreference<AppPreferences>( AppSliderPreference<AppPreferences>(
title = R.string.skip_forward_preference, title = R.string.skip_forward_preference,
defaultValue = 30, defaultValue = 30,
min = 10, min = 5,
max = 5.minutes.inWholeSeconds, max = 5.minutes.inWholeSeconds,
interval = 5, interval = 5,
getter = { getter = {

View file

@ -68,14 +68,12 @@ import com.github.damontecres.wholphin.ui.AspectRatios
import com.github.damontecres.wholphin.ui.LocalImageUrlService import com.github.damontecres.wholphin.ui.LocalImageUrlService
import com.github.damontecres.wholphin.ui.components.ErrorMessage import com.github.damontecres.wholphin.ui.components.ErrorMessage
import com.github.damontecres.wholphin.ui.components.LoadingPage import com.github.damontecres.wholphin.ui.components.LoadingPage
import com.github.damontecres.wholphin.ui.components.TextButton
import com.github.damontecres.wholphin.ui.ifElse import com.github.damontecres.wholphin.ui.ifElse
import com.github.damontecres.wholphin.ui.nav.Destination 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.applyToMpv
import com.github.damontecres.wholphin.ui.preferences.subtitle.SubtitleSettings.calculateEdgeSize import com.github.damontecres.wholphin.ui.preferences.subtitle.SubtitleSettings.calculateEdgeSize
import com.github.damontecres.wholphin.ui.preferences.subtitle.SubtitleSettings.toSubtitleStyle import com.github.damontecres.wholphin.ui.preferences.subtitle.SubtitleSettings.toSubtitleStyle
import com.github.damontecres.wholphin.ui.seasonEpisode import com.github.damontecres.wholphin.ui.seasonEpisode
import com.github.damontecres.wholphin.ui.skipStringRes
import com.github.damontecres.wholphin.ui.tryRequestFocus import com.github.damontecres.wholphin.ui.tryRequestFocus
import com.github.damontecres.wholphin.util.ExceptionHandler import com.github.damontecres.wholphin.util.ExceptionHandler
import com.github.damontecres.wholphin.util.LoadingState import com.github.damontecres.wholphin.util.LoadingState
@ -463,8 +461,8 @@ fun PlaybackPageContent(
delay(10.seconds) delay(10.seconds)
viewModel.updateSegment(segment.segment.id, true) viewModel.updateSegment(segment.segment.id, true)
} }
TextButton( SkipSegmentButton(
stringRes = segment.segment.type.skipStringRes, type = segment.segment.type,
onClick = { onClick = {
viewModel.updateSegment(segment.segment.id, false) viewModel.updateSegment(segment.segment.id, false)
}, },

View file

@ -0,0 +1,92 @@
package com.github.damontecres.wholphin.ui.playback
import androidx.compose.animation.animateColor
import androidx.compose.animation.core.InfiniteRepeatableSpec
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.tv.material3.MaterialTheme
import androidx.tv.material3.Text
import com.github.damontecres.wholphin.ui.PreviewTvSpec
import com.github.damontecres.wholphin.ui.components.Button
import com.github.damontecres.wholphin.ui.skipStringRes
import com.github.damontecres.wholphin.ui.theme.PreviewInteractionSource
import com.github.damontecres.wholphin.ui.theme.WholphinTheme
import org.jellyfin.sdk.model.api.MediaSegmentType
@Composable
fun SkipSegmentButton(
type: MediaSegmentType,
onClick: () -> Unit,
modifier: Modifier = Modifier,
onLongClick: (() -> Unit)? = null,
interactionSource: MutableInteractionSource? = null,
) {
val infiniteTransition = rememberInfiniteTransition("SkipSegmentButton")
val color by infiniteTransition.animateColor(
initialValue = MaterialTheme.colorScheme.onSurface,
targetValue = Color.Transparent,
animationSpec =
InfiniteRepeatableSpec(
animation = tween(durationMillis = 1500, easing = LinearEasing),
repeatMode = RepeatMode.Reverse,
),
label = "SkipSegmentButton_color",
)
Button(
onClick = onClick,
modifier =
modifier.drawBehind {
val px = 6.dp.toPx()
drawRoundRect(
color = color,
cornerRadius = CornerRadius(this.size.width * .5f),
topLeft = Offset(-px, -px),
size = Size(this.size.width + px * 2, this.size.height + px * 2),
)
},
onLongClick = onLongClick,
enabled = true,
contentPadding =
PaddingValues(
start = 8.dp,
top = 4.dp,
end = 8.dp,
bottom = 4.dp,
),
contentHeight = 32.dp,
interactionSource = interactionSource,
content = {
Text(text = stringResource(type.skipStringRes))
},
)
}
@PreviewTvSpec
@Composable
fun SkipSegmentButtonPreview() {
WholphinTheme {
val source = remember { PreviewInteractionSource() }
SkipSegmentButton(
type = MediaSegmentType.INTRO,
onClick = {},
modifier = Modifier.padding(16.dp),
interactionSource = source,
)
}
}