command_it 9.4.2
command_it: ^9.4.2 copied to clipboard
command_it is a way to manage your state based on `ValueListenable` and the `Command` design pattern. It is a rebranding of flutter_command.
[9.4.2] - 2025-11-25
Maintenance #
- Updated example projects
[9.4.1] - 2024-11-24
Bug Fixes #
- Progress Control: Fixed progress state not resetting between command executions
- Progress state (progress, statusMessage, isCanceled) now automatically resets at the start of each execution
cancel()method now also clears progress and statusMessage (not just sets isCanceled flag)- Prevents issues where canceled commands would remain canceled on subsequent runs
- Implementation uses wrapper functions in WithProgress factories to call
reset()automatically
New Methods:
Command.resetProgress({double? progress, String? statusMessage})- Manually reset/initialize progress state- Without parameters: resets to defaults (0.0, null)
- With parameters: initializes to specific values (useful for resuming operations)
Technical Details:
- Added
ProgressHandle.reset()method to clear all state back to initial values - All 8 WithProgress factory methods now wrap user functions to call
reset()before execution cancel()now sets isCanceled=true, progress=0.0, and statusMessage=null for clean UI state
[9.4.0] - 2024-11-24
New Features #
- Progress Control: Commands now support built-in progress tracking, status messages, and cooperative cancellation through the new
ProgressHandleclass.
New Factory Methods (8 variants):
Command.createAsyncWithProgress<TParam, TResult>()- Async command with progress trackingCommand.createAsyncNoParamWithProgress<TResult>()- No-param async with progressCommand.createAsyncNoResultWithProgress<TParam>()- Void-return async with progressCommand.createAsyncNoParamNoResultWithProgress()- No-param, void-return async with progressCommand.createUndoableWithProgress<TParam, TResult, TUndoState>()- Undoable with progressCommand.createUndoableNoParamWithProgress<TResult, TUndoState>()- No-param undoable with progressCommand.createUndoableNoResultWithProgress<TParam, TUndoState>()- Void-return undoable with progressCommand.createUndoableNoParamNoResultWithProgress<TUndoState>()- No-param, void-return undoable with progress
New Command Properties:
progress- Observable progress value (0.0-1.0) viaValueListenable<double>statusMessage- Observable status text viaValueListenable<String?>isCanceled- Observable cancellation flag viaValueListenable<bool>cancel()- Request cooperative cancellation
MockCommand Progress Support:
withProgressHandleconstructor parameter to enable progress simulationupdateMockProgress(double)- Simulate progress updates in testsupdateMockStatusMessage(String?)- Simulate status message updatesmockCancel()- Simulate cancellation
Example Usage:
final uploadCommand = Command.createAsyncWithProgress<File, String>(
(file, handle) async {
for (int i = 0; i <= 100; i += 10) {
if (handle.isCanceled.value) return 'Canceled';
await uploadChunk(file, i);
handle.updateProgress(i / 100.0);
handle.updateStatusMessage('Uploading: $i%');
}
return 'Complete';
},
initialValue: '',
);
// In UI:
watchValue((MyService s) => s.uploadCommand.progress) // 0.0 to 1.0
watchValue((MyService s) => s.uploadCommand.statusMessage) // Status text
uploadCommand.cancel(); // Request cancellation
Benefits:
- Zero-overhead: Commands without progress use static default notifiers (no memory cost)
- Type-safe: Progress properties available on all commands via non-nullable API
- Cooperative cancellation: Works with external cancellation tokens (e.g., Dio's CancelToken)
- Test-friendly: MockCommand supports full progress simulation
[9.3.0] - 2025-01-23
Added #
- MockCommand "run" Terminology: MockCommand now uses "run" terminology to match the Command API migration from v9.0.0:
startRun()- replacesstartExecution()endRunWithData()- replacesendExecutionWithData()endRunWithError()- replacesendExecutionWithError()endRunNoData()- replacesendExecutionNoData()queueResultsForNextRunCall()- replacesqueueResultsForNextExecuteCall()runCountproperty - replacesexecutionCountlastPassedValueToRunproperty - replaceslastPassedValueToExecutereturnValuesForNextRunproperty - replacesreturnValuesForNextExecute
Deprecated #
- Old MockCommand "execute" Terminology: All "execute" terminology methods and properties in MockCommand are now deprecated
- Will be removed in v10.0.0
- See
BREAKING_CHANGE_EXECUTE_TO_RUN.mdfor migration guide
[9.2.0] - 2025-11-22
New Features #
- CommandBuilder Auto-Run: CommandBuilder now supports automatically executing commands on first build via
runCommandOnFirstBuildparameter. This is especially useful for non-watch_it users who want self-contained data-loading widgets without needing StatefulWidget boilerplate.
CommandBuilder<String, List<Item>>(
command: searchCommand,
runCommandOnFirstBuild: true, // Executes in initState
initialParam: 'flutter', // Parameter to pass
onData: (context, items, _) => ItemList(items),
whileRunning: (context, _, __) => LoadingIndicator(),
)
Benefits:
- Eliminates StatefulWidget boilerplate for simple data loading
- Self-contained widgets that manage their own data fetching
- Runs only once in initState (not on rebuilds)
- Perfect for non-watch_it users (watch_it users should continue using
callOnce)
Deprecations #
- Deprecated Command.toWidget(): The
Command.toWidget()method is now deprecated in favor ofCommandResult.toWidget(). The CommandResult version provides a richer API with better separation of concerns (onData/onSuccess/onNullData) and is already used by CommandBuilder. Command.toWidget() will be removed in v10.0.0.
Migration:
// Before (deprecated):
command.toWidget(
onResult: (data, param) => DataWidget(data),
whileRunning: (lastData, param) => LoadingWidget(),
onError: (error, param) => ErrorWidget(error),
)
// After (recommended):
ValueListenableBuilder(
valueListenable: command.results,
builder: (context, result, _) => result.toWidget(
onData: (data, param) => DataWidget(data),
whileRunning: (lastData, param) => LoadingWidget(),
onError: (error, lastData, param) => ErrorWidget(error),
),
)
[9.1.1] - 2025-11-21
Improvements #
- Renamed GlobalIfNoLocalErrorFilter: Renamed
FirstLocalThenGlobalErrorFiltertoGlobalIfNoLocalErrorFilterfor better clarity. The name now clearly indicates "global if no local handler".
New Features #
- Added GlobalErrorFilter: New filter that routes errors ONLY to the global handler, regardless of local listeners. Returns
ErrorReaction.globalHandler.
Fixes #
- Removed incorrectly named GlobalErrorFilter: The previous
GlobalErrorFilterthat was deprecated in v9.1.0 has been removed and replaced with the correct implementation.
[9.1.0] - 2025-11-21
New Features #
- Global errors stream: Added
Command.globalErrorsstream that emits all command errors across the entire application. This provides a centralized way to observe, log, and respond to command errors without polling individual commands.
Key capabilities:
- Reactive error monitoring: Stream emits
CommandError<dynamic>for every globally-routed error - Production-focused: Emits for ErrorFilter-routed errors and error handler exceptions, does NOT emit debug-only
reportAllExceptions - Use cases: Centralized logging, analytics/monitoring, crash reporting, global UI notifications (error toasts)
- watch_it integration: Perfect for
registerStreamHandlerto show error toasts in root widget
Example - Global error toast with watch_it:
class MyApp extends WatchingWidget {
@override
Widget build(BuildContext context) {
registerStreamHandler<Stream<CommandError>, CommandError>(
target: Command.globalErrors,
handler: (context, snapshot, cancel) {
if (snapshot.hasData) {
final error = snapshot.data!;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: ${error.error}')),
);
}
},
);
return MaterialApp(...);
}
}
Stream behavior:
- ✅ Emits when
ErrorFilterroutes error to global handler - ✅ Emits when error handler itself throws (if
reportErrorHandlerExceptionsToGlobalHandlerenabled) - ❌ Does NOT emit for
reportAllExceptions(debug-only feature) - Multiple listeners supported (broadcast stream)
- Cannot be closed
[9.0.3] - TBD
Improvements #
- Improved ErrorFilter class naming consistency: Renamed
ErrorHandler*classes to simpler*ErrorFilterpattern to better align with existing filters. Old names remain functional with deprecation warnings until v10.0.0.
Class name changes:
ErrorHandlerGlobalIfNoLocal→GlobalIfNoLocalErrorFilter(deprecated)ErrorHandlerLocal→LocalErrorFilter(deprecated)ErrorHandlerLocalAndGlobal→LocalAndGlobalIfNoLocalErrorFilter(deprecated)
Why this change:
- Better naming consistency: matches
TableErrorFilterandPredicatesErrorFilterpattern - Simpler and clearer:
LocalErrorFiltervsLocalHandlingFilter - All filter implementations now end with
*ErrorFilter
Migration: No action required - old names still work with deprecation warnings. Update at your convenience:
// Old (still works)
Command.errorFilterDefault = const ErrorHandlerGlobalIfNoLocal();
errorFilter: const ErrorHandlerLocal()
// New
Command.errorFilterDefault = const GlobalIfNoLocalErrorFilter();
errorFilter: const LocalErrorFilter()
[9.0.2] - 2025-11-15
Fixes #
- Properly deprecated ExecuteInsteadHandler and ifRestrictedExecuteInstead: Added proper deprecation instead of breaking renames. Both old (
ExecuteInsteadHandler,ifRestrictedExecuteInstead) and new (RunInsteadHandler,ifRestrictedRunInstead) names now work during v9.x. Added comprehensive tests for deprecated variants to maintain coverage. Updated fix_data.yaml to auto-migrate users viadart fix.
[9.0.1] - 2025-11-14
Fixes #
- Enhanced fix_data.yaml: Added comprehensive coverage for all Command subclasses (
CommandAsync,CommandSync,UndoableCommand) to ensuredart fixproperly migrates deprecated API usage when commands are accessed through property getters
[9.0.0] - 2025-11-14
Breaking Changes - API Terminology Migration (execute → run) #
This release renames the primary API from "execute" terminology to "run" for better Flutter ecosystem consistency.
API Changes (with deprecation period until v10.0.0):
Methods:
execute([TParam? param])→run([TParam? param])executeWithFuture([TParam? param])→runAsync([TParam? param])
Properties:
isExecuting→isRunning(async notifications for UI)isExecutingSync→isRunningSync(sync notifications for command coordination)canExecute→canRunthrownExceptions→errors
Parameters:
ifRestrictedExecuteInstead:→ifRestrictedRunInstead:(12 factory methods)whileExecuting:→whileRunning:(CommandBuilder and toWidget methods)
Migration Guide:
Automated migration: Run dart fix --apply to automatically update most usages via data-driven fixes.
Manual search/replace patterns:
.execute( → .run(
.executeWithFuture( → .runAsync(
.isExecuting → .isRunning
.isExecutingSync → .isRunningSync
.canExecute → .canRun
.thrownExceptions → .errors
ifRestrictedExecuteInstead: → ifRestrictedRunInstead:
whileExecuting: → whileRunning:
Old API remains functional with deprecation warnings until v10.0.0.
See BREAKING_CHANGE_EXECUTE_TO_RUN.md for complete migration details.
New Features (from 8.1.0) #
- Added
errorFilterFnparameter for function-based error filtering - provides simple inline alternative to object-basedErrorFiltersystem - Return
ErrorReactiondirectly orErrorReaction.defaulErrorFilterto delegate to default - Assertion prevents using both
errorFilteranderrorFilterFnsimultaneously - Available on all 12 command factory methods and MockCommand
Bug Fixes (from 8.1.0) #
- Fixed unsafe ValueNotifier type casts in
_canExecutefield - changed to ValueListenable - Fixed parameter order in CommandBuilder.onError callback - now (error, lastData, paramData) for consistency
- Fixed MockCommand type signature from
Command<TParam, TResult?>toCommand<TParam, TResult>to match real Commands
Documentation #
- Added comprehensive documentation to run() method (formerly execute())
- Improved error handling documentation in README with configuration examples
- Fixed image URLs to use flutter-it organization
- Updated all examples to use new "run" terminology
- Added data-driven fixes for automatic migration (fix_data.yaml)
[8.0.2]
Maintenance #
- Fixed analyzer issues in example_command_results (broken package imports, missing http version)
- Updated both examples to use latest dependencies (listen_it ^5.3.0, http ^1.0.0)
[8.0.1]
Maintenance #
- Updated listen_it dependency to ^5.3.0
- Updated GitHub Actions workflow with modern action versions and codecov v5
- Fixed workflow to trigger on main branch
- Fixed badges to point to flutter-it organization
- Fixed test pollution issue by adding proper setUp/tearDown
[8.0.0] - 19.07.2025
- although this doesn't add any new functionality because of the rebranding from flutter_command to command_it we use the next major version
[7.2.2] - 25.12.2024 >> from here all entries reference the old flutter_command package
-
another fix [7.2.1] - 25.12.2024
-
logic fix [7.2.0] - 25.12.2024
-
adding
onSuccessbuilder to theCommandBuilderandisSuccessto theCommandResultsto make them easiery to use if the Command doesn't return a value. [7.1.0] 27.11.2024 -
adding
isExecutingSyncto allow better chaining of commands [7.0.1] 27.11.2024 -
ensure that isExecuting is set back to false before we notify any result listeners. [7.0.0] 14.11.2024
-
add stricter static type checks. this is a breaking change because the
globalExceptionHandlercorrectly has to acceptCommandError<dynamic>instead ofCommandError<Object>[6.0.1] 29.09.2024 -
Update to latest version of listen_it to fix a potential bug when removing the last listener from
canExecute[6.0.0] -
official new release [6.0.0+pre2]
-
fixing asssert in CommandBuilder [6.0.0+pre1]
-
breaking changes: Command.debugName -> Command.name, ErrorReaction.defaultHandler -> ErrorReaction.defaulErrorFilter
-
unless an error filter returns none or throwException all errors will be published on the
resultsPropertyincluding the result of the error filter. This alloes you if you use theresultsproperty to reject on any error with a generic action like popping a page while doing the specific handlign of the error in the local or global handler. -
if an error handler itself throws an exception, that is now also reported to the
globalExceptionHandler[5.0.0+20] - 18.07.2024 -
undoing the last one as it makes merging of
errorsof multiple commands impossible [5.0.0+19] - 18.07.2024 -
added TParam in the defintion of the
errorsproperty [5.0.0+18] - 18.07.2024 -
adding precaution to make disposing of a command from one of its own handlers more robust [5.0.0+17] - 08.11.2023
-
https://github.com/escamoteur/flutter_command/issues/20 [5.0.0+16] - 18.9.2023
-
added experimental global setting
useChainCapturewhich can lead to better stacktraces in async commands functions [5.0.0+15] - 30.08.2023 -
improved assertion error messages [5.0.0+14] - 15.8.2023
-
made commands more robust against disposing while still running which should be totally valid because the user could close a page where a command is running [5.0.0+12] - 14.8.2023
-
added check in dispose if the command hasn't finished yet [5.0.0+11] - 13.8.2023
-
fixed bub in UndoableCommand and disabled the Chain.capture for now [5.0.0+10] - 11.8.2023
-
general refactoring to reduce code duplication
-
improving stack traces
-
adding new
reportAllExceptionsglobal override [5.0.0+9] - 02.08.2023 -
clearErrors()will now notify its listeners with anullvalue. [5.0.0+8] - 31.07.2023 -
made sure that while undo is running
isExecutingis true and will block any parallel call of the command [5.0.0+7] - 29.07.2023 -
added
clearErrorsmethod to theCommandclass which resets theerrorsproperty to null without notifying listeners -
fix for Exception
Bad state: Future already completed[5.0.0+6] - 20.06.2023 -
added two more ErrorFilter types [5.0.0+5] - 18.06.2023
-
release candidate but missing docs [5.0.0+4] - 18.05.2023
-
bug fix of a too arrow assertion [5.0.0+2] - 21.04.2023
-
bug fix in the factory functions of UndoableCommand
[5.0.0+1] - 28.03.2023
- beta version of the new UndoableCommand
[5.0.0] - 24.03.2023
-
Another breaking change but one that hopefully will be appreciated by most of you. When this package was originally written you could pass a
ValueListenable<bool> canExecutewhen you created a Command that could decide if a Command could be executed at runtime. As the naming was am reminiscent of the .Net version of RxUIs Command but confusing because Commands have a property namedcanExecutetoo I renamed it torestrictionbut didn't change the meaning of its bool values. Which meant thatrestriction==falsemeant that the Command couldn't be executed which absolutely isn't intuitive. After falling myself for this illogic use of bool values I know inverted the meaning so thatrestriction==truemeans that you cannot execute the Command. -
To add to the declarative power of defining behaviour with Command, they now got an optional handler that will be called if a Command is restricted but one tries to execute it anyway (from the source docs):
/// [ifRestrictedExecuteInstead] if [restriction] is set for the command and its value is `true`
/// this function will be called instead of the wrapped function.
/// This is useful if you want to execute a different function when the command
/// is restricted. For example you could show a dialog to let the user logg in
/// if the restriction is because the user is not logged in.
/// If you don't set this function, the command will just do nothing when it's
/// restricted.
[4.0.0] - 01.03.2023
- Two breaking changes in two days :-) I know that is a lot but I encountered a problem in one of my projects, that you might encounter too if you are using flutter_command. If your UI would change depending on the state of
isExecutingand that change was triggered from within the build function, you could get an exception telling you, thatsetStatewas called while a rebuild was already running. In this new version async Commands now wait a frame before notifying any listeners. I don't expect, that you will see any difference in your existing apps. If this latest change has any negative side effects, please open an issue immediately. As the philosophy of Commands is that your UI should always only react on state changes and not expect synchronous data, this shouldn't make any trouble.
[3.0.0] - 24.02.2023
- Breaking change: In the past the Command only triggered listeners when the resulting value of a Command execution changed. However in many case you want to always update your UI even if the result hasn't changed. Therefore Commands now always notify the listeners even if the result hasn't changed. you can change that behaviour by setting [notifyOnlyWhenValueChanges] to true when creating your Commands.
2.0.1 07.03.2021 #
- Fixed small nullability bug in the signature of
static Command<TParam, TResult> createAsync<TParam, TResult>(
Future<TResult> Function(TParam? x) func, TResult initialValue
the type of func has to be correctly Future<TResult> Function(TParam x) so now it looks like
static Command<TParam, TResult> createAsync<TParam, TResult>(
Future<TResult> Function(TParam x) func, TResult initialValue,
You could probably call this a breaking change but as it won't change the behaviour, just that you probably will have to remove some '!' from your code I won't do a major version here.
2.0.0 03.03.2021 #
- finished null safety migration
- thrownExceptions only notifies its listeners now when a error happens and not also when it is reset to null at the beginning of a command
1.0.0-nullsafety.1 15.02.2021 #
- Added
toWidget()extension method onCommandResult
0.9.2 25.10.2020 #
- Added
executeWithFutureto use withRefreshIndicator - Added
toWidget()method
0.9.1 24.08.2020 #
- Shortened package description in pubspec
0.9.0 24.08.2020 #
- Initial official release
