A sophisticated Flutter application showcasing a coffee ordering system with smooth animations, custom BLoC state management, and modern UI/UX design patterns.
This project demonstrates a complete coffee ordering experience with:
- Custom BLoC Architecture (no external packages)
- Smooth Animations with wave effects and cart interactions
- Dynamic Pricing System based on cup size and quantity
- Dark/Light Theme Support with seamless switching
- Responsive Design across all platforms
- Clean Architecture with separation of concerns
This project implements a custom BLoC (Business Logic Component) pattern without external dependencies, providing:
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β UI β β BLoC β β State β
β (Widgets) βββββΆβ (Business βββββΆβ (Immutable β
β β β Logic) β β Data) β
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β² β β
β βΌ β
ββββββββββββββββββββββEventsββββββββββββββββββββββ
-
Events (
lib/bloc/coffee_events.dart)- Immutable classes representing user actions
- Type-safe event handling
-
State (
lib/bloc/coffee_state.dart)- Single source of truth for application state
- Immutable with
copyWith()pattern
-
BLoC (
lib/bloc/coffee_bloc.dart)- Handles business logic and state transitions
- Manages async operations and animations
lib/
βββ bloc/ # Custom BLoC implementation
β βββ coffee_events.dart # Event definitions
β βββ coffee_state.dart # State management
β βββ coffee_bloc.dart # Business logic
βββ constants/ # App-wide constants
β βββ app_constants.dart # Colors, sizes, durations
βββ widgets/ # Reusable UI components
β βββ coffee_machine_widget.dart
β βββ cup_selector_widget.dart
β βββ quantity_selector_widget.dart
β βββ action_button_widget.dart
βββ utils/ # Utility classes
β βββ price_formatter.dart # Price formatting logic
βββ cup_enum.dart # Cup types and pricing
βββ main.dart # App entry point
- Wave Animation: Realistic coffee filling effect
- Drop Animation: Coffee dripping simulation
- Cart Animation: Smooth add-to-cart transitions
- Loading States: Visual feedback during operations
- Reactive UI: Automatic updates via StreamBuilder
- Immutable State: Predictable state changes
- Event-Driven: Clean separation of actions and reactions
- Dynamic Switching: Toggle between light/dark themes
- Custom ColorScheme: Tailored color palettes
- Consistent Styling: Unified design language
- Size-Based Pricing: Different prices per cup size
- Quantity Calculation: Real-time total updates
- Price Breakdown: Clear pricing display
-
Separation of Concerns
// UI only handles presentation StreamBuilder<CoffeeState>( stream: coffeeBloc.stateStream, builder: (context, snapshot) { final state = snapshot.data!; return CoffeeUI(state: state); }, )
-
Testability
// Easy unit testing test('should increment quantity', () { bloc.add(QuantityIncrementEvent()); expect(bloc.currentState.quantity, 2); });
-
Predictable State Changes
// Immutable state updates CoffeeState copyWith({ CupEnum? selectedCup, int? quantity, bool? isDarkMode, }) => CoffeeState( selectedCup: selectedCup ?? this.selectedCup, quantity: quantity ?? this.quantity, isDarkMode: isDarkMode ?? this.isDarkMode, );
// Coordinated animation sequences
void _handleFillingAnimation() async {
await Future.delayed(const Duration(milliseconds: 600));
add(ShowLoadingOverlayEvent());
await Future.delayed(AppConstants.waveDuration);
add(FillingCompletedEvent());
}// Dynamic theme switching
ThemeData get darkTheme => ThemeData(
colorScheme: const ColorScheme(
brightness: Brightness.dark,
primary: Color(0xffD4A574),
background: Color(0xff121212),
// ... more colors
),
);- Single Responsibility Principle
- Dependency Inversion
- Separation of Concerns
- Immutable state objects
- Centralized state management
- Predictable state transitions
- Feature-based structure
- Reusable components
- Consistent naming conventions
- Efficient widget rebuilds
- Proper resource disposal
- Optimized animations
- Strong typing throughout
- Null safety compliance
- Pattern matching for events
- Graceful error states
- Resource cleanup
- Async safety checks
- β Android
- β iOS
- β Web
- β Windows
- β macOS
- β Linux
- Flutter SDK (3.0+)
- Dart SDK (3.0+)
-
Clone the repository
git clone https://github.com/yourusername/coffee-machine-animation.git cd coffee-machine-animation -
Install dependencies
flutter pub get
-
Run the app
flutter run
# Run with hot reload
flutter run
# Run tests
flutter test
# Analyze code
flutter analyze
# Build for production
flutter build apk # Android
flutter build ios # iOS
flutter build web # WebThe BLoC architecture makes testing straightforward:
// Unit test example
void main() {
group('CoffeeBloc', () {
late CoffeeBloc bloc;
setUp(() {
bloc = CoffeeBloc();
});
test('should start with initial state', () {
expect(bloc.currentState.selectedCup, CupEnum.small);
expect(bloc.currentState.quantity, 1);
});
test('should update cup selection', () {
bloc.selectCup(CupEnum.large);
expect(bloc.currentState.selectedCup, CupEnum.large);
});
});
}- Material Design 3 compliance
- Smooth animations (60fps)
- Intuitive interactions
- Accessibility support
- Responsive layout
- Tap to Fill: Initiates coffee brewing animation
- Swipe Cups: Navigate between cup sizes
- Quantity Controls: Increment/decrement with haptic feedback
- Theme Toggle: Instant theme switching
- Add to Cart: Animated cart addition
// In cup_enum.dart
enum CupEnum {
small(label: 'Small', price: 30, image: 'assets/cup1.png'),
medium(label: 'Medium', price: 35, image: 'assets/cup2.png'),
large(label: 'Large', price: 40, image: 'assets/cup3.png'),
extraLarge(label: 'Extra Large', price: 45, image: 'assets/cup4.png'), // New
}// In app_constants.dart
class AppConstants {
static const Duration waveDuration = Duration(seconds: 5);
static const Duration animation1200 = Duration(milliseconds: 1200);
// Add your custom durations
}This project demonstrates:
- BLoC Pattern implementation
- Stream-based state management
- Animation coordination
- Theme management
- Clean Architecture principles
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Flutter team for the amazing framework
- Material Design team for design guidelines
- Community contributors for inspiration
Built with β€οΈ using Flutter and custom BLoC architecture
