feat(components): navigation slot and full-bleed content for the onboarding shell
A step that can be stepped back from passes navigationIcon. The slot's width is reserved whether or not it is filled, and mirrored on the other side, so the progress stays centred as steps come and go. contentPadding lets a step built from grouped rows drop the column's own inset, since those rows carry their own.
This commit is contained in:
@@ -33,6 +33,9 @@ import androidx.compose.ui.semantics.clearAndSetSemantics
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/** Standard touch target, reserved for the shell's navigation slot. */
|
||||
private val NavigationSlotSize = 48.dp
|
||||
|
||||
/** MD3 8dp spacing scale shared by the onboarding screens. */
|
||||
object OnboardingSpace {
|
||||
val xs = 8.dp
|
||||
@@ -50,8 +53,14 @@ object OnboardingSpace {
|
||||
* as one family while keeping their own mark.
|
||||
*
|
||||
* A multi-step flow passes [progress] (see [OnboardingProgress]), which is
|
||||
* pinned above the scrolling content. [topSpacing] gives a step whose hero is a
|
||||
* large picture rather than a mark room to breathe without overflowing.
|
||||
* pinned above the scrolling content, and [navigationIcon] for a step that can
|
||||
* be stepped back from. The navigation slot's width is reserved whether or not
|
||||
* it is filled, and mirrored on the other side, so the progress stays centred
|
||||
* and does not shift as steps come and go.
|
||||
*
|
||||
* [topSpacing] gives a step whose hero is a large picture rather than a mark
|
||||
* room to breathe. [contentPadding] is the scrolling column's own horizontal
|
||||
* inset — a step built from grouped rows passes 0, since those carry their own.
|
||||
*/
|
||||
@Composable
|
||||
fun OnboardingScaffold(
|
||||
@@ -59,21 +68,26 @@ fun OnboardingScaffold(
|
||||
actions: @Composable ColumnScope.() -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
progress: (@Composable () -> Unit)? = null,
|
||||
navigationIcon: (@Composable () -> Unit)? = null,
|
||||
topSpacing: Dp = OnboardingSpace.xl,
|
||||
contentPadding: Dp = OnboardingSpace.md,
|
||||
body: @Composable ColumnScope.() -> Unit,
|
||||
) {
|
||||
Scaffold(
|
||||
modifier = modifier,
|
||||
containerColor = MaterialTheme.colorScheme.surface,
|
||||
topBar = {
|
||||
if (progress != null) {
|
||||
Box(
|
||||
if (progress != null || navigationIcon != null) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.statusBarsPadding()
|
||||
.padding(horizontal = OnboardingSpace.md, vertical = OnboardingSpace.sm),
|
||||
.padding(horizontal = OnboardingSpace.xs, vertical = OnboardingSpace.sm),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
progress()
|
||||
Box(Modifier.size(NavigationSlotSize)) { navigationIcon?.invoke() }
|
||||
Box(Modifier.weight(1f)) { progress?.invoke() }
|
||||
Spacer(Modifier.width(NavigationSlotSize))
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -94,7 +108,7 @@ fun OnboardingScaffold(
|
||||
.fillMaxSize()
|
||||
.padding(innerPadding)
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(horizontal = OnboardingSpace.md),
|
||||
.padding(horizontal = contentPadding),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Spacer(Modifier.height(topSpacing))
|
||||
|
||||
Reference in New Issue
Block a user