Sequential Flow
A Flutter library for building declarative, step-by-step flows with comprehensive state management and customizable navigation behavior.
Features
- ✅ Declarative Flow Definition - Define your flow steps with clear configuration
- ✅ Type-Safe Data Storage - Store and retrieve data with full type safety using enums or strings
- ✅ Flexible Navigation Control - Multiple back navigation behaviors per step
- ✅ User Confirmation Steps - Built-in support for confirmation dialogs
- ✅ Comprehensive Error Handling - Custom error UI with retry functionality
- ✅ Progress Tracking - Real-time progress updates with customizable UI
- ✅ Custom Back Button Handling - Handle back button presses with custom logic
- ✅ State Management - Built-in reactive state management with ChangeNotifier
- ✅ Production Ready - Thoroughly tested with comprehensive example implementations
Installation
Add this to your package's pubspec.yaml file:
dependencies:
sequential_flow: ^1.2.0
Then run:
flutter pub get
Quick Start
import 'package:sequential_flow/sequential_flow.dart';
// Define your flow steps
enum ProcessStep { init, verify, complete }
// Create your flow
SequentialFlow<ProcessStep>(
steps: [
FlowStep(
step: ProcessStep.init,
name: 'Initializing',
progressValue: 0.3,
onStepCallback: (controller) async {
await Future.delayed(Duration(seconds: 2));
},
),
FlowStep(
step: ProcessStep.verify,
name: 'Verification',
progressValue: 0.7,
onStepCallback: (controller) async {
await Future.delayed(Duration(seconds: 1));
},
),
FlowStep(
step: ProcessStep.complete,
name: 'Complete',
progressValue: 1.0,
onStepCallback: (controller) async {
await Future.delayed(Duration(milliseconds: 500));
},
),
],
)
Core Concepts
FlowStep
Defines individual steps with business logic and UI configuration:
- step: Step identifier (typically an enum)
- name: Human-readable step name
- progressValue: Progress between 0.0 and 1.0
- onStepCallback: Main business logic
- requiresConfirmation: Optional confirmation UI
- actionOnPressBack: Back navigation behavior
FlowController
Manages state, navigation, and data persistence:
- State Management: Loading, completion, error states
- Data Storage: Type-safe data storage with flexible keys
- Navigation: Back button handling and step transitions
- Error Recovery: Built-in retry and error handling
SequentialFlow Widget
Orchestrates execution and renders UI:
- Lifecycle Management: Automatic controller management
- Custom UI Builders: Customizable loading, error, and completion states
- Back Button Integration: Automatic back button handling
Type-Safe Data Storage
Use enums for type-safe data keys:
enum UserKeys { email, name, phone, verified }
// Store data
controller.setData(UserKeys.email, 'user@example.com');
controller.setData(UserKeys.verified, true);
// Retrieve data with type safety
String? email = controller.getData<UserKeys, String>(UserKeys.email);
bool? isVerified = controller.getData<UserKeys, bool>(UserKeys.verified);
// Backward compatibility with strings
controller.setData('legacy-key', 'value');
String? value = controller.getData('legacy-key');
User Confirmation Steps
Create interactive confirmation dialogs:
FlowStep(
step: ProcessStep.confirm,
name: 'Confirmation',
progressValue: 0.8,
onStepCallback: (controller) async {
// Process after confirmation
await processData();
},
requiresConfirmation: (controller) => AlertDialog(
title: Text('Confirm Action'),
content: Text('Are you sure you want to continue?'),
actions: [
TextButton(
onPressed: () => controller.continueFlow(),
child: Text('Yes'),
),
TextButton(
onPressed: () => controller.cancelFlow(),
child: Text('No'),
),
],
),
)
Back Navigation Control
Configure how each step handles back navigation:
FlowStep(
step: ProcessStep.critical,
name: 'Critical Step',
onStepCallback: (controller) async {
await criticalOperation();
},
actionOnPressBack: ActionOnPressBack.block, // Prevent going back
)
Available Back Navigation Options:
| ActionOnPressBack | Behavior |
|---|---|
block |
Prevents back navigation completely |
goToPreviousStep |
Returns to previous step |
cancelFlow |
Cancels entire flow |
saveAndExit |
Allows normal exit |
custom |
Triggers custom onBackPressed callback |
goToSpecificStep |
Jumps to specified step index |
Custom Back Button Handling
Handle back button presses with custom logic:
SequentialFlow<ProcessStep>(
steps: steps,
onBackPressed: (controller) {
// Return a widget to show it as part of the flow
return AlertDialog(
title: Text('Exit Process?'),
content: Text('Your progress will be lost.'),
actions: [
TextButton(
onPressed: () => controller.hideBackWidget(),
child: Text('Continue'),
),
TextButton(
onPressed: () => Navigator.pop(context),
child: Text('Exit'),
),
],
);
},
)
Error Handling
Provide custom error UI with retry functionality:
SequentialFlow<ProcessStep>(
steps: steps,
onStepError: (step, name, error, stack, controller) => Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.error, size: 64, color: Colors.red),
Text('Error in $name'),
Text(error.toString()),
SizedBox(height: 16),
ElevatedButton(
onPressed: () => controller.retry(),
child: Text('Retry'),
),
],
),
)
Custom UI States
Customize the appearance of different flow states:
SequentialFlow<ProcessStep>(
steps: steps,
onStepLoading: (step, name, progress) => Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(value: progress),
SizedBox(height: 16),
Text(name),
Text('${(progress * 100).toInt()}% Complete'),
],
),
onStepFinish: (step, name, progress, controller) => Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.check_circle, size: 64, color: Colors.green),
Text('Process Complete!'),
SizedBox(height: 16),
ElevatedButton(
onPressed: () => Navigator.pop(context),
child: Text('Done'),
),
],
),
)
Real-World Example: Payment Flow
See the complete payment flow example in /example/example.dart for a production-ready implementation featuring:
- User authentication and verification
- Conditional flow navigation
- Dynamic step progression
- Multiple payment methods
- Complete error handling
- Real-world payment processing simulation
Key features demonstrated:
- 8 sequential steps with complex logic
- Type-safe data storage with enums
- Conditional step execution
- Method-specific UI forms
- Comprehensive error recovery
- Custom back navigation handling
Best Practices
Data Management
- Use enums for type-safe keys:
controller.setData(MyKeys.email, value) - Clean up data after completion:
controller.reset() - Validate required data in
onStepCallback
Error Handling
- Always provide
onStepErrorfor user-friendly error messages - Use
controller.retry()for recoverable errors - Implement proper fallbacks for network-dependent steps
Navigation
- Use
ActionOnPressBack.blockfor critical operations - Implement
onBackPressedfor custom confirmation dialogs - Consider user experience when choosing navigation behavior
Performance
- Dispose controllers in
StatefulWidget.dispose() - Use
autoStart: falsefor manual flow control - Avoid heavy operations in
requiresConfirmationbuilders
Common Use Cases
Perfect for:
- User onboarding and registration flows
- Payment processing workflows
- File upload/download processes
- Multi-step forms and wizards
- App setup and configuration
- Data migration workflows
- Survey and questionnaire forms
- Checkout processes
API Reference
FlowController Methods
// Flow Control
await controller.start() // Start flow execution
await controller.continueFlow() // Continue after confirmation
controller.cancelFlow() // Cancel flow
controller.reset() // Reset to initial state
controller.restart() // Restart from beginning
await controller.retry() // Retry after error
// Data Management
controller.setData(key, value) // Store data
controller.getData<K, V>(key) // Retrieve data
controller.getAllData() // Get all data
// State Properties
controller.isLoading // Currently executing
controller.isCompleted // Successfully finished
controller.hasError // Error occurred
controller.isCancelled // User cancelled
controller.isWaitingConfirmation // Waiting for user input
controller.currentStep // Current step identifier
controller.currentStepName // Current step name
controller.currentProgress // Current progress (0.0-1.0)
FlowStep Properties
FlowStep<T>(
required T step, // Step identifier
required String name, // Display name
required double progressValue, // Progress (0.0-1.0)
required Future<void> Function(FlowController<T>) onStepCallback,
Future<void> Function(FlowController<T>)? onStartStep,
Widget Function(FlowController<T>)? requiresConfirmation,
ActionOnPressBack actionOnPressBack = ActionOnPressBack.block,
int? goToStepIndex, // For goToSpecificStep
Future<bool> Function(FlowController<T>)? customBackAction,
)
SequentialFlow Properties
SequentialFlow<T>(
required List<FlowStep<T>> steps,
bool autoStart = true,
Widget Function(T, String, double)? onStepLoading,
Widget Function(T, String, Object, StackTrace, FlowController<T>)? onStepError,
Widget Function(T, String, double, FlowController<T>)? onStepFinish,
Widget Function(T, String, FlowController<T>)? onStepCancel,
Widget? Function(FlowController<T>)? onBackPressed,
FlowController<T>? controller, // Optional external controller
)
Requirements
- Flutter: >=3.0.0
- Dart: >=2.17.0
- Platforms: iOS, Android, Web, Desktop
Contributing
Contributions are welcome! Please read our Contributing Guide for details on our code of conduct and the process for submitting pull requests.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Changelog
See CHANGELOG.md for a detailed list of changes and version history.
Libraries
- sequential_flow
- A Flutter library for creating sequential, step-by-step flows with customizable UI and navigation.