From 9d7b276d5e965c69fa09df7e1fc90dd4d31526a0 Mon Sep 17 00:00:00 2001 From: Thomas Burkhart Date: Wed, 25 Dec 2024 19:22:51 +0100 Subject: [PATCH] adding onSuccess builder and isSuccess property --- CHANGELOG.md | 3 +++ README.md | 5 +++++ lib/command_builder.dart | 27 +++++++++++++++++++++++---- lib/flutter_command.dart | 5 ++++- pubspec.yaml | 2 +- 5 files changed, 36 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5432d7..2793eaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +[7.2.0] - 25.12.2024 +* adding `onSuccess` builder to the `CommandBuilder` and `isSuccess` to the `CommandResults` to make them easiery to use +if the Command doesn't return a value. [7.1.0] 27.11.2024 * adding `isExecutingSync` to allow better chaining of commands [7.0.1] 27.11.2024 diff --git a/README.md b/README.md index 003af07..06853df 100644 --- a/README.md +++ b/README.md @@ -311,8 +311,10 @@ class CommandResult { final Object error; final bool isExecuting; + bool get isSuccsess => !hasError && !isExecuting; bool get hasData => data != null; bool get hasError => error != null; + /// This is a stripped down version of the class. Please see the source } @@ -378,6 +380,9 @@ child: CommandBuilder>( ), ``` +In case your Command does not return a value you can use the `onSuccess` builder. + + ### toWidget() extension method on Command Result I you are using a package `get_it_mixin`, `provider` or `flutter_hooks` you probably don't want to use the `CommandBuilder` for you there is an extension method for the `CommandResult` type that you can use like this: diff --git a/lib/command_builder.dart b/lib/command_builder.dart index 2271453..442525a 100644 --- a/lib/command_builder.dart +++ b/lib/command_builder.dart @@ -1,10 +1,19 @@ -import 'package:flutter/widgets.dart'; -import 'package:flutter_command/flutter_command.dart'; +part of flutter_command; class CommandBuilder extends StatelessWidget { final Command command; + + /// This builder will be called when the + /// command is executed successfully, independent of the return value. + final Widget Function(BuildContext context, TParam? param)? onSuccess; + + /// If your command has a return value, you can use this builder to build a widget + /// when the command is executed successfully. final Widget Function(BuildContext context, TResult data, TParam? param)? onData; + + /// If the command has no return value or returns null, this builder will be called when the + /// command is executed successfully. final Widget Function(BuildContext context, TParam? param)? onNullData; final Widget Function( BuildContext context, @@ -20,6 +29,7 @@ class CommandBuilder extends StatelessWidget { const CommandBuilder({ required this.command, + this.onSuccess, this.onData, this.onNullData, this.whileExecuting, @@ -29,10 +39,13 @@ class CommandBuilder extends StatelessWidget { @override Widget build(BuildContext context) { + if (command._noReturnValue) {} return ValueListenableBuilder>( valueListenable: command.results, builder: (context, result, _) { return result.toWidget( + onSuccess: (paramData) => + onSuccess?.call(context, paramData) ?? const SizedBox(), onData: (data, paramData) => onData?.call(context, data, paramData) ?? const SizedBox(), onNullData: (paramData) => @@ -59,19 +72,25 @@ class CommandBuilder extends StatelessWidget { extension ToWidgeCommandResult on CommandResult { Widget toWidget({ - required Widget Function(TResult result, TParam? param) onData, + Widget Function(TResult result, TParam? param)? onData, + Widget Function(TParam? param)? onSuccess, Widget Function(TParam? param)? onNullData, Widget Function(TResult? lastResult, TParam? param)? whileExecuting, Widget Function(Object error, TResult? lastResult, TParam? param)? onError, }) { + assert(onData != null || onSuccess != null, + 'You have to provide at least a builder for onData or onSuccess'); if (error != null) { return onError?.call(error!, data, paramData) ?? const SizedBox(); } if (isExecuting) { return whileExecuting?.call(data, paramData) ?? const SizedBox(); } + if (onSuccess != null) { + return onSuccess.call(paramData); + } if (data != null) { - return onData(data as TResult, paramData); + return onData?.call(data as TResult, paramData) ?? const SizedBox(); } else { return onNullData?.call(paramData) ?? const SizedBox(); } diff --git a/lib/flutter_command.dart b/lib/flutter_command.dart index c337dad..54b7489 100644 --- a/lib/flutter_command.dart +++ b/lib/flutter_command.dart @@ -11,7 +11,6 @@ import 'package:stack_trace/stack_trace.dart'; import 'error_filters.dart'; -export 'package:flutter_command/command_builder.dart'; export 'package:flutter_command/error_filters.dart'; export 'package:functional_listener/functional_listener.dart'; @@ -19,6 +18,7 @@ part './async_command.dart'; part './mock_command.dart'; part './sync_command.dart'; part './undoable_command.dart'; +part './command_builder.dart'; /// Combined execution state of a `Command` represented using four of its fields. /// A [CommandResult] will be issued for any state change of any of its fields @@ -52,6 +52,9 @@ class CommandResult { const CommandResult.blank() : this(null, null, null, false); + /// if a CommandResult is not executing and has no error, it is considered successful + /// if the command has no return value, this can be used to check if the command was executed successfully + bool get isSuccess => !isExecuting && !hasError; bool get hasData => data != null; bool get hasError => error != null && !isUndoValue; diff --git a/pubspec.yaml b/pubspec.yaml index a1635ad..3574f0b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_command description: flutter_command is a way to manage your state based on `ValueListenable` and the `Command` design pattern. -version: 7.1.0 +version: 7.2.0 homepage: https://github.com/escamoteur/flutter_command environment: