A unified onboarding step, with a full-bleed adaptive hero #40
Labels
No Label
P0
P1
P2
release-blocker
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: null/Privacy-Period-Tracker#40
Loading…
Reference in New Issue
No description provided.
Delete Branch "%!s(<nil>)"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Seven hand-rolled step layouts become one component, and the illustration becomes a hero that spans the screen.
What is true now
Every step in
app/src/main/kotlin/dev/privacyllc/period/feature/onboarding/OnboardingScreen.kthand-rolls the same shape —Spacer → Illustration(size) → Spacer → Heading → controls— with three different spacer rhythms (32/32 on Welcome, 24/24 on four steps, 16/16 on steps 3 and 6) and a reason recorded for only two of the divergences.There is no shared layout component anywhere in
core/designsystem: no screen scaffold, no spacing constants. Spacing is hard-codeddpliterals in every feature file. The only reusable objects areIllustrationDefaultsandMarkerDefaults, both art-specific.Illustration()atcore/designsystem/src/main/kotlin/dev/privacyllc/period/designsystem/art/Illustrations.kt:149-174applies.height(size),ContentScale.FillHeightand.clip(RoundedCornerShape(18.dp)).What it costs
Seven copies of one layout is seven places for the rhythm to drift, and it already has. More immediately, the illustration cannot be made a hero while every step positions it independently.
What to do
OnboardingStep(artHeight, art, title, body, content)composable. The seven steps become declarations.artHeightstays a per-step parameter — see the traps.Illustration()becomes the hero:fillMaxWidth(),ContentScale.Crop, and.clip(...)removed along withIllustrationDefaults.CornerRadius. Rewrite the KDoc rather than deleting it — record that the corners went away when the art went full-bleed, so nobody restores them.BoxWithConstraintsand usemin(target, maxHeight * 0.32f).Brush.verticalGradientfromColor.TransparenttoMaterialTheme.colorScheme.backgroundover the bottom ~30%, inside aBox. The theme token, never a hard-coded colour.Heading()'s title moves fromheadlineMedium(28 sp) toheadlineLarge(32 sp). Body staysbodyLarge.Traps
Columnapplies a uniform.padding(24.dp), so nothing inside it can reach the screen edge. Change it tovertical = 24.dpand have the step component applyhorizontal = 24.dpto everything except the hero. Check the messageCardand theBackTextButtonstill get theirs.docs/qa/ClaudeQACoverage.md. Keep the comments explaining why.WindowSizeClassorLocalConfiguration, and onboarding does not lock orientation. The adaptive cap is what makes rotation survivable.TodayScreen.kt'sEmptyStateIllustrationorInsightsScreen.kt'sLearningIllustration. Those are in-page empty states, not heroes, and design rule 1 says nothing may compete with the forecast number.Verify: all seven steps driven by hand on
PeriodQAandPeriodMinSdk26, in both themes, at font scales 1.0, 1.3 and 2.0, with the primary button reachable on every step; plus one landscape pass on each device showing the hero shrinking rather than pushing the button off screen.Shipped in
ae27ef6. StepBody replaces seven hand-rolled step layouts; Illustration is full-bleed with ContentScale.Crop, no clip, and a theme-drawn bottom fade. Height caps at a third of the screen via LocalConfiguration.screenHeightDp — BoxWithConstraints cannot work here because a verticalScroll column measures children with an infinite height constraint. Screen padding moved off the scrolling column so the hero can reach the edges. Driven on PeriodMinSdk26: all steps, both themes, font scale 1.0 and 2.0, and landscape, where the cap holds the hero to 131dp instead of 280dp and the primary button stays visible.