@@ -8,19 +8,32 @@ import androidx.compose.animation.fadeOut
88import androidx.compose.foundation.background
99import androidx.compose.foundation.basicMarquee
1010import androidx.compose.foundation.layout.*
11+ import androidx.compose.foundation.shape.CircleShape
1112import androidx.compose.material.icons.Icons
1213import androidx.compose.material.icons.automirrored.filled.Undo
1314import androidx.compose.material.icons.filled.*
14- import androidx.compose.material3.*
15+ import androidx.compose.material3.FloatingActionButton
16+ import androidx.compose.material3.Icon
17+ import androidx.compose.material3.IconButton
18+ import androidx.compose.material3.IconButtonDefaults
19+ import androidx.compose.material3.MaterialTheme
20+ import androidx.compose.material3.Text
21+ import androidx.compose.material3.TextButton
1522import androidx.compose.runtime.Composable
1623import androidx.compose.runtime.collectAsState
1724import androidx.compose.runtime.getValue
25+ import androidx.compose.runtime.mutableStateOf
26+ import androidx.compose.runtime.remember
27+ import androidx.compose.runtime.setValue
1828import androidx.compose.ui.Alignment
1929import androidx.compose.ui.Modifier
30+ import androidx.compose.ui.composed
2031import androidx.compose.ui.draw.alpha
2132import androidx.compose.ui.focus.FocusRequester
2233import androidx.compose.ui.focus.focusRequester
34+ import androidx.compose.ui.focus.onFocusChanged
2335import androidx.compose.ui.graphics.Color
36+ import androidx.compose.ui.graphics.Shape
2437import androidx.compose.ui.layout.layout
2538import androidx.compose.ui.text.PlatformTextStyle
2639import androidx.compose.ui.text.TextStyle
@@ -102,6 +115,23 @@ fun Modifier.alphaHitTestPassThrough(alpha: Float): Modifier {
102115 }
103116}
104117
118+ fun Modifier.focusedTVBackground (
119+ focusedColor : Color = Color .White .copy(alpha = 0.5f),
120+ shape : Shape = CircleShape
121+ ): Modifier = composed {
122+ if (! SharedContext .isTv) return @composed this
123+ var isFocused by remember { mutableStateOf(false ) }
124+
125+ this
126+ .onFocusChanged { isFocused = it.isFocused }
127+ .background(
128+ color = if (isFocused) focusedColor else Color .Transparent ,
129+ shape = shape
130+ )
131+ }
132+
133+
134+
105135@OptIn(ExperimentalLayoutApi ::class )
106136@Composable
107137fun PlayerControl (
@@ -139,7 +169,14 @@ fun PlayerControl(
139169 label = " controlsAlpha"
140170 )
141171
142- Box (modifier = Modifier .fillMaxSize()) {
172+ Box (modifier =
173+ Modifier .fillMaxSize().then(
174+ if (playPauseFocusRequester != null ) {
175+ Modifier .focusRequester(playPauseFocusRequester)
176+ } else {
177+ Modifier
178+ }
179+ )) {
143180 // Background dim with alpha animation
144181 Box (
145182 modifier = Modifier
@@ -240,7 +277,10 @@ fun PlayerControl(
240277 verticalAlignment = Alignment .Top
241278 ) {
242279 if (! isFullscreenMode) {
243- IconButton (onClick = callbacks.onClose) {
280+ IconButton (
281+ onClick = callbacks.onClose,
282+ modifier = Modifier .focusedTVBackground()
283+ ) {
244284 Icon (
245285 Icons .Default .Close ,
246286 contentDescription = stringResource(MR .strings.close),
@@ -304,7 +344,7 @@ fun PlayerControl(
304344 }
305345
306346 // Speed button
307- TextButton (onClick = callbacks.onSpeedPitchClick) {
347+ TextButton (onClick = callbacks.onSpeedPitchClick, modifier = Modifier .focusedTVBackground() ) {
308348 Text (
309349 text = if (state.currentSpeed == 1f ) " 1x" else String .format(
310350 " %.1fx" ,
@@ -355,7 +395,7 @@ fun PlayerControl(
355395 if (state.timelineSize > 1 && state.currentTimelineIndex < state.timelineSize - 1 ) {
356396 IconButton (
357397 onClick = callbacks.onSeekToPrevious,
358- modifier = Modifier .size(40 .dp)
398+ modifier = Modifier .size(40 .dp).focusedTVBackground(),
359399 ) {
360400 Icon (
361401 Icons .Default .SkipPrevious ,
@@ -368,14 +408,7 @@ fun PlayerControl(
368408 IconButton (
369409 onClick = callbacks.onPlayPauseClick,
370410 modifier = Modifier
371- .size(60 .dp)
372- .then(
373- if (playPauseFocusRequester != null ) {
374- Modifier .focusRequester(playPauseFocusRequester)
375- } else {
376- Modifier
377- }
378- )
411+ .size(60 .dp).focusedTVBackground(),
379412 ) {
380413 Icon (
381414 if (state.isPlaying) Icons .Default .Pause else Icons .Default .PlayArrow ,
@@ -389,7 +422,7 @@ fun PlayerControl(
389422 if (state.timelineSize > 1 && state.currentTimelineIndex < state.timelineSize - 1 ) {
390423 IconButton (
391424 onClick = callbacks.onSeekToNext,
392- modifier = Modifier .size(40 .dp)
425+ modifier = Modifier .size(40 .dp).focusedTVBackground(),
393426 ) {
394427 Icon (
395428 Icons .Default .SkipNext ,
@@ -434,7 +467,10 @@ fun PlayerControl(
434467 color = Color .White ,
435468 fontSize = 14 .sp
436469 )
437- IconButton (onClick = callbacks.onFullScreenClick) {
470+ IconButton (
471+ onClick = callbacks.onFullScreenClick,
472+ modifier = Modifier .focusedTVBackground()
473+ ) {
438474 Icon (
439475 Icons .Default .Fullscreen ,
440476 contentDescription = stringResource(MR .strings.player_rotate_screen),
0 commit comments