velo 1.0.0
velo: ^1.0.0 copied to clipboard
A simple and efficient state management solution for Flutter, inspired by flutter_bloc but keeping only the essentials.
Velo ๐ดโโ๏ธ #
A simple and efficient state management solution for Flutter, inspired by flutter_bloc but keeping only the essentials.
Velo takes the Cubit concept from flutter_bloc and builds upon Flutter's native ValueNotifier with Equatable support for efficient state comparisons.
๐ Features #
- Simple : Built on Flutter's native
ValueNotifier - Efficient : Integrates with
Equatableto avoid unnecessary rebuilds - Lightweight : Only essential components, no superfluous complexity
- Compatible : Works perfectly with the
Providerpackage - Complete : Includes builder, consumer, and listener widgets
๐ Installation #
Add velo to your pubspec.yaml:
dependencies:
velo: ^1.0.0
provider: ^6.1.5
equatable: ^2.0.7
๐ Usage #
1. Define a State #
Create your state class by extending Equatable:
import 'package:equatable/equatable.dart';
class CounterState extends Equatable {
final int count;
final bool isLoading;
const CounterState({
this.count = 0,
this.isLoading = false,
});
@override
List<Object?> get props => [count, isLoading];
CounterState copyWith({
int? count,
bool? isLoading,
}) {
return CounterState(
count: count ?? this.count,
isLoading: isLoading ?? this.isLoading,
);
}
}
2. Create a Velo #
Extend the Velo class to create your state manager:
import 'package:velo/velo.dart';
class CounterVelo extends Velo<CounterState> {
CounterVelo() : super(const CounterState());
void increment() {
emit(state.copyWith(count: state.count + 1));
}
void decrement() {
emit(state.copyWith(count: state.count - 1));
}
Future<void> incrementAsync() async {
emit(state.copyWith(isLoading: true));
// Simulate async operation
await Future.delayed(const Duration(milliseconds: 500));
emit(state.copyWith(
count: state.count + 1,
isLoading: false,
));
}
}
3. Use with Widgets #
VeloBuilder - For UI Rebuilding
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:velo/velo.dart';
class CounterPage extends StatelessWidget {
const CounterPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Provider<CounterVelo>(
create: (_) => CounterVelo(),
dispose: (_, velo) => velo.dispose(),
child: Scaffold(
appBar: AppBar(title: const Text('Velo Counter')),
body: Center(
child: VeloBuilder<CounterVelo, CounterState>(
builder: (context, state) {
if (state.isLoading) {
return const CircularProgressIndicator();
}
return Text(
'Count: ${state.count}',
style: Theme.of(context).textTheme.headlineMedium,
);
},
),
),
floatingActionButton: Builder(
builder: (context) {
return FloatingActionButton(
onPressed: () => context.read<CounterVelo>().increment(),
child: const Icon(Icons.add),
);
},
),
),
);
}
}
VeloListener - For Side Effects
VeloListener<CounterVelo, CounterState>(
listener: (context, state) {
if (state.count > 10) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('High counter!')),
);
}
},
child: VeloBuilder<CounterVelo, CounterState>(
builder: (context, state) {
return Text('Count: ${state.count}');
},
),
)
VeloConsumer - Combined Builder + Listener
VeloConsumer<CounterVelo, CounterState>(
listener: (context, state) {
// Side effects
if (state.count < 0) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Negative counter')),
);
}
},
builder: (context, state) {
// UI building
return Text('Count: ${state.count}');
},
)
๐ง API Reference #
Velo<S> #
Abstract main class that extends ValueNotifier<S>.
Methods
emit(S state): Emits a new state if different from the previous oneemitAsync(Future<S> futureState): Emits a state from a FutureS get state: Gets the current state
Widgets #
VeloBuilder<N, S>
Rebuilds the UI when state changes.
VeloBuilder<MyVelo, MyState>(
builder: (context, state) => Widget,
loadingWidget: Widget?, // Widget displayed on error
)
VeloListener<N, S>
Listens to state changes without rebuilding.
VeloListener<MyVelo, MyState>(
listener: (context, state) => void,
child: Widget,
)
VeloConsumer<N, S>
Combines VeloBuilder and VeloListener.
VeloConsumer<MyVelo, MyState>(
builder: (context, state) => Widget,
listener: (context, state) => void,
)
MultiVeloListener
Provides multiple Velos in the widget tree.
MultiVeloListener(
listeners: [
Provider<CounterVelo>(create: (_) => CounterVelo()),
Provider<UserVelo>(create: (_) => UserVelo()),
],
child: MyWidget(),
)
๐ก Best Practices #
- Immutable States : Always use
copyWith()to create new states - Equatable : Implement
Equatableto avoid unnecessary rebuilds - Dispose : Don't forget to dispose your Velos with Provider
- Separation : One Velo per business domain
- Testing : Test your Velos as simple Dart classes
๐งช Testing #
import 'package:flutter_test/flutter_test.dart';
void main() {
group('CounterVelo', () {
late CounterVelo counterVelo;
setUp(() {
counterVelo = CounterVelo();
});
tearDown(() {
counterVelo.dispose();
});
test('initial state', () {
expect(counterVelo.state, const CounterState());
});
test('increment', () {
counterVelo.increment();
expect(counterVelo.state.count, 1);
});
});
}
๐ Comparison with flutter_bloc #
| Aspect | Velo | flutter_bloc |
|---|---|---|
| Size | ~500 lines | ~5000+ lines |
| Complexity | Simple | Complex |
| Learning curve | Low | High |
| Performance | Excellent | Excellent |
| Features | Essential | Complete |
๐ Code Quality #
Velo maintains high code quality standards:
- 100% Test Coverage: All code paths are tested
- Static Analysis: Passes all Flutter linter rules
- CI/CD: Automated testing on every commit
- Security Scanning: Regular security vulnerability checks
- Documentation: Comprehensive API documentation
Quality Metrics #
- โ All tests pass on multiple platforms (Linux, macOS, Windows)
- โ Zero linter warnings or errors
- โ 100% documented public API
- โ Semantic versioning
- โ Changelog maintained
๐ค Contributing #
We welcome contributions! Please see our Contributing Guide for details.
Development Setup #
- Fork the repository
- Clone your fork:
git clone https://github.com/yourusername/velo.git - Install dependencies:
flutter pub get - Run tests:
flutter test - Make your changes
- Run quality checks:
flutter analyze && dart format --set-exit-if-changed . - Submit a pull request
๐ License #
MIT License - see LICENSE file for details.