Skip to content

Commit

Permalink
adding onSuccess builder and isSuccess property
Browse files Browse the repository at this point in the history
  • Loading branch information
escamoteur committed Dec 25, 2024
1 parent e17b1ce commit 9d7b276
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 6 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,8 +311,10 @@ class CommandResult<TParam, TResult> {
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
}
Expand Down Expand Up @@ -378,6 +380,9 @@ child: CommandBuilder<String, List<WeatherEntry>>(
),
```

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:

Expand Down
27 changes: 23 additions & 4 deletions lib/command_builder.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_command/flutter_command.dart';
part of flutter_command;

class CommandBuilder<TParam, TResult> extends StatelessWidget {
final Command<TParam, TResult> 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,
Expand All @@ -20,6 +29,7 @@ class CommandBuilder<TParam, TResult> extends StatelessWidget {

const CommandBuilder({
required this.command,
this.onSuccess,
this.onData,
this.onNullData,
this.whileExecuting,
Expand All @@ -29,10 +39,13 @@ class CommandBuilder<TParam, TResult> extends StatelessWidget {

@override
Widget build(BuildContext context) {
if (command._noReturnValue) {}
return ValueListenableBuilder<CommandResult<TParam?, TResult>>(
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) =>
Expand All @@ -59,19 +72,25 @@ class CommandBuilder<TParam, TResult> extends StatelessWidget {
extension ToWidgeCommandResult<TParam, TResult>
on CommandResult<TParam, TResult> {
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();
}
Expand Down
5 changes: 4 additions & 1 deletion lib/flutter_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ 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';

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
Expand Down Expand Up @@ -52,6 +52,9 @@ class CommandResult<TParam, TResult> {

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;
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -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:
Expand Down

0 comments on commit 9d7b276

Please sign in to comment.