# Future Provider Package

`future_provider` is a Flutter package designed to help developers handle asynchronous operations with ease. It allows you to execute multiple asynchronous tasks, handle success/failure responses, manage loading states, and retry failed tasks with a clean and modular approach.

## Features

- Sequential execution of multiple asynchronous tasks.
- Handles loading states and provides progress feedback.
- Supports retries for failed tasks with a configurable retry limit.
- Built-in success and failure handlers.
- Lightweight and easy-to-use API.

## Getting Started

To use the `future_provider` package in your Flutter project, follow these steps:

### Step 1: Add Dependency

Add the following dependency to your `pubspec.yaml`:

```yaml
dependencies:
  future_provider: ^1.0.0

Then, run:

flutter pub get

Step 2: Import the Package

Import the future_provider package in the Dart file where you want to use it:

import 'package:future_provider/future_provider.dart';

Class: FutureProvider

The FutureProvider class is the core of the package. It is designed to manage asynchronous operations by executing tasks sequentially and handling various states like loading, success, and failure.

Constructor

FutureProvider(BuildContext context);

Parameters:

  • context: The BuildContext used for showing progress indicators and managing dialogs.

Methods

void init()

Initializes the process by loading the processes and setting up the necessary state.

void _start({bool diable=false})

Starts the process. If diable is true, it shows a loading dialog.

void _stop({bool diable=false})

Stops the ongoing process. If diable is true, it hides the loading dialog.

void executeSingleProcess(...)

Executes a single process. This method runs a specific process and handles its result or failure.

Parameters:
  • enableLoadIndicator: Whether to show the loading indicator while the process is running.
  • onExecuted: A callback that is called after the process has been executed.
  • onFailed: A callback that is called if the process fails.

void executeAll(...)

Executes all processes in sequence. It handles the execution of multiple processes and provides feedback after each task.

void resetProcess()

Resets the process state, clearing any ongoing tasks and results.

bool get isAllProcessCompleted

Checks if all processes have been completed.

How to Use

Example.dart


class Example extends FutureProvider {

  Example(super.context);

  Future<String> getData() async {
    await Future.delayed(const Duration(seconds: 1));
    return "{DATA}";
  }


  @override
  FutureProcess loadProcess() => FutureProcess({
    "get_data": getData,
  });

  @override
  void onSucess(FutureData data) {
    // print(data.futureData);
  }

}

Home.dart


import 'dart:math';
import 'package:flutter/material.dart';
import 'package:future/main.dart';
import 'package:future/mylib/future_event.dart';
import 'package:future/mylib/future_process.dart';
import 'package:future/services/api_service.dart';

class Home extends StatefulWidget {
  
  const Home({super.key});

  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {

  late Example service = Example(context);

  @override
  Widget build(BuildContext context) {


    return Scaffold(
      body: ElevetedButton(
        onPressed: (){
            service.executeAll();
        },
        child: Center(child: Text("Load")),
      ),
    );
  }
}


Class: FutureProcess

The FutureProcess class holds a map of processes (each represented as a Future function) and provides methods to find, execute, and manage these processes.

Constructor

FutureProcess(Map<String, Future Function()> proccessList);

Parameters:

  • proccessList: A map where the key is a string ID for each process, and the value is a Future function.

Methods

Future Function() findById(String id)

Finds and returns a Future function by its ID.

Future Function() findByIndex(int idx)

Finds and returns a Future function by its index in the list.

int findIndexById(String id)

Finds and returns the index of a process by its ID.


Class: FutureData

The FutureData class holds the results of the executed asynchronous tasks in a list.

Constructor

FutureData();

Properties

  • futureData: A list where the results of the executed tasks are stored.

Class: FutureWidget

FutureWidget is a customizable widget that allows you to display asynchronous data with loading states, retries, and failure handling.

Constructor

FutureWidget({
  required this.process,
  required this.builder,
  this.canBuild=true,
  this.loadingIndicator,
  this.withAnimation=false,
  this.canExecuteProcess=true,
  this.reTryTime=1,
  this.canReTry=false,
  this.onSucess,
});

Parameters:

  • process: The FutureProcess that holds the processes to execute.
  • builder: A callback that builds the widget once the process is completed.
  • loadingIndicator: A custom widget to display while loading.
  • canReTry: Whether the widget should retry failed tasks.
  • reTryTime: The number of retries before giving up.

Example Usage

FutureWidget(
  process: myProcess,  // An instance of FutureProcess
  builder: (context, data) {
    return Text('Process Completed!');
  },
  loadingIndicator: CircularProgressIndicator(),
  onSucess: () {
    print('Process Successful!');
  },
);

Example

import 'dart:math';
import 'package:flutter/material.dart';
import 'package:future/mylib/future_process.dart';
import 'package:future/mylib/future_widget.dart';

class RetryExample extends StatelessWidget {
  const RetryExample({super.key});

  Future<Map<String, dynamic>> getUserProfile() async {
    await Future.delayed(Duration(seconds: 2));
    return {"name": "John Doe", "age": 25};
  }

  Future<List<String>> getUserPosts() async {
    await Future.delayed(Duration(seconds: 2));
    return ["Hello World!", "Flutter is awesome!", "FutureWidget Testing"];
  }

  Future<List<String>> getUserFollowers() async {
    await Future.delayed(Duration(seconds: 2));
    if (Random().nextBool()) {
      throw Exception("Followers fetch failed");
    }
    return ["Alice", "Bob", "Charlie"];
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: FutureWidget(
          process: FutureProcess({
            "getUserProfile": getUserProfile,
            "getUserPosts": getUserPosts,
            "getUserFollowers": getUserFollowers,
          }),
          canReTry: true,
          reTryTime: 3, // Retry 3 times before failing
          builder: (context, data) {
            final user = data.futureData[0];
            final posts = data.futureData[1];
            final followers = data.futureData[2];

            return Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text("[User: ${user['name']}, Age: ${user['age']}]"),
                for (int i = 0; i < posts.length; i++) Text("Post ${i + 1}: ${posts[i]}"),
                if (followers == null)
                  Column(
                    children: [
                      Icon(Icons.error, color: Colors.red),
                      Text("❌ Failed to Load Data"),
                    ],
                  )
                else
                  Column(
                    children: [
                      Text("Data"),
                    ],
                  ),
              ],
            );
          },
        ),
      ),
    );
  }
}


Class: FutureList

FutureList is a widget designed for executing multiple processes in sequence and displaying the results. It handles success and failure at each step, and allows for retrying failed tasks.

Constructor

FutureList({
  required this.process,
  required this.childern,
  required this.mainContext,
  this.showLog = true,
});

Parameters:

  • process: The FutureProcess object containing the list of tasks to execute.
  • childern: A list of ListBuilder objects that define how to build widgets before and after each task.
  • showLog: Whether to show debug logs.

Example Usage

FutureList(
  process: myProcess,  // An instance of FutureProcess
  childern: [
    ListBuilder(
      builder: (data) {
        return Text('First Process Completed');
      },
      beforeLoadWidget: () => CircularProgressIndicator(),
    ),
    // More ListBuilder items...
  ],
  mainContext: context,
);

Example

import 'dart:math';
import 'package:flutter/material.dart';
import 'package:future/mylib/future_list.dart';
import 'package:future/mylib/future_process.dart';

class FutureListTest extends StatefulWidget {
  @override
  _FutureListTestState createState() => _FutureListTestState();
}

class _FutureListTestState extends State<FutureListTest> {
  
  Future<String> fetchUserProfile() async {
    await Future.delayed(Duration(seconds: 2));
    if (Random().nextBool()) throw Exception("Profile Fetch Failed");
    return "User: John Doe, Age: 25";
  }

  Future<List<String>> fetchUserPosts() async {
    await Future.delayed(Duration(seconds: 3));
    if (Random().nextBool()) throw Exception("Posts Fetch Failed");
    return ["Post 1: Hello World!", "Post 2: Flutter is awesome!", "Post 3: FutureList Testing"];
  }

  Future<List<String>> fetchUserFollowers() async {
    await Future.delayed(Duration(seconds: 2));
    if (Random().nextBool()) throw Exception("Followers Fetch Failed");
    return ["Alice", "Bob", "Charlie", "David"];
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("FutureList Complex Test")),
      body: FutureList(
        mainContext: context,
        process: FutureProcess({
          'fetch_profile': fetchUserProfile,
          'fetch_posts': fetchUserPosts,
          'fetch_followers': fetchUserFollowers,
        }),
        childern: [
          // Profile Fetch
          ListBuilder(
            onFailDisplayWidget: () => Center(
              child: Column(
                children: [
                  Text("❌ Failed to Load Profile"),
                  ElevatedButton(
                    onPressed: () => setState(() {}),
                    child: Text("Retry"),
                  ),
                ],
              ),
            ),
            builder: (data) => ListTile(
              leading: Icon(Icons.person, size: 50),
              title: Text(data.futureData.toString(), style: TextStyle(fontSize: 18)),
            ),
          ),

          // Posts Fetch
          ListBuilder(
            onFailDisplayWidget: () => Center(
              child: Column(
                children: [
                  Text("❌ Failed to Load Posts"),
                  ElevatedButton(
                    onPressed: () => setState(() {}),
                    child: Text("Retry"),
                  ),
                ],
              ),
            ),
            builder: (data) => Column(
              children: (data.futureData.first as List<String>)
                  .map((post) => ListTile(title: Text(post)))
                  .toList(),
            ),
          ),

          // Followers Fetch
          ListBuilder(
            onFailDisplayWidget: () => Center(
              child: Column(
                children: [
                  Text("❌ Failed to Load Followers"),
                  ElevatedButton(
                    onPressed: () => setState(() {}),
                    child: Text("Retry"),
                  ),
                ],
              ),
            ),
            // builder: (data) => Text("Loaded ${data.futureData}"),
            builder: (data) => Wrap(
              children: (data.futureData.first as List<String>)
                  .map((follower) => Chip(label: Text(follower)))
                  .toList(),
            ),
          ),

          
        ],
      ),
    );
  }
}


Additional Information

Contributing

To contribute to this package, fork the repository and submit a pull request with your changes.

Issues

If you encounter any issues or have any feature requests, please open an issue on the repository.


License

This package is licensed under the MIT License. See the LICENSE file for more information.