Integrate Discover with canonical shared UI

This commit is contained in:
justinzeus 2026-11-05 20:57:57 +01:00
commit 575103ce98
690 changed files with 2899 additions and 174 deletions

View file

@ -0,0 +1,101 @@
// SPDX-License-Identifier: GPL-2.0-only
package org.justinvisser.wolfskin.tv
import android.app.Application
import androidx.activity.ComponentActivity
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performKeyInput
import androidx.compose.ui.test.pressKey
import kotlinx.coroutines.CompletableDeferred
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertTrue
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.justinvisser.wolfskin.design.DiscoverFixture
import org.justinvisser.wolfskin.design.DiscoverScreen
import org.justinvisser.wolfskin.design.DiscoverState
import org.justinvisser.wolfskin.design.DiscoverStatus
import org.justinvisser.wolfskin.design.ShellPerson
import org.justinvisser.wolfskin.design.ShellState
import org.justinvisser.wolfskin.design.ShellSurface
import org.justinvisser.wolfskin.design.WolfskinTheme
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import org.robolectric.annotation.GraphicsMode
/** The real asynchronous host must return focus from its loading nav to the first loaded action. */
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi")
@GraphicsMode(GraphicsMode.Mode.NATIVE)
class DiscoverLoadingFocusTest {
@get:Rule val rule = createAndroidComposeRule<ComponentActivity>()
@Test fun firstOkAfterLoadingOpensTheHeroInsteadOfSelectingTheNav() {
val pending = CompletableDeferred<DiscoverFixture>()
val shell = ShellState(listOf(ShellPerson("justin", "Justin", "J", true)), "justin").apply {
pickerVisible = false
enterDestination("discover")
}
lateinit var current: DiscoverState
rule.setContent {
val state = rememberDiscoverState(shell, shell::enterDestination, { shell.enterDestination("discover") }, loadFixture = { pending.await() })
current = state
WolfskinTheme { ShellSurface(shell) { DiscoverScreen(state, it) } }
}
rule.runOnIdle {
assertEquals(DiscoverStatus.Loading, current.snapshot.status)
assertTrue(shell.navFocused)
val json = rule.activity.assets.open("wolfskin-discover/fixture.json").bufferedReader().use { it.readText() }
pending.complete(DiscoverFixture(json) { "file:///android_asset/wolfskin-discover/$it" })
}
rule.waitForIdle()
rule.runOnIdle {
assertEquals(DiscoverStatus.Ready, current.snapshot.status)
assertFalse(shell.navFocused)
assertEquals(0, current.focusedRow)
}
rule.onNodeWithTag("wolfskin-shell").performKeyInput { pressKey(Key.DirectionCenter) }
rule.runOnIdle {
assertNotNull(current.title)
assertEquals("The Amazing Spider-Man", current.title!!.title)
assertEquals("discover-title/${current.title!!.key}", shell.route)
}
}
@Test fun finishingLoadPreservesANavTargetChosenWhileLoading() {
val pending = CompletableDeferred<DiscoverFixture>()
val shell = ShellState(listOf(ShellPerson("justin", "Justin", "J", true)), "justin").apply {
pickerVisible = false
enterDestination("discover")
}
lateinit var current: DiscoverState
rule.setContent {
val state = rememberDiscoverState(shell, shell::enterDestination, { shell.enterDestination("discover") }, loadFixture = { pending.await() })
current = state
WolfskinTheme { ShellSurface(shell) { DiscoverScreen(state, it) } }
}
rule.onNodeWithTag("wolfskin-shell").performKeyInput { pressKey(Key.DirectionRight) }
rule.runOnIdle {
assertEquals(DiscoverStatus.Loading, current.snapshot.status)
assertEquals(2, shell.navIndex)
val json = rule.activity.assets.open("wolfskin-discover/fixture.json").bufferedReader().use { it.readText() }
pending.complete(DiscoverFixture(json) { "file:///android_asset/wolfskin-discover/$it" })
}
rule.waitForIdle()
rule.runOnIdle {
assertEquals(DiscoverStatus.Ready, current.snapshot.status)
assertTrue(shell.navFocused)
assertEquals(2, shell.navIndex)
}
rule.onNodeWithTag("wolfskin-shell").performKeyInput { pressKey(Key.DirectionCenter) }
rule.runOnIdle {
assertEquals("movies", shell.route)
assertEquals(null, current.title)
}
}
}