diff --git a/app/src/main/kotlin/com/subtracks/ui/playback/NowPlayingScreen.kt b/app/src/main/kotlin/com/subtracks/ui/playback/NowPlayingScreen.kt index 785520f7..9c02c20a 100644 --- a/app/src/main/kotlin/com/subtracks/ui/playback/NowPlayingScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/playback/NowPlayingScreen.kt @@ -196,7 +196,7 @@ fun NowPlayingRoute( userPreferences: UserPreferences = koinInject(), ) { val state by controller.state.collectAsStateWithLifecycle() - val keepScreenOn by userPreferences.keepScreenOn().collectAsStateWithLifecycle(initialValue = false) + val keepScreenOn by remember { userPreferences.keepScreenOn() }.collectAsStateWithLifecycle(initialValue = false) val positionMs by controller.positionMs.collectAsStateWithLifecycle() val sourceId = state.context?.sourceId val songId = state.item?.id diff --git a/app/src/test/kotlin/com/subtracks/ui/playback/NowPlayingKeepScreenOnTest.kt b/app/src/test/kotlin/com/subtracks/ui/playback/NowPlayingKeepScreenOnTest.kt new file mode 100644 index 00000000..78ce2daf --- /dev/null +++ b/app/src/test/kotlin/com/subtracks/ui/playback/NowPlayingKeepScreenOnTest.kt @@ -0,0 +1,85 @@ +package com.subtracks.ui.playback + +import android.view.View +import android.view.ViewGroup +import androidx.activity.ComponentActivity +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.ui.test.junit4.v2.createAndroidComposeRule +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.subtracks.data.model.CoverArtRef +import com.subtracks.playback.PlaybackState +import com.subtracks.playback.QueueItem +import com.subtracks.ui.theme.SubtracksTheme +import com.subtracks.ui.theme.artworkColorsFromSeed +import org.junit.Assert.assertNotNull +import org.junit.Assert.assertNull +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.annotation.GraphicsMode + +@RunWith(AndroidJUnit4::class) +@GraphicsMode(GraphicsMode.Mode.NATIVE) +class NowPlayingKeepScreenOnTest { + @get:Rule + val composeRule = createAndroidComposeRule() + + private val state = + PlaybackState( + item = + QueueItem( + id = "s-eiirp", + title = "Everything In Its Right Place", + artist = "Radiohead", + album = "Kid A", + coverArtId = "art-al-kid-a", + ), + isPlaying = true, + durationMs = 251_000, + hasNext = true, + hasPrevious = false, + ) + + @Test + fun theScreenOnFlagTracksTheSetting() { + var keepScreenOn by mutableStateOf(true) + composeRule.setContent { + SubtracksTheme { + NowPlayingScreen( + state = state, + positionMs = 62_000, + title = "Kid A", + coverArt = CoverArtRef("art-al-kid-a", "test:art-al-kid-a"), + artwork = artworkColorsFromSeed(android.graphics.Color.rgb(120, 80, 200)), + onBack = {}, + onQueue = {}, + onPlayPause = {}, + onNext = {}, + onPrevious = {}, + onSeek = {}, + keepScreenOn = keepScreenOn, + ) + } + } + composeRule.waitForIdle() + assertNotNull("now playing should hold the screen on", viewHoldingTheScreenOn()) + + composeRule.runOnIdle { keepScreenOn = false } + composeRule.waitForIdle() + assertNull("clearing the setting should release the screen-on flag", viewHoldingTheScreenOn()) + } + + private fun viewHoldingTheScreenOn(): View? = findKeepingScreenOn(composeRule.activity.window.decorView) + + private fun findKeepingScreenOn(view: View): View? { + if (view.keepScreenOn) return view + if (view is ViewGroup) { + for (index in 0 until view.childCount) { + findKeepingScreenOn(view.getChildAt(index))?.let { return it } + } + } + return null + } +} diff --git a/app/src/test/kotlin/com/subtracks/ui/settings/SettingsScreenTest.kt b/app/src/test/kotlin/com/subtracks/ui/settings/SettingsScreenTest.kt index 094ac9e5..eaa48ca1 100644 --- a/app/src/test/kotlin/com/subtracks/ui/settings/SettingsScreenTest.kt +++ b/app/src/test/kotlin/com/subtracks/ui/settings/SettingsScreenTest.kt @@ -1,8 +1,10 @@ package com.subtracks.ui.settings import androidx.activity.ComponentActivity +import androidx.compose.ui.test.hasAnySibling import androidx.compose.ui.test.hasScrollToNodeAction import androidx.compose.ui.test.hasText +import androidx.compose.ui.test.isToggleable import androidx.compose.ui.test.junit4.v2.createAndroidComposeRule import androidx.compose.ui.test.onAllNodesWithText import androidx.compose.ui.test.onNodeWithText @@ -27,8 +29,44 @@ class SettingsScreenTest { val composeRule = createAndroidComposeRule() @Test - fun theKeepScreenOnRowToggles() { + fun theKeepScreenOnRowTurnsTheSettingOn() { var requested: Boolean? = null + renderSettings(keepScreenOn = false) { requested = it } + + composeRule.onNodeWithText("Keep screen on").performClick() + composeRule.waitForIdle() + + assertEquals(true, requested) + } + + @Test + fun theKeepScreenOnRowTurnsTheSettingOff() { + var requested: Boolean? = null + renderSettings(keepScreenOn = true) { requested = it } + + composeRule.onNodeWithText("Keep screen on").performClick() + composeRule.waitForIdle() + + assertEquals(false, requested) + } + + @Test + fun theKeepScreenOnSwitchTurnsTheSettingOn() { + var requested: Boolean? = null + renderSettings(keepScreenOn = false) { requested = it } + + composeRule + .onNode(isToggleable() and hasAnySibling(hasText("Keep screen on")), useUnmergedTree = true) + .performClick() + composeRule.waitForIdle() + + assertEquals(true, requested) + } + + private fun renderSettings( + keepScreenOn: Boolean, + onKeepScreenOnChange: (Boolean) -> Unit, + ) { composeRule.setContent { SubtracksTheme { SettingsScreen( @@ -40,7 +78,7 @@ class SettingsScreenTest { downloadQuality = StreamQuality(), downloadOverMetered = false, scrobbling = false, - keepScreenOn = false, + keepScreenOn = keepScreenOn, onSelectSource = {}, onEditServer = {}, onWifiQualityChange = {}, @@ -49,7 +87,7 @@ class SettingsScreenTest { onDownloadQualityChange = {}, onDownloadOverMeteredChange = {}, onScrobblingChange = {}, - onKeepScreenOnChange = { requested = it }, + onKeepScreenOnChange = onKeepScreenOnChange, onAddServer = {}, onOpenDownloads = {}, onOpenLicenses = {}, @@ -60,9 +98,6 @@ class SettingsScreenTest { } awaitText("Add server") composeRule.onNode(hasScrollToNodeAction()).performScrollToNode(hasText("Keep screen on")) - composeRule.onNodeWithText("Keep screen on").performClick() - composeRule.waitForIdle() - assertEquals(true, requested) } private fun awaitText(text: String) {