async_wrapper 1.0.0

SDKflutter
Platformandroidioswindowslinuxmacosweb

A lightweight Flutter package for handling async operations with built-in loading, success, and error states.

AsyncWrapper

A lightweight Flutter package that simplifies async state management by providing built-in loading, success, and error states for asynchronous operations.

Features

  • 🔄 Automatic state management - Handles loading, success, and error states
  • 🚀 Easy to use - Wrap any async operation with minimal boilerplate
  • 🎯 Type-safe - Generic implementation with full type support
  • Flexible - Supports autorun, multiple fetches, and lifecycle callbacks
  • 🎨 Reactive UI - Rebuild widgets based on async state changes

Installation

Add this to your package's pubspec.yaml file:

dependencies:
  async_wrapper: ^1.0.0

Then run:

flutter pub get

Usage

Basic Example

import 'package:async_wrapper/async_wrapper.dart';

AsyncWrapper<String>(
  fetch: () async {
    // Simulate API call
    await Future.delayed(Duration(seconds: 2));
    return "Hello, World!";
  },
  builder: (trigger, state) {
    if (state.isPending) {
      return CircularProgressIndicator();
    }

    if (state.isError) {
      return Text('Error: ${state.error}');
    }

    if (state.isSuccess) {
      return Text('Result: ${state.data}');
    }

    return ElevatedButton(
      onPressed: trigger,
      child: Text('Start Async Operation'),
    );
  },
)

API Status Check Example

AsyncWrapper<bool>(
  autorun: true, // Automatically runs on initialization
  fetch: () async => await apiService.checkConnection(),
  onSuccess: (isConnected, retry) {
    if (isConnected) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Connected to server!')),
      );
    }
  },
  onError: (error, retry) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('Connection failed: $error')),
    );
  },
  builder: (checkConnection, state) {
    return Column(
      children: [
        if (state.isPending)
          CircularProgressIndicator()
        else
          Icon(
            state.isSuccess && state.data == true
              ? Icons.wifi
              : Icons.wifi_off,
            color: state.isSuccess && state.data == true
              ? Colors.green
              : Colors.red,
          ),
        ElevatedButton(
          onPressed: state.isPending ? null : checkConnection,
          child: Text('Check Connection'),
        ),
      ],
    );
  },
)

User Profile Example

class UserProfile extends StatelessWidget {
  final String userId;

  const UserProfile({required this.userId});

  @override
  Widget build(BuildContext context) {
    return AsyncWrapper<User>(
      autorun: true,
      fetch: () => userRepository.fetchUser(userId),
      builder: (refetch, state) {
        return RefreshIndicator(
          onRefresh: refetch,
          child: ListView(
            children: [
              if (state.isPending && state.data == null)
                Center(child: CircularProgressIndicator())
              else if (state.isError)
                ErrorWidget(
                  error: state.error.toString(),
                  onRetry: refetch,
                )
              else if (state.isSuccess && state.data != null)
                UserCard(user: state.data!)
              else
                EmptyState(onRefresh: refetch),
            ],
          ),
        );
      },
    );
  }
}

API Reference

AsyncWrapper Properties

PropertyTypeDescriptionDefault
fetchAsyncCallback<T>The async operation to executerequired
builderAsyncBuilder<T>Builder function receiving trigger and staterequired
autorunboolAuto-execute fetch on initializationfalse
multipleFetchboolAllow multiple concurrent fetchesfalse
onSuccessFunction(T, AsyncCallback<void>)?Success callback with data and retry functionnull
onErrorFunction(Object?, AsyncCallback<void>)?Error callback with error and retry functionnull

AsyncState Properties

PropertyTypeDescription
stateLoadStateCurrent state (stale, pending, success, error)
dataT?Success data (null if not successful)
errorObject?Error object (null if no error)

AsyncState Getters

GetterTypeDescription
staleboolTrue if fetch hasn't started
isPendingboolTrue if fetch is in progress
isSuccessboolTrue if fetch completed successfully
isErrorboolTrue if fetch resulted in error

LoadState Enum

enum LoadState { stale, pending, success, error }

Advanced Usage

Multiple Fetch Operations

AsyncWrapper<String>(
  multipleFetch: true, // Allows concurrent operations
  fetch: () => apiService.fetchData(),
  builder: (trigger, state) {
    return ElevatedButton(
      onPressed: trigger, // Can be called even while pending
      child: state.isPending
        ? CircularProgressIndicator()
        : Text('Fetch Data'),
    );
  },
)

State Persistence During Updates

AsyncWrapper<List<Item>>(
  fetch: () => repository.fetchItems(),
  builder: (refresh, state) {
    // Show previous data while refreshing
    final items = state.data ?? [];

    return Column(
      children: [
        if (state.isPending && items.isEmpty)
          CircularProgressIndicator()
        else if (state.isPending)
          LinearProgressIndicator(), // Show loading bar during refresh

        if (state.isError && items.isEmpty)
          ErrorMessage(error: state.error, onRetry: refresh)
        else
          ItemList(items: items, onRefresh: refresh),
      ],
    );
  },
)

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

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