add hamburger icon to rail
This commit is contained in:
@@ -7,7 +7,7 @@ plugins {
|
|||||||
alias(libs.plugins.convention.ktor.client)
|
alias(libs.plugins.convention.ktor.client)
|
||||||
}
|
}
|
||||||
|
|
||||||
val appVersion = "1.26.4"
|
val appVersion = "1.26.5"
|
||||||
|
|
||||||
android {
|
android {
|
||||||
buildFeatures { buildConfig = true }
|
buildFeatures { buildConfig = true }
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="?attr/colorControlNormal"
|
||||||
|
android:viewportWidth="960"
|
||||||
|
android:viewportHeight="960">
|
||||||
|
<path
|
||||||
|
android:fillColor="#fff"
|
||||||
|
android:pathData="M120,720L120,640L840,640L840,720L120,720ZM120,520L120,440L840,440L840,520L120,520ZM120,320L120,240L840,240L840,320L120,320Z" />
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:autoMirrored="true"
|
||||||
|
android:tint="?attr/colorControlNormal"
|
||||||
|
android:viewportWidth="960"
|
||||||
|
android:viewportHeight="960">
|
||||||
|
<path
|
||||||
|
android:fillColor="#fff"
|
||||||
|
android:pathData="M120,720L120,640L640,640L640,720L120,720ZM784,680L584,480L784,280L840,336L696,480L840,624L784,680ZM120,520L120,440L520,440L520,520L120,520ZM120,320L120,240L640,240L640,320L120,320Z" />
|
||||||
|
</vector>
|
||||||
@@ -1,52 +1,22 @@
|
|||||||
package ru.shadowsparky.ui
|
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.PaddingValues
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.navigationBars
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.NavigationBar
|
|
||||||
import androidx.compose.material3.NavigationBarDefaults
|
|
||||||
import androidx.compose.material3.NavigationBarItem
|
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.SnackbarHost
|
import androidx.compose.material3.SnackbarHost
|
||||||
import androidx.compose.material3.SnackbarHostState
|
import androidx.compose.material3.SnackbarHostState
|
||||||
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.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.focus.onFocusChanged
|
|
||||||
import androidx.compose.ui.graphics.Brush
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.graphics.painter.Painter
|
import androidx.compose.ui.graphics.painter.Painter
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import ru.shadowsparky.ui.nav.Route
|
import ru.shadowsparky.ui.nav.Route
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@@ -141,128 +111,3 @@ fun <T : Route> AppScaffold(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
|
||||||
private fun <T : Route> DynamicNavigationScaffold(
|
|
||||||
modifier: Modifier,
|
|
||||||
navigationSuiteType: NavigationSuiteType,
|
|
||||||
navigationEntries: List<NavigationEntry<T>>?,
|
|
||||||
currentRoute: T?,
|
|
||||||
onSelectNavigation: ((T) -> Unit)?,
|
|
||||||
scrollBehavior: TopAppBarScrollBehavior?,
|
|
||||||
appBar: @Composable (TopAppBarScrollBehavior?) -> Unit,
|
|
||||||
snackbarState: SnackbarHostState?,
|
|
||||||
content: @Composable (PaddingValues) -> Unit,
|
|
||||||
) {
|
|
||||||
val entries = navigationEntries.orEmpty()
|
|
||||||
val railState = rememberWideNavigationRailState(WideNavigationRailValue.Collapsed)
|
|
||||||
val isExpanded = railState.targetValue == WideNavigationRailValue.Expanded
|
|
||||||
var railHasFocus by remember { mutableStateOf(false) }
|
|
||||||
LaunchedEffect(railHasFocus) {
|
|
||||||
if (railHasFocus) railState.expand() else railState.collapse()
|
|
||||||
}
|
|
||||||
NavigationSuiteScaffoldLayout(
|
|
||||||
navigationSuiteType = navigationSuiteType,
|
|
||||||
navigationSuite = {
|
|
||||||
WideNavigationRail(
|
|
||||||
state = railState,
|
|
||||||
modifier = Modifier.onFocusChanged { railHasFocus = it.hasFocus }.focusGroup()
|
|
||||||
) {
|
|
||||||
entries.forEach { entry ->
|
|
||||||
WideNavigationRailItem(
|
|
||||||
railExpanded = isExpanded,
|
|
||||||
selected = currentRoute == entry.route,
|
|
||||||
onClick = { onSelectNavigation?.invoke(entry.route) },
|
|
||||||
icon = { Icon(entry.painter, entry.title) },
|
|
||||||
label = {
|
|
||||||
if (isExpanded) Text(entry.title)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
Scaffold(
|
|
||||||
modifier = if (scrollBehavior != null) {
|
|
||||||
modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
|
|
||||||
} else {
|
|
||||||
modifier
|
|
||||||
},
|
|
||||||
topBar = { appBar(scrollBehavior) },
|
|
||||||
snackbarHost = {
|
|
||||||
snackbarState?.let { SnackbarHost(it) }
|
|
||||||
},
|
|
||||||
content = content
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
|
||||||
private fun <T : Route> BottomBarScaffold(
|
|
||||||
modifier: Modifier,
|
|
||||||
navigationEntries: List<NavigationEntry<T>>?,
|
|
||||||
currentRoute: T?,
|
|
||||||
appBar: @Composable (scroll: TopAppBarScrollBehavior?) -> Unit,
|
|
||||||
content: @Composable (padding: PaddingValues) -> Unit,
|
|
||||||
scrollBehavior: TopAppBarScrollBehavior?,
|
|
||||||
onSelectNavigation: ((T) -> Unit)?,
|
|
||||||
snackbarState: SnackbarHostState?
|
|
||||||
) {
|
|
||||||
Scaffold(
|
|
||||||
bottomBar = { BottomBar(navigationEntries, currentRoute, onSelectNavigation) },
|
|
||||||
topBar = { appBar(scrollBehavior) },
|
|
||||||
modifier = if (scrollBehavior != null) {
|
|
||||||
modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
|
|
||||||
} else {
|
|
||||||
modifier
|
|
||||||
}, snackbarHost = {
|
|
||||||
snackbarState?.let { SnackbarHost(it) }
|
|
||||||
},
|
|
||||||
content = content
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun <T : Route> BottomBar(
|
|
||||||
navigationEntries: List<NavigationEntry<T>>?,
|
|
||||||
currentRoute: T?,
|
|
||||||
onSelectNavigation: ((T) -> Unit)?
|
|
||||||
) {
|
|
||||||
navigationEntries?.let { entries ->
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.background(
|
|
||||||
Brush.verticalGradient(
|
|
||||||
listOf(Color.Transparent, MaterialTheme.colorScheme.surfaceContainer)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.padding(8.dp)
|
|
||||||
.windowInsetsPadding(WindowInsets.navigationBars)
|
|
||||||
) {
|
|
||||||
NavigationBar(
|
|
||||||
containerColor = navBarContentColor(),
|
|
||||||
modifier = Modifier.clip(RoundedCornerShape(24.dp)).blurEffect()
|
|
||||||
) {
|
|
||||||
entries.forEach { entry ->
|
|
||||||
NavigationBarItem(
|
|
||||||
selected = currentRoute == entry.route,
|
|
||||||
onClick = { onSelectNavigation?.invoke(entry.route) },
|
|
||||||
icon = { Icon(entry.painter, contentDescription = entry.title) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun navBarContentColor(): Color {
|
|
||||||
return if (isBlurEnabled()) {
|
|
||||||
MaterialTheme.colorScheme.surfaceContainerHigh.copy(alpha = 0.5f)
|
|
||||||
} else {
|
|
||||||
NavigationBarDefaults.containerColor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
package ru.shadowsparky.ui
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.navigationBars
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.NavigationBar
|
||||||
|
import androidx.compose.material3.NavigationBarDefaults
|
||||||
|
import androidx.compose.material3.NavigationBarItem
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.SnackbarHost
|
||||||
|
import androidx.compose.material3.SnackbarHostState
|
||||||
|
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.Brush
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import ru.shadowsparky.ui.nav.Route
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
internal fun <T : Route> BottomBarScaffold(
|
||||||
|
modifier: Modifier,
|
||||||
|
navigationEntries: List<NavigationEntry<T>>?,
|
||||||
|
currentRoute: T?,
|
||||||
|
appBar: @Composable (scroll: TopAppBarScrollBehavior?) -> Unit,
|
||||||
|
content: @Composable (padding: PaddingValues) -> Unit,
|
||||||
|
scrollBehavior: TopAppBarScrollBehavior?,
|
||||||
|
onSelectNavigation: ((T) -> Unit)?,
|
||||||
|
snackbarState: SnackbarHostState?
|
||||||
|
) {
|
||||||
|
Scaffold(
|
||||||
|
bottomBar = { BottomBar(navigationEntries, currentRoute, onSelectNavigation) },
|
||||||
|
topBar = { appBar(scrollBehavior) },
|
||||||
|
modifier = if (scrollBehavior != null) {
|
||||||
|
modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
|
||||||
|
} else {
|
||||||
|
modifier
|
||||||
|
}, snackbarHost = {
|
||||||
|
snackbarState?.let { SnackbarHost(it) }
|
||||||
|
},
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun <T : Route> BottomBar(
|
||||||
|
navigationEntries: List<NavigationEntry<T>>?,
|
||||||
|
currentRoute: T?,
|
||||||
|
onSelectNavigation: ((T) -> Unit)?
|
||||||
|
) {
|
||||||
|
navigationEntries?.let { entries ->
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(
|
||||||
|
Brush.verticalGradient(
|
||||||
|
listOf(Color.Transparent, MaterialTheme.colorScheme.surfaceContainer)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.padding(8.dp)
|
||||||
|
.windowInsetsPadding(WindowInsets.navigationBars)
|
||||||
|
) {
|
||||||
|
NavigationBar(
|
||||||
|
containerColor = navBarContentColor(),
|
||||||
|
modifier = Modifier.clip(RoundedCornerShape(24.dp)).blurEffect()
|
||||||
|
) {
|
||||||
|
entries.forEach { entry ->
|
||||||
|
NavigationBarItem(
|
||||||
|
selected = currentRoute == entry.route,
|
||||||
|
onClick = { onSelectNavigation?.invoke(entry.route) },
|
||||||
|
icon = { Icon(entry.painter, contentDescription = entry.title) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun navBarContentColor(): Color {
|
||||||
|
return if (isBlurEnabled()) {
|
||||||
|
MaterialTheme.colorScheme.surfaceContainerHigh.copy(alpha = 0.5f)
|
||||||
|
} else {
|
||||||
|
NavigationBarDefaults.containerColor
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
package ru.shadowsparky.ui
|
||||||
|
|
||||||
|
import androiddev.libs.ui.generated.resources.Res
|
||||||
|
import androiddev.libs.ui.generated.resources.menu
|
||||||
|
import androiddev.libs.ui.generated.resources.menu_open
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.SnackbarHost
|
||||||
|
import androidx.compose.material3.SnackbarHostState
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||||
|
import androidx.compose.material3.WideNavigationRail
|
||||||
|
import androidx.compose.material3.WideNavigationRailItem
|
||||||
|
import androidx.compose.material3.WideNavigationRailState
|
||||||
|
import androidx.compose.material3.WideNavigationRailValue
|
||||||
|
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.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.compositionLocalOf
|
||||||
|
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.input.nestedscroll.nestedScroll
|
||||||
|
import org.jetbrains.compose.resources.painterResource
|
||||||
|
import ru.shadowsparky.ui.nav.Route
|
||||||
|
|
||||||
|
internal val LocalWideNavigationRailState = compositionLocalOf<WideNavigationRailState?> { null }
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
internal fun <T : Route> DynamicNavigationScaffold(
|
||||||
|
modifier: Modifier,
|
||||||
|
navigationSuiteType: NavigationSuiteType,
|
||||||
|
navigationEntries: List<NavigationEntry<T>>?,
|
||||||
|
currentRoute: T?,
|
||||||
|
onSelectNavigation: ((T) -> Unit)?,
|
||||||
|
scrollBehavior: TopAppBarScrollBehavior?,
|
||||||
|
appBar: @Composable (TopAppBarScrollBehavior?) -> Unit,
|
||||||
|
snackbarState: SnackbarHostState?,
|
||||||
|
content: @Composable (PaddingValues) -> Unit,
|
||||||
|
) {
|
||||||
|
val entries = navigationEntries.orEmpty()
|
||||||
|
val railState = LocalWideNavigationRailState.current
|
||||||
|
?: rememberWideNavigationRailState(WideNavigationRailValue.Collapsed)
|
||||||
|
var isExpanded by remember {
|
||||||
|
mutableStateOf(railState.targetValue == WideNavigationRailValue.Expanded)
|
||||||
|
}
|
||||||
|
LaunchedEffect(isExpanded) {
|
||||||
|
if (!isExpanded) railState.collapse() else railState.expand()
|
||||||
|
}
|
||||||
|
NavigationSuiteScaffoldLayout(
|
||||||
|
navigationSuiteType = navigationSuiteType,
|
||||||
|
navigationSuite = {
|
||||||
|
WideNavigationRail(state = railState) {
|
||||||
|
val resId = if (isExpanded) Res.drawable.menu_open else Res.drawable.menu
|
||||||
|
WideNavigationRailItem(
|
||||||
|
false,
|
||||||
|
onClick = { isExpanded = !isExpanded },
|
||||||
|
icon = { Icon(painterResource(resId), null) },
|
||||||
|
label = {},
|
||||||
|
railExpanded = isExpanded
|
||||||
|
)
|
||||||
|
entries.forEach { entry ->
|
||||||
|
WideNavigationRailItem(
|
||||||
|
railExpanded = isExpanded,
|
||||||
|
selected = currentRoute == entry.route,
|
||||||
|
onClick = { onSelectNavigation?.invoke(entry.route) },
|
||||||
|
icon = { Icon(entry.painter, entry.title) },
|
||||||
|
label = { if (isExpanded) Text(entry.title) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Scaffold(
|
||||||
|
modifier = if (scrollBehavior != null) {
|
||||||
|
modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
|
||||||
|
} else {
|
||||||
|
modifier
|
||||||
|
},
|
||||||
|
topBar = { appBar(scrollBehavior) },
|
||||||
|
snackbarHost = { snackbarState?.let { SnackbarHost(it) } },
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -104,21 +104,14 @@ fun ExpressiveLazyColumn(
|
|||||||
verticalArrangement = verticalArrangement
|
verticalArrangement = verticalArrangement
|
||||||
) {
|
) {
|
||||||
scope.sections.forEachIndexed { sectionIndex, section ->
|
scope.sections.forEachIndexed { sectionIndex, section ->
|
||||||
|
|
||||||
if (sectionIndex != 0 && sectionSpacing > 0.dp) {
|
if (sectionIndex != 0 && sectionSpacing > 0.dp) {
|
||||||
item(key = "sectionSpacer_$sectionIndex") {
|
item(key = "sectionSpacer_$sectionIndex") {
|
||||||
Spacer(
|
Spacer(Modifier.animateItem().height(sectionSpacing))
|
||||||
Modifier
|
|
||||||
.animateItem()
|
|
||||||
.height(sectionSpacing)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
section.nodes.forEachIndexed { index, node ->
|
section.nodes.forEachIndexed { index, node ->
|
||||||
val topRadius = if (index == 0) roundedMax else roundedMin
|
val topRadius = if (index == 0) roundedMax else roundedMin
|
||||||
val bottomRadius = if (index == section.nodes.lastIndex) roundedMax else roundedMin
|
val bottomRadius = if (index == section.nodes.lastIndex) roundedMax else roundedMin
|
||||||
|
|
||||||
item(key = node.key, contentType = node.contentType) {
|
item(key = node.key, contentType = node.contentType) {
|
||||||
ExpressiveCard(
|
ExpressiveCard(
|
||||||
topRadius = if (reverseLayout) bottomRadius else topRadius,
|
topRadius = if (reverseLayout) bottomRadius else topRadius,
|
||||||
|
|||||||
@@ -2,13 +2,17 @@ package ru.shadowsparky.ui.nav
|
|||||||
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||||
import androidx.compose.material3.MaterialExpressiveTheme
|
import androidx.compose.material3.MaterialExpressiveTheme
|
||||||
|
import androidx.compose.material3.WideNavigationRailValue
|
||||||
|
import androidx.compose.material3.rememberWideNavigationRailState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import com.arkivanov.decompose.ExperimentalDecomposeApi
|
import com.arkivanov.decompose.ExperimentalDecomposeApi
|
||||||
import com.arkivanov.decompose.extensions.compose.stack.Children
|
import com.arkivanov.decompose.extensions.compose.stack.Children
|
||||||
import com.arkivanov.decompose.extensions.compose.stack.animation.fade
|
import com.arkivanov.decompose.extensions.compose.stack.animation.fade
|
||||||
import com.arkivanov.decompose.extensions.compose.stack.animation.predictiveback.androidPredictiveBackAnimatableV2
|
import com.arkivanov.decompose.extensions.compose.stack.animation.predictiveback.androidPredictiveBackAnimatableV2
|
||||||
import com.arkivanov.decompose.extensions.compose.stack.animation.predictiveback.predictiveBackAnimation
|
import com.arkivanov.decompose.extensions.compose.stack.animation.predictiveback.predictiveBackAnimation
|
||||||
import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation
|
import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation
|
||||||
|
import ru.shadowsparky.ui.LocalWideNavigationRailState
|
||||||
import ru.shadowsparky.ui.theme.getColorScheme
|
import ru.shadowsparky.ui.theme.getColorScheme
|
||||||
|
|
||||||
@OptIn(ExperimentalDecomposeApi::class, ExperimentalMaterial3ExpressiveApi::class)
|
@OptIn(ExperimentalDecomposeApi::class, ExperimentalMaterial3ExpressiveApi::class)
|
||||||
@@ -17,17 +21,20 @@ fun Nav(
|
|||||||
rootComponent: RootComponent<*>,
|
rootComponent: RootComponent<*>,
|
||||||
process: @Composable (child: Child, route: Route) -> Unit
|
process: @Composable (child: Child, route: Route) -> Unit
|
||||||
) {
|
) {
|
||||||
MaterialExpressiveTheme(getColorScheme()) {
|
val railState = rememberWideNavigationRailState(WideNavigationRailValue.Collapsed)
|
||||||
Children(
|
CompositionLocalProvider(LocalWideNavigationRailState provides railState) {
|
||||||
stack = rootComponent.valueChildStack,
|
MaterialExpressiveTheme(getColorScheme()) {
|
||||||
animation = predictiveBackAnimation(
|
Children(
|
||||||
backHandler = rootComponent.backHandler,
|
stack = rootComponent.valueChildStack,
|
||||||
fallbackAnimation = stackAnimation(fade()),
|
animation = predictiveBackAnimation(
|
||||||
onBack = rootComponent::onBack,
|
backHandler = rootComponent.backHandler,
|
||||||
selector = { backEvent, _, _ -> androidPredictiveBackAnimatableV2(backEvent) },
|
fallbackAnimation = stackAnimation(fade()),
|
||||||
),
|
onBack = rootComponent::onBack,
|
||||||
) {
|
selector = { backEvent, _, _ -> androidPredictiveBackAnimatableV2(backEvent) },
|
||||||
process(it.instance, it.configuration as Route)
|
),
|
||||||
|
) {
|
||||||
|
process(it.instance, it.configuration as Route)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user