diff --git a/app-tv/src/androidTest/java/hu/bbara/purefin/app/content/episode/EpisodeScreenContentTest.kt b/app-tv/src/androidTest/java/hu/bbara/purefin/app/content/episode/EpisodeScreenContentTest.kt index 3c72015c..47ec4fc3 100644 --- a/app-tv/src/androidTest/java/hu/bbara/purefin/app/content/episode/EpisodeScreenContentTest.kt +++ b/app-tv/src/androidTest/java/hu/bbara/purefin/app/content/episode/EpisodeScreenContentTest.kt @@ -7,11 +7,16 @@ import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.assertIsFocused import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.compose.ui.test.onAllNodesWithText +import androidx.compose.ui.test.onRoot import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performKeyInput +import androidx.compose.ui.test.pressKey +import androidx.compose.ui.input.key.Key import hu.bbara.purefin.core.model.CastMember import hu.bbara.purefin.core.model.Episode import hu.bbara.purefin.ui.theme.AppTheme +import org.junit.Assert.assertEquals import org.junit.Rule import org.junit.Test import java.util.UUID @@ -66,6 +71,32 @@ class EpisodeScreenContentTest { composeRule.onAllNodesWithText("Series").assertCountEquals(0) } + @Test + fun episodeScreenContent_startsPlaybackOnFirstCenterPress() { + var playCount = 0 + + composeRule.setContent { + AppTheme { + EpisodeScreenContent( + episode = sampleEpisode(progress = 63.0), + seriesTitle = "Severance", + onPlay = { playCount++ } + ) + } + } + + composeRule.waitForIdle() + + composeRule.onNodeWithTag(EpisodePlayButtonTag).assertIsFocused() + composeRule.onRoot().performKeyInput { + pressKey(Key.DirectionCenter) + } + + composeRule.waitForIdle() + + assertEquals(1, playCount) + } + private fun sampleEpisode(progress: Double?): Episode { val seriesId = UUID.fromString("11111111-1111-1111-1111-111111111111") val seasonId = UUID.fromString("22222222-2222-2222-2222-222222222222") diff --git a/app-tv/src/androidTest/java/hu/bbara/purefin/app/content/movie/MovieScreenContentTest.kt b/app-tv/src/androidTest/java/hu/bbara/purefin/app/content/movie/MovieScreenContentTest.kt index 1dbcb23d..41edc6f2 100644 --- a/app-tv/src/androidTest/java/hu/bbara/purefin/app/content/movie/MovieScreenContentTest.kt +++ b/app-tv/src/androidTest/java/hu/bbara/purefin/app/content/movie/MovieScreenContentTest.kt @@ -7,11 +7,16 @@ import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.assertIsFocused import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.compose.ui.test.onAllNodesWithText +import androidx.compose.ui.test.onRoot import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performKeyInput +import androidx.compose.ui.test.pressKey +import androidx.compose.ui.input.key.Key import hu.bbara.purefin.core.model.CastMember import hu.bbara.purefin.core.model.Movie import hu.bbara.purefin.ui.theme.AppTheme +import org.junit.Assert.assertEquals import org.junit.Rule import org.junit.Test import java.util.UUID @@ -43,6 +48,31 @@ class MovieScreenContentTest { .assertIsFocused() } + @Test + fun movieScreenContent_startsPlaybackOnFirstCenterPress() { + var playCount = 0 + + composeRule.setContent { + AppTheme { + MovieScreenContent( + movie = sampleMovie(progress = 42.0), + onPlay = { playCount++ } + ) + } + } + + composeRule.waitForIdle() + + composeRule.onNodeWithTag(MoviePlayButtonTag).assertIsFocused() + composeRule.onRoot().performKeyInput { + pressKey(Key.DirectionCenter) + } + + composeRule.waitForIdle() + + assertEquals(1, playCount) + } + private fun sampleMovie(progress: Double?): Movie { return Movie( id = UUID.fromString("11111111-1111-1111-1111-111111111111"), diff --git a/app-tv/src/androidTest/java/hu/bbara/purefin/app/content/series/SeriesScreenContentTest.kt b/app-tv/src/androidTest/java/hu/bbara/purefin/app/content/series/SeriesScreenContentTest.kt index 182844b9..6a0e82b2 100644 --- a/app-tv/src/androidTest/java/hu/bbara/purefin/app/content/series/SeriesScreenContentTest.kt +++ b/app-tv/src/androidTest/java/hu/bbara/purefin/app/content/series/SeriesScreenContentTest.kt @@ -5,13 +5,18 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.assertIsFocused import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onRoot import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performKeyInput +import androidx.compose.ui.test.pressKey +import androidx.compose.ui.input.key.Key import hu.bbara.purefin.core.model.CastMember import hu.bbara.purefin.core.model.Episode import hu.bbara.purefin.core.model.Season import hu.bbara.purefin.core.model.Series import hu.bbara.purefin.ui.theme.AppTheme +import org.junit.Assert.assertEquals import org.junit.Rule import org.junit.Test import java.util.UUID @@ -65,6 +70,31 @@ class SeriesScreenContentTest { .assertIsFocused() } + @Test + fun seriesScreenContent_startsPlaybackOnFirstCenterPress() { + var playCount = 0 + + composeRule.setContent { + AppTheme { + SeriesScreenContent( + series = sampleSeriesWithEpisodes(), + onPlayEpisode = { playCount++ } + ) + } + } + + composeRule.waitForIdle() + + composeRule.onNodeWithTag(SeriesPlayButtonTag).assertIsFocused() + composeRule.onRoot().performKeyInput { + pressKey(Key.DirectionCenter) + } + + composeRule.waitForIdle() + + assertEquals(1, playCount) + } + private fun sampleSeriesWithEpisodes(): Series { val seriesId = UUID.fromString("11111111-1111-1111-1111-111111111111") val seasonId = UUID.fromString("22222222-2222-2222-2222-222222222222") diff --git a/app-tv/src/main/java/hu/bbara/purefin/app/content/episode/EpisodeScreen.kt b/app-tv/src/main/java/hu/bbara/purefin/app/content/episode/EpisodeScreen.kt index f41fa984..53b87d97 100644 --- a/app-tv/src/main/java/hu/bbara/purefin/app/content/episode/EpisodeScreen.kt +++ b/app-tv/src/main/java/hu/bbara/purefin/app/content/episode/EpisodeScreen.kt @@ -8,6 +8,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.remember +import androidx.compose.runtime.withFrameNanos import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.unit.dp @@ -75,6 +76,7 @@ internal fun EpisodeScreenContent( val playFocusRequester = remember { FocusRequester() } LaunchedEffect(episode.id) { + withFrameNanos { } playFocusRequester.requestFocus() } diff --git a/app-tv/src/main/java/hu/bbara/purefin/app/content/movie/MovieScreen.kt b/app-tv/src/main/java/hu/bbara/purefin/app/content/movie/MovieScreen.kt index b88d8bc5..7fb95737 100644 --- a/app-tv/src/main/java/hu/bbara/purefin/app/content/movie/MovieScreen.kt +++ b/app-tv/src/main/java/hu/bbara/purefin/app/content/movie/MovieScreen.kt @@ -8,6 +8,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.remember +import androidx.compose.runtime.withFrameNanos import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.unit.dp @@ -54,6 +55,7 @@ internal fun MovieScreenContent( val playFocusRequester = remember { FocusRequester() } LaunchedEffect(movie.id) { + withFrameNanos { } playFocusRequester.requestFocus() } diff --git a/app-tv/src/main/java/hu/bbara/purefin/app/content/series/SeriesScreen.kt b/app-tv/src/main/java/hu/bbara/purefin/app/content/series/SeriesScreen.kt index bf387240..6d4f99ec 100644 --- a/app-tv/src/main/java/hu/bbara/purefin/app/content/series/SeriesScreen.kt +++ b/app-tv/src/main/java/hu/bbara/purefin/app/content/series/SeriesScreen.kt @@ -7,10 +7,11 @@ import androidx.compose.foundation.layout.height import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.remember import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.runtime.withFrameNanos import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.unit.dp @@ -63,6 +64,7 @@ internal fun SeriesScreenContent( val firstContentFocusRequester = remember { FocusRequester() } LaunchedEffect(series.id, nextUpEpisode?.id) { + withFrameNanos { } if (nextUpEpisode != null) { playFocusRequester.requestFocus() } else { diff --git a/app-tv/src/main/java/hu/bbara/purefin/common/ui/components/MediaResumeButton.kt b/app-tv/src/main/java/hu/bbara/purefin/common/ui/components/MediaResumeButton.kt index 0b991c6d..584e7ff0 100644 --- a/app-tv/src/main/java/hu/bbara/purefin/common/ui/components/MediaResumeButton.kt +++ b/app-tv/src/main/java/hu/bbara/purefin/common/ui/components/MediaResumeButton.kt @@ -68,8 +68,8 @@ fun MediaResumeButton( .border(3.dp, focusBorderColor, focusShape) .clip(focusShape) .onFocusChanged { isFocused = it.isFocused || it.hasFocus } - .focusable() .clickable(onClick = onClick) + .focusable() ) { // Bottom layer: inverted colors (visible for the remaining %) Box(