Keep TV player controls hidden while seeking

This commit is contained in:
2026-04-13 14:40:07 +02:00
parent a0af187e8f
commit 9a130e9738
2 changed files with 78 additions and 2 deletions

View File

@@ -56,6 +56,7 @@ import org.junit.Test
private const val TvPlayerRootTag = "tv_player_root" private const val TvPlayerRootTag = "tv_player_root"
private const val TvPlayerHiddenPauseCountTag = "tv_player_hidden_pause_count" private const val TvPlayerHiddenPauseCountTag = "tv_player_hidden_pause_count"
private const val TvPlayerHiddenResumeCountTag = "tv_player_hidden_resume_count" private const val TvPlayerHiddenResumeCountTag = "tv_player_hidden_resume_count"
private const val TvPlayerHiddenSeekDeltaTag = "tv_player_hidden_seek_delta"
@OptIn(ExperimentalTestApi::class) @OptIn(ExperimentalTestApi::class)
class TvPlayerControlsOverlayTest { class TvPlayerControlsOverlayTest {
@@ -492,6 +493,66 @@ class TvPlayerControlsOverlayTest {
) )
} }
@Test
fun hiddenControls_leftSeeksWithoutShowingControls() {
composeRule.setContent {
AppTheme {
TrackPanelHost(
uiState = samplePlayerState(),
initialControlsVisible = false
)
}
}
composeRule.onNodeWithTag(TvPlayerRootTag)
.performSemanticsAction(SemanticsActions.RequestFocus)
.performKeyInput {
pressKey(Key.DirectionLeft)
}
composeRule.waitForIdle()
composeRule.onAllNodesWithTag(TvPlayerPlayPauseButtonTag).assertCountEquals(0)
composeRule.onAllNodesWithTag(TvPlayerHiddenStopFeedbackTag).assertCountEquals(0)
composeRule.onNodeWithTag(TvPlayerHiddenSeekDeltaTag)
.assert(
SemanticsMatcher.expectValue(
SemanticsProperties.StateDescription,
"-10000"
)
)
}
@Test
fun hiddenControls_rightSeeksWithoutShowingControls() {
composeRule.setContent {
AppTheme {
TrackPanelHost(
uiState = samplePlayerState(),
initialControlsVisible = false
)
}
}
composeRule.onNodeWithTag(TvPlayerRootTag)
.performSemanticsAction(SemanticsActions.RequestFocus)
.performKeyInput {
pressKey(Key.DirectionRight)
}
composeRule.waitForIdle()
composeRule.onAllNodesWithTag(TvPlayerPlayPauseButtonTag).assertCountEquals(0)
composeRule.onAllNodesWithTag(TvPlayerHiddenStopFeedbackTag).assertCountEquals(0)
composeRule.onNodeWithTag(TvPlayerHiddenSeekDeltaTag)
.assert(
SemanticsMatcher.expectValue(
SemanticsProperties.StateDescription,
"10000"
)
)
}
@Test @Test
fun backOnTrackPanel_closesItAndRestoresFocusToOpeningButton() { fun backOnTrackPanel_closesItAndRestoresFocusToOpeningButton() {
composeRule.setContent { composeRule.setContent {
@@ -656,6 +717,7 @@ private fun TrackPanelHost(
var stopFeedbackRequestId by remember { mutableStateOf(0) } var stopFeedbackRequestId by remember { mutableStateOf(0) }
var pauseWithoutControlsCount by remember { mutableStateOf(0) } var pauseWithoutControlsCount by remember { mutableStateOf(0) }
var resumeWithoutControlsCount by remember { mutableStateOf(0) } var resumeWithoutControlsCount by remember { mutableStateOf(0) }
var lastHiddenSeekDeltaMs by remember { mutableStateOf(0L) }
val rootFocusRequester = remember { FocusRequester() } val rootFocusRequester = remember { FocusRequester() }
val controlsFocusRequester = remember { FocusRequester() } val controlsFocusRequester = remember { FocusRequester() }
val qualityButtonFocusRequester = remember { FocusRequester() } val qualityButtonFocusRequester = remember { FocusRequester() }
@@ -677,6 +739,10 @@ private fun TrackPanelHost(
resumeWithoutControlsCount += 1 resumeWithoutControlsCount += 1
stopFeedbackVisible = false stopFeedbackVisible = false
} }
val seekWithoutShowingControls: (Long) -> Unit = { deltaMs ->
lastHiddenSeekDeltaMs = deltaMs
stopFeedbackVisible = false
}
LaunchedEffect(trackPanelType, pendingTrackButtonFocus) { LaunchedEffect(trackPanelType, pendingTrackButtonFocus) {
val pendingFocus = pendingTrackButtonFocus ?: return@LaunchedEffect val pendingFocus = pendingTrackButtonFocus ?: return@LaunchedEffect
@@ -721,7 +787,7 @@ private fun TrackPanelHost(
onHideControls = { controlsVisible = false }, onHideControls = { controlsVisible = false },
onPausePlaybackWithoutShowingControls = pausePlaybackWithoutShowingControls, onPausePlaybackWithoutShowingControls = pausePlaybackWithoutShowingControls,
onResumePlaybackWithoutShowingControls = resumePlaybackWithoutShowingControls, onResumePlaybackWithoutShowingControls = resumePlaybackWithoutShowingControls,
onSeekRelative = { _ -> controlsVisible = true }, onSeekRelative = seekWithoutShowingControls,
onShowControls = { controlsVisible = true }, onShowControls = { controlsVisible = true },
onTogglePlayPause = { controlsVisible = true } onTogglePlayPause = { controlsVisible = true }
) )
@@ -781,6 +847,12 @@ private fun TrackPanelHost(
.semantics { stateDescription = resumeWithoutControlsCount.toString() } .semantics { stateDescription = resumeWithoutControlsCount.toString() }
) )
Box(
modifier = Modifier
.testTag(TvPlayerHiddenSeekDeltaTag)
.semantics { stateDescription = lastHiddenSeekDeltaMs.toString() }
)
trackPanelType?.let { panelType -> trackPanelType?.let { panelType ->
TvTrackSelectionPanel( TvTrackSelectionPanel(
panelType = panelType, panelType = panelType,

View File

@@ -150,6 +150,10 @@ fun TvPlayerScreen(
viewModel.seekBy(deltaMs) viewModel.seekBy(deltaMs)
showTvControls() showTvControls()
} }
val seekByWithoutShowingControls: (Long) -> Unit = { deltaMs ->
viewModel.seekBy(deltaMs)
stopFeedbackVisible = false
}
val seekToLiveEdgeAndShowControls: () -> Unit = { val seekToLiveEdgeAndShowControls: () -> Unit = {
viewModel.seekToLiveEdge() viewModel.seekToLiveEdge()
showTvControls() showTvControls()
@@ -226,7 +230,7 @@ fun TvPlayerScreen(
onHideControls = { viewModel.toggleControlsVisibility() }, onHideControls = { viewModel.toggleControlsVisibility() },
onPausePlaybackWithoutShowingControls = pausePlaybackWithoutShowingControls, onPausePlaybackWithoutShowingControls = pausePlaybackWithoutShowingControls,
onResumePlaybackWithoutShowingControls = resumePlaybackWithoutShowingControls, onResumePlaybackWithoutShowingControls = resumePlaybackWithoutShowingControls,
onSeekRelative = seekByAndShowControls, onSeekRelative = seekByWithoutShowingControls,
onShowControls = showTvControls, onShowControls = showTvControls,
onTogglePlayPause = togglePlayPauseAndShowControls onTogglePlayPause = togglePlayPauseAndShowControls
) )