Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,26 @@ package com.inspiredandroid.linuxcommandbibliotheca
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.activity.compose.setContent
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalWindowInfo
import androidx.compose.ui.platform.WindowInfo
import androidx.compose.ui.test.assertCountEquals
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertTextEquals
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onAllNodesWithContentDescription
import androidx.compose.ui.test.onAllNodesWithText
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.linuxcommandlibrary.app.App
import org.junit.Before
import org.junit.Rule
import org.junit.Test
Expand Down Expand Up @@ -77,6 +91,36 @@ class ComposeDeeplinkTests {
.assertTextEquals("Commands")
}

@Test
fun testCommandListDoesNotSelectFirstCommandOnExpandedLayout() {
// Pretend the window is tablet sized so the two-pane list/detail layout is used.
composeTestRule.runOnUiThread {
composeTestRule.activity.setContent {
val windowInfo = LocalWindowInfo.current
val density = LocalDensity.current
val expandedWindowInfo = remember(windowInfo, density) {
object : WindowInfo by windowInfo {
override val containerSize: IntSize
get() = with(density) { IntSize(1280.dp.roundToPx(), 800.dp.roundToPx()) }
}
}
CompositionLocalProvider(LocalWindowInfo provides expandedWindowInfo) {
App(initialDeeplink = "https://linuxcommandlibrary.com/")
}
}
}

// Wait for the command list to load before checking that nothing got selected.
composeTestRule.waitUntil(timeoutMillis = 10_000) {
composeTestRule.onAllNodesWithText("2048").fetchSemanticsNodes().isNotEmpty()
}
composeTestRule.waitForIdle()

composeTestRule.onNodeWithText("Select a command").assertIsDisplayed()
composeTestRule.onAllNodesWithContentDescription("Search in page")
.assertCountEquals(0)
}

@Test
fun testCommandDetail() {
openUrl("https://linuxcommandlibrary.com/man/2048")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ private fun CommandsTab(state: LinuxNavState, withTabStackOverlay: Boolean) {
onNavigate = state::onNavigate,
stack = commandsStack,
onPopStack = { state.popStack(RouteKey.Commands) },
isExpanded = !withTabStackOverlay,
)
if (withTabStackOverlay) {
TabStackTop(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import com.linuxcommandlibrary.app.ui.screens.commandlist.CommandListViewModel
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.ImmutableSet
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import org.koin.compose.koinInject

Expand All @@ -51,7 +50,6 @@ internal fun CommandsPaneScreen(
onNavigate: (NavEvent) -> Unit,
stack: SnapshotStateList<TabStackEntry>,
onPopStack: () -> Unit,
isExpanded: Boolean,
) {
val listViewModel: CommandListViewModel = koinInject()
val commands by listViewModel.commands.collectAsState()
Expand All @@ -63,20 +61,6 @@ internal fun CommandsPaneScreen(
onSelectionConsumed()
}

// Two-pane layouts: pre-select the first command once data loads so the detail
// pane shows real content instead of an empty placeholder. Compact (single-pane)
// skips this — auto-pushing to detail on launch would be jarring.
LaunchedEffect(isExpanded) {
if (!isExpanded) return@LaunchedEffect
val list = listViewModel.commands.first { it.isNotEmpty() }
if (navigator.currentDestination?.contentKey == null &&
stack.isEmpty() &&
pendingSelection == null
) {
navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, list.first().name)
}
}

// Hoisted so the LazyColumn keeps its scroll position across AnimatedPane's
// exit/enter cycle. Without hoisting, the pane content's nested rememberSaveable was
// intermittently coerced to 0 on re-mount because the bookmark-driven sort re-emits
Expand Down