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