Stepper Models & Enums¶
This document covers the essential data models, enums, and utility classes used by the JetCo Stepper components. Understanding these models is crucial for implementing steppers effectively.
🎯 StepperNode¶
The core data class representing a single step in any stepper component.
Structure¶
data class StepperNode(
val title: String? = null,
val description: String? = null,
val icon: ImageVector? = null,
val painter: Painter? = null,
val status: StepperStatus = StepperStatus.IDLE
)
Parameters¶
Parameter | Type | Default | Description |
---|---|---|---|
title |
String? |
null |
Short title describing the step |
description |
String? |
null |
Optional secondary text with additional details |
icon |
ImageVector? |
null |
Custom vector icon for the step |
painter |
Painter? |
null |
Custom painter for images (VerticalStepper only) |
status |
StepperStatus |
StepperStatus.IDLE |
Current status of the step |
Example Usage¶
// Basic step with title only
val basicStep = StepperNode(
title = "Complete Profile",
status = StepperStatus.ACTIVE
)
// Detailed step with description
val detailedStep = StepperNode(
title = "Upload Documents",
description = "Please upload your identity documents for verification",
status = StepperStatus.IDLE
)
// Step with custom icon
val iconStep = StepperNode(
title = "Payment",
description = "Enter your payment information",
icon = Icons.Default.Payment,
status = StepperStatus.COMPLETE
)
// Step with image (VerticalStepper only)
val imageStep = StepperNode(
title = "Welcome",
description = "Welcome to our amazing platform",
painter = painterResource(R.drawable.welcome_image),
status = StepperStatus.COMPLETE
)
📊 StepperStatus¶
Enum representing the possible states of a step within the stepper.
Values¶
Status | Description | Visual Indicator |
---|---|---|
COMPLETE |
Step has been completed successfully | ✅ Completed color + check icon |
ACTIVE |
Step is currently active or in progress | 🎯 Active color + custom/default icon |
IDLE |
Step is inactive or pending | ⭕ Inactive color + number/icon |
ERROR |
Step has encountered an error state | ❌ Error color + error icon |
Example Usage¶
val steps = listOf(
StepperNode("Sign Up", status = StepperStatus.COMPLETE),
StepperNode("Verify Email", status = StepperStatus.COMPLETE),
StepperNode("Complete Profile", status = StepperStatus.ACTIVE),
StepperNode("Start Using", status = StepperStatus.IDLE)
)
// Dynamic status update
fun updateStepStatus(steps: MutableList<StepperNode>, index: Int, status: StepperStatus) {
steps[index] = steps[index].copy(status = status)
}
🎭 StepperActionIcons¶
Defines the set of icons used by steppers for different states.
Structure¶
data class StepperActionIcons(
val completed: ImageVector = Icons.Default.Check,
val error: ImageVector = Icons.Default.Close,
val active: ImageVector = Icons.Rounded.Check
)
Parameters¶
Parameter | Type | Default | Description |
---|---|---|---|
completed |
ImageVector |
Icons.Default.Check |
Icon for completed steps |
error |
ImageVector |
Icons.Default.Close |
Icon for error steps |
active |
ImageVector |
Icons.Rounded.Check |
Default icon for active steps |
Example Usage¶
// Material Design icons
val materialIcons = StepperActionIcons(
completed = Icons.Default.CheckCircle,
error = Icons.Default.Error,
active = Icons.Default.RadioButtonChecked
)
// Custom icons
val customIcons = StepperActionIcons(
completed = Icons.Default.Done,
error = Icons.Default.Cancel,
active = Icons.Default.PlayArrow
)
// Usage in stepper
VerticalStepper(
steps = steps,
actionIcons = customIcons
)
🔄 State Management Patterns¶
1. Basic State Management¶
@Composable
fun StatefulStepper() {
var currentStep by remember { mutableStateOf(0) }
val steps = remember(currentStep) {
listOf(
StepperNode(
title = "Step 1",
status = if (currentStep >= 0) StepperStatus.COMPLETE else StepperStatus.IDLE
),
StepperNode(
title = "Step 2",
status = when {
currentStep > 1 -> StepperStatus.COMPLETE
currentStep == 1 -> StepperStatus.ACTIVE
else -> StepperStatus.IDLE
}
),
StepperNode(
title = "Step 3",
status = when {
currentStep > 2 -> StepperStatus.COMPLETE
currentStep == 2 -> StepperStatus.ACTIVE
else -> StepperStatus.IDLE
}
)
)
}
VerticalStepper(
steps = steps,
onStepClick = { index ->
if (index <= currentStep + 1) {
currentStep = index
}
}
)
}
2. Form Validation State¶
@Composable
fun FormValidationStepper() {
var formStates by remember {
mutableStateOf(
mapOf(
0 to StepperStatus.IDLE, // Personal Info
1 to StepperStatus.IDLE, // Contact Details
2 to StepperStatus.IDLE, // Preferences
3 to StepperStatus.IDLE // Confirmation
)
)
}
val steps = formStates.map { (index, status) ->
StepperNode(
title = when (index) {
0 -> "Personal Info"
1 -> "Contact Details"
2 -> "Preferences"
3 -> "Confirmation"
else -> "Step ${index + 1}"
},
status = status
)
}
// Function to update validation status
fun validateStep(stepIndex: Int, isValid: Boolean) {
formStates = formStates.toMutableMap().apply {
this[stepIndex] = if (isValid) StepperStatus.COMPLETE else StepperStatus.ERROR
}
}
}
3. Async Process Tracking¶
@Composable
fun AsyncProcessStepper() {
var processStates by remember {
mutableStateOf(
listOf(
StepperStatus.IDLE, // Download
StepperStatus.IDLE, // Install
StepperStatus.IDLE, // Configure
StepperStatus.IDLE // Launch
)
)
}
val stepTitles = listOf("Download", "Install", "Configure", "Launch")
val steps = processStates.mapIndexed { index, status ->
StepperNode(
title = stepTitles[index],
status = status
)
}
// Simulate async process
LaunchedEffect(Unit) {
processStates.forEachIndexed { index, _ ->
// Update to active
processStates = processStates.toMutableList().apply {
this[index] = StepperStatus.ACTIVE
}
delay(2000) // Simulate process time
// Update to complete
processStates = processStates.toMutableList().apply {
this[index] = StepperStatus.COMPLETE
}
}
}
HorizontalStepper(steps = steps)
}
🛠️ Utility Functions¶
Step Navigation Helpers¶
object StepperUtils {
/**
* Create steps with progressive completion status
*/
fun createProgressiveSteps(
titles: List<String>,
currentStep: Int,
descriptions: List<String>? = null
): List<StepperNode> {
return titles.mapIndexed { index, title ->
StepperNode(
title = title,
description = descriptions?.getOrNull(index),
status = when {
index < currentStep -> StepperStatus.COMPLETE
index == currentStep -> StepperStatus.ACTIVE
else -> StepperStatus.IDLE
}
)
}
}
/**
* Update step status at specific index
*/
fun updateStepStatus(
steps: List<StepperNode>,
index: Int,
newStatus: StepperStatus
): List<StepperNode> {
return steps.mapIndexed { i, step ->
if (i == index) step.copy(status = newStatus) else step
}
}
/**
* Get next incomplete step index
*/
fun getNextIncompleteStep(steps: List<StepperNode>): Int? {
return steps.indexOfFirst { it.status != StepperStatus.COMPLETE }
.takeIf { it != -1 }
}
/**
* Check if all steps are complete
*/
fun areAllStepsComplete(steps: List<StepperNode>): Boolean {
return steps.all { it.status == StepperStatus.COMPLETE }
}
/**
* Get completion percentage
*/
fun getCompletionPercentage(steps: List<StepperNode>): Float {
if (steps.isEmpty()) return 0f
val completedSteps = steps.count { it.status == StepperStatus.COMPLETE }
return completedSteps.toFloat() / steps.size.toFloat()
}
}
Usage Examples¶
// Create progressive steps
val progressSteps = StepperUtils.createProgressiveSteps(
titles = listOf("Start", "Process", "Complete"),
currentStep = 1,
descriptions = listOf(
"Begin the process",
"Processing your request",
"All done!"
)
)
// Update step status
val updatedSteps = StepperUtils.updateStepStatus(
steps = progressSteps,
index = 2,
newStatus = StepperStatus.ERROR
)
// Check completion
val isComplete = StepperUtils.areAllStepsComplete(progressSteps)
val percentage = StepperUtils.getCompletionPercentage(progressSteps)
🎨 Icon Recommendations¶
Material Icons for Common Use Cases¶
object StepperIcons {
// Authentication Flow
val signUp = Icons.Default.PersonAdd
val verify = Icons.Default.VerifiedUser
val login = Icons.Default.Login
// E-commerce Flow
val cart = Icons.Default.ShoppingCart
val shipping = Icons.Default.LocalShipping
val payment = Icons.Default.Payment
val confirmation = Icons.Default.CheckCircle
// Onboarding Flow
val welcome = Icons.Default.Waving
val tutorial = Icons.Default.School
val preferences = Icons.Default.Settings
val ready = Icons.Default.Rocket
// Document Processing
val upload = Icons.Default.Upload
val review = Icons.Default.Preview
val approve = Icons.Default.Approval
val complete = Icons.Default.Done
}
⚠️ Important Notes¶
Status Transitions¶
- Always transition states logically (IDLE → ACTIVE → COMPLETE/ERROR)
- Avoid jumping directly from IDLE to COMPLETE without ACTIVE
- Use ERROR status for validation failures or process errors
Performance Considerations¶
- Use
remember
for step lists to avoid unnecessary recompositions - Consider using
derivedStateOf
for computed step states - Avoid creating new StepperNode instances on every recomposition
Accessibility¶
- Provide meaningful titles and descriptions
- Use appropriate status indicators for screen readers
- Ensure step navigation is keyboard accessible
🔗 Related Documentation¶
- StepperConfig - Configuration options
- VerticalStepper - Vertical stepper component
- HorizontalStepper - Horizontal stepper component
- CompactHorizontalStepper - Compact horizontal stepper
📋 Quick Reference¶
// Complete example with all models
val customIcons = StepperActionIcons(
completed = Icons.Default.CheckCircle,
error = Icons.Default.Error,
active = Icons.Default.PlayArrow
)
val steps = listOf(
StepperNode(
title = "Setup Account",
description = "Create your profile",
icon = Icons.Default.Person,
status = StepperStatus.COMPLETE
),
StepperNode(
title = "Verify Identity",
description = "Upload documents",
icon = Icons.Default.Badge,
status = StepperStatus.ACTIVE
),
StepperNode(
title = "Start Using",
description = "Begin your journey",
icon = Icons.Default.Rocket,
status = StepperStatus.IDLE
)
)
VerticalStepper(
steps = steps,
actionIcons = customIcons,
onStepClick = { index -> /* Handle click */ }
)