add wide navbar

This commit is contained in:
2026-08-15 13:13:16 +03:00
parent 333ef152f8
commit e99743a9df
@@ -1,6 +1,7 @@
package ru.shadowsparky.ui
import androidx.compose.foundation.background
import androidx.compose.foundation.focusGroup
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.WindowInsets
@@ -23,16 +24,27 @@ import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.WideNavigationRail
import androidx.compose.material3.WideNavigationRailItem
import androidx.compose.material3.WideNavigationRailValue
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfoV2
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuite
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteItem
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffold
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffoldDefaults
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffoldLayout
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteType
import androidx.compose.material3.rememberWideNavigationRailState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
@@ -84,11 +96,13 @@ fun <T : Route> AppScaffold(
) {
val navigationSuiteType = when {
navigationEntries.isNullOrEmpty() -> NavigationSuiteType.None
else -> { NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(currentWindowAdaptiveInfoV2()) }
else -> NavigationSuiteScaffoldDefaults.navigationSuiteType(currentWindowAdaptiveInfoV2())
}
val blurState = rememberBlurState()
CompositionLocalProvider(LocalBlurState provides blurState) {
when (navigationSuiteType) {
NavigationSuiteType.ShortNavigationBarCompact,
NavigationSuiteType.ShortNavigationBarMedium,
NavigationSuiteType.NavigationBar -> {
BottomBarScaffold(
modifier,
@@ -118,6 +132,7 @@ fun <T : Route> AppScaffold(
}
}
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
private fun <T : Route> DynamicNavigationScaffold(
modifier: Modifier,
@@ -126,28 +141,67 @@ private fun <T : Route> DynamicNavigationScaffold(
currentRoute: T?,
onSelectNavigation: ((T) -> Unit)?,
scrollBehavior: TopAppBarScrollBehavior?,
appBar: @Composable ((TopAppBarScrollBehavior?) -> Unit),
appBar: @Composable (TopAppBarScrollBehavior?) -> Unit,
snackbarState: SnackbarHostState?,
content: @Composable ((PaddingValues) -> Unit)
content: @Composable (PaddingValues) -> Unit,
) {
NavigationSuiteScaffold(
val entries = navigationEntries.orEmpty()
val isWideRail = navigationSuiteType == NavigationSuiteType.WideNavigationRailCollapsed ||
navigationSuiteType == NavigationSuiteType.WideNavigationRailExpanded
val railState = rememberWideNavigationRailState(
initialValue = WideNavigationRailValue.Collapsed
)
var railHasFocus by remember { mutableStateOf(false) }
LaunchedEffect(railHasFocus) {
if (railHasFocus) railState.expand() else railState.collapse()
}
NavigationSuiteScaffoldLayout(
navigationSuiteType = navigationSuiteType,
navigationItems = {
navigationEntries.orEmpty().forEach { entry ->
NavigationSuiteItem(
navigationSuiteType = navigationSuiteType,
selected = currentRoute == entry.route,
onClick = { onSelectNavigation?.invoke(entry.route) },
icon = { Icon(entry.painter, entry.title) },
label = {
when (navigationSuiteType) {
NavigationSuiteType.NavigationDrawer -> Text(entry.title)
}
},
modifier = Modifier.focusBorder(false, CircleShape)
)
navigationSuite = {
if (isWideRail) {
WideNavigationRail(
state = railState,
modifier = Modifier.onFocusChanged { railHasFocus = it.hasFocus }
.focusGroup(),
) {
entries.forEach { entry ->
WideNavigationRailItem(
railExpanded =
railState.targetValue == WideNavigationRailValue.Expanded,
selected = currentRoute == entry.route,
onClick = {
onSelectNavigation?.invoke(entry.route)
},
icon = {
Icon(entry.painter, entry.title)
},
label = { Text(entry.title) },
modifier = Modifier.focusBorder(false, CircleShape)
)
}
}
} else {
NavigationSuite(navigationSuiteType = navigationSuiteType) {
entries.forEach { entry ->
NavigationSuiteItem(
navigationSuiteType = navigationSuiteType,
selected = currentRoute == entry.route,
onClick = {
onSelectNavigation?.invoke(entry.route)
},
icon = {
Icon(
painter = entry.painter,
contentDescription = entry.title,
)
},
label = { Text(entry.title) },
modifier = Modifier.focusBorder(false, CircleShape)
)
}
}
}
}
},
) {
Scaffold(
modifier = if (scrollBehavior != null) {
@@ -156,7 +210,9 @@ private fun <T : Route> DynamicNavigationScaffold(
modifier
},
topBar = { appBar(scrollBehavior) },
snackbarHost = { snackbarState?.let { SnackbarHost(it) } },
snackbarHost = {
snackbarState?.let { SnackbarHost(it) }
},
content = content
)
}