AsyncButtonBuilder offers a simple way to extend any type of button with an asynchronous aspect

Overview

async_button_builder

AsyncButtonBuilder offers a simple way to extend any type of button with an asynchronous aspect. It allows adding loading, disabled, errored and completed states (with fluid animation between each) on top of buttons that perform asynchronous tasks.

Getting Started

Include the package:

  async_button_builder: 
   

Wrap the builder around a button, passing the onPressed and child element to builder instead of the button directly. These two are the only required fields.

AsyncButtonBuilder(
  child: Text('Click Me'),
  onPressed: () async {
    await Future.delayed(Duration(seconds: 1));
  },
  builder: (context, child, callback, _) {
    return TextButton(
      child: child,
      onPressed: callback,
    );
  },
),

The fourth value in the builder allows you listen to the loading state. This can be used to conditionally style the button. This package depends freezed in order to create a sealed union to better handle the possible states.

AsyncButtonBuilder(
  child: Text('Click Me'),
  loadingWidget: Text('Loading...'),
  onPressed: () async {
    await Future.delayed(Duration(seconds: 1));

    // See the examples file for a way to handle timeouts
    throw 'yikes';
  },
  builder: (context, child, callback, buttonState) {
    final buttonColor = buttonState.when(
      idle: () => Colors.yellow[200],
      loading: () => Colors.grey,
      success: () => Colors.orangeAccent,
      error: () => Colors.orange,
    );

    return OutlinedButton(
      child: child,
      onPressed: callback,
      style: OutlinedButton.styleFrom(
        primary: Colors.black,
        backgroundColor: buttonColor,
      ),
    );
  },
),

You can also drive the state of the button yourself using the buttonState field:

AsyncButtonBuilder(
  buttonState: ButtonState.completing(),
  // ...
),

async_button_builder even works for custom buttons. You can define your own widgets for loading, error, and completion as well as define the transitions between them. This example is a little verbose but shows some of what's possible.

AsyncButtonBuilder(
  child: Padding(
    padding: const EdgeInsets.symmetric(
      horizontal: 16.0,
      vertical: 8.0,
    ),
    child: Text(
      'Click Me',
      style: TextStyle(color: Colors.white),
    ),
  ),
  loadingWidget: Padding(
    padding: const EdgeInsets.all(8.0),
    child: SizedBox(
      height: 16.0,
      width: 16.0,
      child: CircularProgressIndicator(
        valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
      ),
    ),
  ),
  successWidget: Padding(
    padding: const EdgeInsets.all(4.0),
    child: Icon(
      Icons.check,
      color: Colors.purpleAccent,
    ),
  ),
  onPressed: () async {
    await Future.delayed(Duration(seconds: 2));
  },
  loadingSwitchInCurve: Curves.bounceInOut,
  loadingTransitionBuilder: (child, animation) {
    return SlideTransition(
      position: Tween<Offset>(
        begin: Offset(0, 1.0),
        end: Offset(0, 0),
      ).animate(animation),
      child: child,
    );
  },
  builder: (context, child, callback, state) {
    return Material(
      color: state.maybeWhen(
        success: () => Colors.purple[100],
        orElse: () => Colors.blue,
      ),
      // This prevents the loading indicator showing below the
      // button
      clipBehavior: Clip.hardEdge,
      shape: StadiumBorder(),
      child: InkWell(
        child: child,
        onTap: callback,
      ),
    );
  },
),

Issues and PR's welcome

Comments
  • v2.1.2+1 fails to compile with flutter v2.2.2

    v2.1.2+1 fails to compile with flutter v2.2.2

    async_button_builder-2.1.2+1/lib/src/async_button_builder.dart:355:25: Error: Required named parameter 'vsync' must be provided. /flutter/lib/src/widgets/animated_size.dart:56:9: Context: Found this candidate, but the arguments don't match.

    My flutter env is:

    Doctor summary (to see all details, run flutter doctor -v):
    [✓] Flutter (Channel stable, 2.2.2, on Linux, locale en_US.UTF-8)
    [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
    [✓] Chrome - develop for the web
    [✓] Android Studio (version 4.2)
    [✓] IntelliJ IDEA Ultimate Edition (version 2021.1)
    [✓] VS Code (version 1.56.2)
    [✓] Connected device (1 available)
    
    opened by oysterpack 3
  • Make a `hook` version in a subpackage

    Make a `hook` version in a subpackage

    This will need to be a subpackage so users don't rely on hooks unnecessarily. I think https://github.com/Baseflow/flutter_cache_manager does something like this for its firebase implementation. Copy how they do it

    final buttonHandler = useAsyncButton(myCallback, child);
    
    // Then add these to the UI
    // buttonHandler.child
    // buttonHandler.callback
    
    enhancement 
    opened by Nolence 2
  • Current version of the package depends on a beta dart SDK

    Current version of the package depends on a beta dart SDK

    I've used the latest version of this package and noticed that it requires a minimum dart sdk of 2.12.0 and the current stable version (listed on https://dart.dev/get-dart) is 2.10.

    Can this be used to only rely on stable versions of dart sdk ?

    enhancement 
    opened by pradt 2
  • [BREAKING] Adds custom animation support as well as more button states

    [BREAKING] Adds custom animation support as well as more button states

    Sort of an RFC

    This handles #5 as well as #4.

    This is a breaking change and will require users to better manage states.

    Instead of a simple isLoading boolean to check the state of the button, users will instead be provided a sealed union for the button state -- either idling, loading, erroring, or completing. The setter for isLoading will also be removed as it does not provide as much customizability asI would have liked

    enhancement 
    opened by Nolence 2
  • Support isCompleted animation

    Support isCompleted animation

    We should have an optional isCompleted widget that will show after the completion of the async operation.

    The animation and duration it stays up would optionally be provided by the user.

    This would be a breaking change however as it would introduce a third state -- one more over basic isLoading:

    enum ButtonState { resting, loading, completed }
    

    that would take the place of the fourth isLoading value in the builder. That would allow users to still conditionally render their button depending on what state its in.

    enhancement 
    opened by Nolence 2
  • Does not throw at original call site

    Does not throw at original call site

    When debugging in VSCode, if I have an exception at a certain point in the code, the debugger always leaves me off at the rethrow instead of the original error point. It's not unusable but it's annoying. Currently dart does not have a way to rethrow the error and the stacktrace so I'll have to think of something in the meantime.

    Maybe .catchError doesn't have the same behaviour? Or maybe I can somehow use a completer.

    enhancement 
    opened by Nolence 1
  • Why does the user need to provide keys?

    Why does the user need to provide keys?

    Why don't I just provide keys myself if I know what widgets are going to be what in the AnimatedTransition? That should be easier than relying on users or doing that asserts everywhere

    This shouldn't be a breaking change

    enhancement 
    opened by Nolence 1
  • Remove `freezed` dependency

    Remove `freezed` dependency

    As much as I love and use freezed in my own projects, I don't think this is a necessary requirement for such a simple library. I can't really think of a better way to handle the sealed union nature of the AppState though and would love some suggestions.

    This only seems like an issue for me now because freezed requires freezed_annotations and that depends on json_annotations which, thanks to nnbd, a lot of other libraries are not quite up to speed on requiring their v4.0.0 version. As a result, this will break dep resolution for some users.

    Another option would to be to publish a stable 2.0.0 version that isn't nnbd and uses the older version. People could still depend on this package then without breaking things.

    enhancement 
    opened by Nolence 1
  • removed `freezed` dependency and added new callbacks

    removed `freezed` dependency and added new callbacks

    As the generated codes are still available, it doesn't make sense to have "freezed_annotation" in the dependencies. If a new button state is needed which is not likely to happen, then it can be temporarily added and removed after generating the code.

    Added two new optional parameters: "onSuccess" and "onError".

    opened by mergehez 0
  • child should be removed in favor of value<T>

    child should be removed in favor of value

    If you want to be able to do a SlidableAction you can't because it takes in raw strings and IconData:

                SlidableAction(
                  label: StringsResource.systemRemove, // String
                  backgroundColor: colors.eventLevel4,
                  icon: icons.delete, // IconData
                  onPressed: (context) async {
                    await maybeOnDeleteDevice();
                  },
                ),
    

    Instead our buttonBuilder should be

    AsyncButtonBuilder<T>(
      value: T,
      loadingValue: T,
      builder: (context, T value, _, __) {
        // ...
      },
    )
    

    We can do an internal check to see if the type is a Widget and provide defaults such as loading widgets etc.

    I'm not sure on this though I'll let it settle in my mind.

    enhancement 
    opened by Nolence 0
  • Added error and stack trace parameters to onError

    Added error and stack trace parameters to onError

    This adds the thrown error and stackTrace parameters to the onError callback.

    It's quite useful to have these passed in, so the caller can e.g. show a SnackBar with some of the error details.

    opened by jonjomckay 4
  • CI deploy to pub.dev on merge

    CI deploy to pub.dev on merge

    Steps

    1. add pub api key to github repo secrets
    2. query for it in CI (only on merge not pr)

    should also run a dry-run on PR so I know the version have been bumped and changelog updated

    enhancement 
    opened by Nolence 0
  • error in new flutter version

    error in new flutter version

    Hi I have error after upgrade flutter to 2.2.3

    `/C:/flutter/.pub-cache/hosted/pub.dartlang.org/async_button_builder-2.1.3+9/lib/src/async_button_builder.dart:271:25: Error: Required named parameter 'vsync' must be provided. ? AnimatedSize( ^ /C:/flutter/packages/flutter/lib/src/widgets/animated_size.dart:56:9: Context: Found this candidate, but the arguments don't match. const AnimatedSize({ ^^^^^^^^^^^^

    FAILURE: Build failed with an exception.`

    Flutter 2.2.3 • channel stable • https://github.com/flutter/flutter.git Framework • revision f4abaa0735 (4 months ago) • 2021-07-01 12:46:11 -0700 Engine • revision 241c87ad80 Tools • Dart 2.13.4

    also i can not get older version because when add older version, download lasted version again

    opened by iranandroid 0
  • RFC: What about onLongPress, onDoubleTap?

    RFC: What about onLongPress, onDoubleTap?

    I could add more parameters, but then the function signature would change on the builder which is breaking. I could also make a class to hold all the various types of taps but that's also breaking:

    AsyncButtonBuilder(
      child: Text('Click Me'),
      onPressed: () async {
        await Future.delayed(Duration(seconds: 1));
      },
      onLongPressed: () async {
        await Future.delayed(Duration(seconds: 1));
      }
      builder: (context, child, callback, _) {
        return TextButton(
          child: child,
          onPressed: callback.onPressed,
          onLongPressed: callback.onLongPressed
        );
      },
    ),
    

    Dunno.

    Another non-breaking option would to make a factory version with all the different types of presses. Not really the cleanest solution though.

    enhancement help wanted 
    opened by Nolence 2
Owner
Nollie
sunlight is for chumps
Nollie
Flutter Triple Status Button can use toggle button but in three statuses.

triple_status_button Triple Status Button. Flutter Triple Status Button can use toggle button but in three statuses. Property Description height heigh

MahdiBagjani 2 Nov 13, 2021
A button that looks like a Cupertino text button

Cupertino Text Button A button that looks like a Cupertino text button! Text Button A simple text button can be created like this: CupertinoTextButton

Nick Sirovsky 0 Nov 24, 2022
Flutter reaction button plugin it is fully customizable widget such as Facebook reaction button

Flutter Reaction Button Flutter button reaction it is fully customizable widget such as Facebook reaction button. Preview Demo Usage Include 'flutter_

Abdelouahed Medjoudja 174 Dec 19, 2022
Flutter widget for fetching, caching and refetching asynchronous data.

Flutter library for fetching, caching and invalidating asynchronous data Quick Features Fetch asynchronous data Data invalidation Optimistic response

null 32 Dec 24, 2022
A popup simple topModalSheet menu button widget with handsome design and easy to use

top_modal_sheet A popup simple topModalSheet menu button widget with handsome design and easy to use. Installations Add top_modal_sheet: ^1.0.0 in you

Baldemar Alejandres 5 Jul 29, 2022
RoundedLoadingButton is a Flutter package with a simple implementation of an animated loading button, complete with success and error animations.

rounded_loading_button RoundedLoadingButton is a Flutter package with a simple implementation of an animated loading button, complete with success and

Chris Edgington 223 Jan 4, 2023
Simple flutter toggle button widge

This is simple flutter toggle button widget. Supports show text labels and icons, Possible set multiple value to toggle ui, not only

fukutan 1 Sep 27, 2022
A button with ripple effect while being hold

ripple_button a button with ripple effect while being hold build requirements to run this project you need a working enviroment of flutter v2 or highe

null 2 Nov 8, 2021
May be used to intercept the Android back-button, as an alternative to `WillPopScope`.

back_button_interceptor In simple cases, when you need to intercept the Android back-button, you usually add WillPopScope to your widget tree. However

Marcelo Glasberg 93 Dec 12, 2022
A Widget that mimics the Facebook Reaction Button in Flutter.

ReactiveButton A Widget that mimics the Facebook Reaction Button in Flutter. Step by step explanation A full explanation on how to build such Widget m

Didier Boelens 47 Jul 12, 2022
A custom dropdown button lets the user select from a number of items

CircularDropDownMenu Description A custom dropdown button lets the user select from a number of items. The button shows the currently selected item as

Surya Dev Singh 2 Dec 5, 2020
Flutter base, with a navigation button

mysample A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if this

null 0 Dec 30, 2021
Flutter progress button

flutter_progress_button flutter_progress_button is a free and open source (MIT license) Material Flutter Button that supports variety of buttons style

Yang JIANG 91 Dec 6, 2022
Flutter Custom, Text, 3D, Social media button's package

Flutter Button flutter_button, which is a flutter package, contains animated, cool and awesome buttons. That you may like, thanks to this package you

Ismael Shakverdiev 15 Dec 29, 2022
This flutter package provides an easy implementation of a Slider Button to cancel current transaction or screen

This flutter package provides an easy implementation of a Slider Button to cancel current transaction or screen

null 222 Nov 8, 2022
A library to easily create radio button and checkbox groups.

Check/Radio Group A library to easily create radio button and checkbox groups. Define font size, selection color, position of radios / check and text

Caiubi Tech 2 Jan 6, 2021
AdvFAB - An Advanced floating action button that expands itself to reveal its hidden widget

AdvFAB (More Than Just A Floating Action Button) AdvFAB is An Advanced floating action button that expands itself to reveal its hidden widget. It can

null 19 Nov 4, 2022
Widget, that can make any static located widget hidable

Installing See the official installing guidline from hidable/install Usage & Overview To start using Hidable widget, we have to create a ScrollControl

Anon 18 Dec 16, 2022
Flutter package: Similar to a ListView, but lets you programmatically jump to any item, by index.

indexed_list_view Similar to a ListView, but lets you programmatically jump to any item, by index. The index jump happens instantly, no matter if you

Marcelo Glasberg 244 Dec 27, 2022