Compare commits
No commits in common. "df8614bf8b11b84746ba06d9ca1c03ebd9f4ab41" and "7d6f041b55eb07cd8f6b1eba5063039dff6dec3e" have entirely different histories.
df8614bf8b
...
7d6f041b55
2 changed files with 7 additions and 100 deletions
|
|
@ -16,7 +16,6 @@ import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.layout.wrapContentWidth
|
import androidx.compose.foundation.layout.wrapContentWidth
|
||||||
import androidx.compose.foundation.lazy.LazyRow
|
import androidx.compose.foundation.lazy.LazyRow
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Add
|
import androidx.compose.material.icons.filled.Add
|
||||||
|
|
@ -89,24 +88,19 @@ fun UserList(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
contentAlignment = Alignment.Center,
|
contentAlignment = Alignment.Center,
|
||||||
) {
|
) {
|
||||||
val listState = rememberLazyListState()
|
val focusRequester = remember { FocusRequester() }
|
||||||
val initialFocusRequester = remember { FocusRequester() }
|
val firstFocusRequester = remember { FocusRequester() }
|
||||||
val initialIndex =
|
if (users.isNotEmpty()) {
|
||||||
users.indexOfFirst { it.user.id == currentUser?.id }.takeIf { it >= 0 } ?: 0
|
LaunchedEffect(Unit) { focusRequester.tryRequestFocus() }
|
||||||
LaunchedEffect(users, currentUser?.id) {
|
|
||||||
if (users.isNotEmpty()) {
|
|
||||||
listState.scrollToItem(initialIndex)
|
|
||||||
initialFocusRequester.tryRequestFocus()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
LazyRow(
|
LazyRow(
|
||||||
state = listState,
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(24.dp), // Spacing to accommodate 20% scale
|
horizontalArrangement = Arrangement.spacedBy(24.dp), // Spacing to accommodate 20% scale
|
||||||
contentPadding = PaddingValues(horizontal = 48.dp, vertical = 16.dp), // Increased padding to accommodate 20% scale
|
contentPadding = PaddingValues(horizontal = 48.dp, vertical = 16.dp), // Increased padding to accommodate 20% scale
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.wrapContentWidth()
|
.wrapContentWidth()
|
||||||
.focusRestorer(initialFocusRequester),
|
.focusRestorer(firstFocusRequester)
|
||||||
|
.focusRequester(focusRequester),
|
||||||
) {
|
) {
|
||||||
itemsIndexed(users) { index, user ->
|
itemsIndexed(users) { index, user ->
|
||||||
UserIconCard(
|
UserIconCard(
|
||||||
|
|
@ -114,7 +108,7 @@ fun UserList(
|
||||||
isCurrentUser = user.user.id == currentUser?.id,
|
isCurrentUser = user.user.id == currentUser?.id,
|
||||||
onClick = { onSwitchUser.invoke(user.user) },
|
onClick = { onSwitchUser.invoke(user.user) },
|
||||||
onLongClick = { showDeleteDialog = user },
|
onLongClick = { showDeleteDialog = user },
|
||||||
modifier = if (index == initialIndex) Modifier.focusRequester(initialFocusRequester) else Modifier,
|
modifier = if (index == 0) Modifier.focusRequester(firstFocusRequester) else Modifier,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// Add User card - always rightmost
|
// Add User card - always rightmost
|
||||||
|
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
package com.github.damontecres.wholphin.ui.setup
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.input.key.Key
|
|
||||||
import androidx.compose.ui.test.assertIsFocused
|
|
||||||
import androidx.compose.ui.test.junit4.createComposeRule
|
|
||||||
import androidx.compose.ui.test.onNodeWithText
|
|
||||||
import androidx.compose.ui.test.performKeyInput
|
|
||||||
import androidx.compose.ui.test.pressKey
|
|
||||||
import com.github.damontecres.wholphin.data.model.JellyfinUser
|
|
||||||
import com.github.damontecres.wholphin.ui.theme.WholphinTheme
|
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.robolectric.RobolectricTestRunner
|
|
||||||
import org.robolectric.annotation.Config
|
|
||||||
import java.util.UUID
|
|
||||||
|
|
||||||
@Config(sdk = [34])
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
|
||||||
class UserListFocusTest {
|
|
||||||
@get:Rule val composeTestRule = createComposeRule()
|
|
||||||
|
|
||||||
private val serverId = UUID.fromString("00000000-0000-0000-0000-000000000010")
|
|
||||||
private val users =
|
|
||||||
listOf("Ada", "Bert", "Cleo").mapIndexed { index, name ->
|
|
||||||
JellyfinUserAndImage(
|
|
||||||
user =
|
|
||||||
JellyfinUser(
|
|
||||||
id = UUID(0, (index + 1).toLong()),
|
|
||||||
name = name,
|
|
||||||
serverId = serverId,
|
|
||||||
accessToken = "token",
|
|
||||||
),
|
|
||||||
imageUrl = null,
|
|
||||||
known = true,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showUsers(currentUser: JellyfinUser?) {
|
|
||||||
composeTestRule.setContent {
|
|
||||||
WholphinTheme {
|
|
||||||
UserList(
|
|
||||||
users = users,
|
|
||||||
currentUser = currentUser,
|
|
||||||
onSwitchUser = {},
|
|
||||||
onAddUser = {},
|
|
||||||
onRemoveUser = {},
|
|
||||||
onSwitchServer = {},
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `opening selector focuses active profile and supports D-pad navigation`() {
|
|
||||||
showUsers(users[1].user)
|
|
||||||
|
|
||||||
composeTestRule.onNodeWithText("B").assertIsFocused().performKeyInput {
|
|
||||||
pressKey(Key.DirectionRight)
|
|
||||||
}
|
|
||||||
composeTestRule.onNodeWithText("C").assertIsFocused()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `opening selector scrolls to an active profile outside the initial viewport`() {
|
|
||||||
showUsers(users[2].user)
|
|
||||||
|
|
||||||
composeTestRule.onNodeWithText("C").assertIsFocused()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `opening selector without a listed active profile focuses first profile`() {
|
|
||||||
showUsers(null)
|
|
||||||
|
|
||||||
composeTestRule.onNodeWithText("A").assertIsFocused()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `opening selector with a removed active profile focuses first profile`() {
|
|
||||||
showUsers(users[1].user.copy(id = UUID(0, 99)))
|
|
||||||
|
|
||||||
composeTestRule.onNodeWithText("A").assertIsFocused()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue