commandy 0.1.1 copy "commandy: ^0.1.1" to clipboard
commandy: ^0.1.1 copied to clipboard

A modern Flutter package for managing asynchronous commands and state effectively.

Commandy #

Commandy Logo

Commandy is a Flutter package designed to streamline the execution and management of asynchronous commands, while providing a clear and consistent way to handle success, failure, and state changes. It helps you abstract away the complexity of asynchronous actions, making your code more modular, testable, and maintainable.

Key Features 🚀 #

  • Unified Result Handling:
    Uses a Result model with Success<T> and FailureResult<T> variants to represent operation outcomes clearly. This encourages a functional approach to error handling and makes your code easier to reason about.

  • Asynchronous Commands:
    Command<T, Params> encapsulates an asynchronous action, notifies execution state changes (isExecuting), and delivers the outcome as a Result<T> through a ValueNotifier. This pattern makes it simple to integrate async logic into your ViewModels or UseCases.

  • Stream-Based Commands:
    StreamCommand<T, Params> handles actions that return a Stream<Result<T>>, automatically managing subscriptions and providing updates via ValueNotifier. This is ideal for continuously updating data sources, such as real-time queries or sensor feeds.

  • Command Listener for UI:
    The CommandListener widget easily integrates into Flutter UI code. It listens to multiple commands and triggers callbacks when results change, allowing the UI layer to react immediately to new data or errors.

  • NoParams for Simplicity:
    Provides a convenient way to manage commands that do not require parameters, avoiding null values or unnecessary complexity.

  • State Management Ready:
    While Commandy focuses on commands, it can also be used as a lightweight state management solution. By encapsulating your business logic and state changes in commands, you get a clean and testable approach to managing application state.


Installation 💻 #

Add Commandy to your pubspec.yaml:

dependencies:
  commandy: ^0.1.0

Then, fetch packages:

flutter pub get

Getting Started #

  1. Import the library:

    import 'package:commandy/commandy.dart';
    
  2. Create a Command that executes your asynchronous logic, for example, fetching data from a repository.

  3. Bind it to your UI using a CommandListener widget or by calling execute and listening to result changes in your ViewModel.

By structuring your app's async operations as Commands returning Results, you can maintain a clean separation of concerns and ensure that logic and UI remain loosely coupled.


Core Concepts #

Result and its Variants #

Result<T> is a sealed class that represents the outcome of an operation. It has two main variants:

  • Success<T>: Indicates that the operation completed successfully. Holds the resulting data.
  • FailureResult<T>: Indicates that the operation failed. Holds a Failure object with details of the error, including a message, optional exception, and stack trace.

NoParams Class 🛠️ #

NoParams is a lightweight class that represents the absence of parameters for a command. It helps maintain a consistent Command<T, Params> interface even when no parameters are required.

Example Usage:

final incrementCommand = Command<int, NoParams>((_) async {
  // Increment logic
  await Future.delayed(const Duration(seconds: 1));
  return Success(42);
});

// Execute the command
await incrementCommand.execute(const NoParams());

This avoids passing null and ensures clarity and consistency in your codebase.


Command #

Encapsulates an asynchronous action and updates its state via ValueNotifiers:

  • isExecuting: A ValueNotifier<bool> indicating if the command is still running.
  • result: A ValueNotifier<Result<T>?> holding the last result.

Use Command for one-shot operations like login requests or data fetching.


StreamCommand #

Works with streams and manages ongoing updates. Call start(params) to begin listening and stop() to cancel the subscription.


CommandListener #

Simplifies UI integration by reacting to command result changes. Instead of manually listening to ValueNotifiers, use CommandListener to handle updates efficiently.


Puedes agregar la documentación de la nueva clase ViewModelSelector en una nueva sección dedicada a "Advanced Features" o "UI Optimization". Esta clase encaja perfectamente en la idea de optimizar el comportamiento de widgets y el estado de la UI, así que deberíamos destacarla como una herramienta avanzada.


Advanced Features ⚡

ViewModelSelector 🧩 #

The ViewModelSelector is a powerful utility for selectively rebuilding Flutter widgets based on specific properties of a ChangeNotifier-based ViewModel. It optimizes UI updates by ensuring that only the widgets depending on the selected value are rebuilt, avoiding unnecessary widget rebuilds when other properties in the ViewModel change.


Key Features:

  • Selective Rebuilding:
    Extracts a specific property from the ViewModel using a selector function and only triggers a rebuild when that property changes.

  • Integration with ChangeNotifier:
    Works seamlessly with your existing ViewModels, which extend ChangeNotifier.

  • Efficient and Modular:
    Allows finer control of UI updates without requiring external libraries or tools.


Example Usage:

Here’s how you can integrate the ViewModelSelector into your code:

1. Create a ViewModel:

class MyViewModel extends ChangeNotifier {
  String _name = 'John Doe';
  int _counter = 0;

  String get name => _name;
  int get counter => _counter;

  void updateName(String newName) {
    _name = newName;
    notifyListeners();
  }

  void incrementCounter() {
    _counter++;
    notifyListeners();
  }
}

2. Use ViewModelSelector in Your Widget:

final myViewModel = MyViewModel();

ViewModelSelector<MyViewModel, String>(
  viewModel: myViewModel,
  selector: (vm) => vm.name, // Watch only the `name` property
  builder: (context, name) {
    return Text('Name: $name');
  },
);

ViewModelSelector<MyViewModel, int>(
  viewModel: myViewModel,
  selector: (vm) => vm.counter, // Watch only the `counter` property
  builder: (context, counter) {
    return Text('Counter: $counter');
  },
);

Benefits:

  • Ensures UI efficiency by rebuilding only the widgets affected by state changes.
  • Simple and clean integration into existing ChangeNotifier architectures.
  • Great for modularizing UI updates when working with complex ViewModels.

Examples 🎯 #

Counter Example #

final incrementCommand = Command<int, NoParams>((_) async {
  // Increment logic
  await Future.delayed(Duration(seconds: 1));
  return Success(42);
});

Timer Example #

final timerCommand = StreamCommand<int, NoParams>((_) {
  return Stream.periodic(Duration(seconds: 1), (x) => 30 - x - 1)
      .take(30)
      .map((value) => Success(value));
});

timerCommand.start(const NoParams());

Full Implementation #

Check the example folder for a full implementation of both the counter and timer examples. Includes UI integration and detailed logic.


Additional Resources 📚 #

Learn more about the Command pattern and its practical applications:

Error Handling 🚦 #

Convert all errors into FailureResult instances:

final safeCommand = Command<int, int>((param) async {
  try {
    if (param < 0) throw Exception('Negative param');
    return Success(param * 2);
  } catch (e, s) {
    return FailureResult<int>(
      Failure(message: 'Error processing param', exception: e, stackTrace: s),
    );
  }
});

Testing 🧪 #

Commandy is test-ready:

  • Mock commands to return Success or FailureResult and verify behavior.
  • Use Stream.fromIterable for testing StreamCommand.
  • Integrate CommandListener in UI tests with flutter_test.

Contributing 🤝 #

We welcome contributions! Feel free to open issues, suggest enhancements, or submit pull requests. Please follow our coding style and ensure all tests pass.


License 📄 #

This project is licensed under the MIT License - see the LICENSE file for details.


1
likes
150
points
17
downloads
screenshot

Publisher

verified publisherhapkiduki.dev

Weekly Downloads

A modern Flutter package for managing asynchronous commands and state effectively.

Repository (GitHub)
View/report issues

Topics

#commandy #state-management #command-pattern #viewmodel

Documentation

API reference

License

MIT (license)

Dependencies

equatable, flutter

More

Packages that depend on commandy