Use LazyColumn for all nav drawer items

This commit is contained in:
Damontecres 2025-10-07 00:21:18 -04:00
parent ffc704bdce
commit 46073cbd74
No known key found for this signature in database
2 changed files with 117 additions and 66 deletions

View file

@ -5,6 +5,7 @@ import android.media.AudioManager
import android.view.KeyEvent
import androidx.compose.foundation.MarqueeAnimationMode
import androidx.compose.foundation.basicMarquee
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@ -17,6 +18,8 @@ import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.input.key.onPreviewKeyEvent
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.media3.common.Player
import kotlinx.coroutines.CoroutineScope
@ -26,6 +29,7 @@ import timber.log.Timber
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.math.min
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.minutes
@ -199,3 +203,29 @@ inline fun <T : Collection<*>, R> T.letNotEmpty(block: (T) -> R): R? {
}
return if (this.isNotEmpty()) block(this) else null
}
// Adapted from https://stackoverflow.com/a/69196765
fun Arrangement.spacedByWithFooter(space: Dp) =
object : Arrangement.Vertical {
override val spacing = space
override fun Density.arrange(
totalSize: Int,
sizes: IntArray,
outPositions: IntArray,
) {
if (sizes.isEmpty()) return
val spacePx = space.roundToPx()
var occupied = 0
sizes.forEachIndexed { index, size ->
if (index == sizes.lastIndex) {
outPositions[index] = totalSize - size
} else {
outPositions[index] = min(occupied, totalSize - size)
}
val lastSpace = min(spacePx, totalSize - outPositions[index] - size)
occupied = outPositions[index] + size + lastSpace
}
}
}

View file

@ -7,7 +7,6 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsFocusedAsState
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
@ -27,8 +26,8 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusProperties
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.focusRestorer
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
@ -60,6 +59,9 @@ import com.github.damontecres.dolphin.data.ServerRepository
import com.github.damontecres.dolphin.data.model.BaseItem
import com.github.damontecres.dolphin.preferences.UserPreferences
import com.github.damontecres.dolphin.ui.FontAwesome
import com.github.damontecres.dolphin.ui.ifElse
import com.github.damontecres.dolphin.ui.spacedByWithFooter
import com.github.damontecres.dolphin.ui.tryRequestFocus
import com.github.damontecres.dolphin.util.ExceptionHandler
import com.github.damontecres.dolphin.util.supportedCollectionTypes
import dagger.hilt.android.lifecycle.HiltViewModel
@ -124,6 +126,7 @@ fun NavDrawer(
}
val libraries by viewModel.libraries.observeAsState(listOf())
val selectedIndex by viewModel.selectedIndex.observeAsState(-1)
val focusRequester = remember { FocusRequester() }
NavigationDrawer(
modifier =
@ -132,16 +135,22 @@ fun NavDrawer(
drawerState = drawerState,
drawerContent = {
ProvideTextStyle(MaterialTheme.typography.labelMedium) {
Column(
verticalArrangement = Arrangement.spacedBy(8.dp),
LazyColumn(
state = listState,
contentPadding = PaddingValues(0.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedByWithFooter(8.dp),
modifier =
Modifier
.focusGroup()
// TODO fix focus restorer
.focusRestorer()
.fillMaxHeight()
.focusProperties {
onEnter = {
focusRequester.tryRequestFocus()
}
}.fillMaxHeight()
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp)),
) {
item {
IconNavItem(
text = user?.name ?: "",
subtext = server?.name ?: server?.url,
@ -151,6 +160,8 @@ fun NavDrawer(
navigationManager.navigateTo(Destination.UserList)
},
)
}
item {
IconNavItem(
text = "Search",
icon = Icons.Default.Search,
@ -159,7 +170,14 @@ fun NavDrawer(
viewModel.setIndex(-2)
navigationManager.navigateToFromDrawer(Destination.Search)
},
modifier =
Modifier.ifElse(
selectedIndex == -2,
Modifier.focusRequester(focusRequester),
),
)
}
item {
IconNavItem(
text = "Home",
icon = Icons.Default.Home,
@ -172,16 +190,13 @@ fun NavDrawer(
navigationManager.goToHome()
}
},
)
LazyColumn(
state = listState,
contentPadding = PaddingValues(0.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier =
Modifier
.weight(1f),
) {
Modifier.ifElse(
selectedIndex == -1,
Modifier.focusRequester(focusRequester),
),
)
}
itemsIndexed(libraries) { index, it ->
LibraryNavItem(
library = it,
@ -190,9 +205,14 @@ fun NavDrawer(
viewModel.setIndex(index)
navigationManager.navigateToFromDrawer(it.destination())
},
modifier =
Modifier.ifElse(
selectedIndex == index,
Modifier.focusRequester(focusRequester),
),
)
}
}
item {
IconNavItem(
text = "Settings",
icon = Icons.Default.Settings,
@ -204,6 +224,7 @@ fun NavDrawer(
)
}
}
}
},
) {
// Drawer content