Logosolidart

ResourceBuilder

The ResourceBuilder widget makes the consumption of a Resource extremely simple. It takes a resource and a builder fired any time the resource state changes.

Let's see it in action:

import 'package:flutter/material.dart';
import 'package:flutter_solidart/flutter_solidart.dart';
import 'package:http/http.dart' as http;

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

  @override
  State<ResourcePage> createState() => _ResourcePageState();
}

class _ResourcePageState extends State<ResourcePage> {
  // source
  final userId = Signal(1);
  // resource
  late final Resource<String> user;

  @override
  void initState() {
    super.initState();
    // creating the resource
    user = Resource(fetcher: fetchUser, source: userId);
  }

  @override
  void dispose() {
    // disposing the source and resource
    userId.dispose();
    user.dispose();
    super.dispose();
  }

  // fetcher
  Future<String> fetchUser() async {
    print('fetchUser function called (with 2s initial delay)');
    // simulating a delay to mimic a slow HTTP request
    await Future.delayed(const Duration(seconds: 2));
    print('Now fetching user: ${userId.value}');
    final response = await http.get(
      Uri.parse('https://swapi.dev/api/people/${userId.value}/'),
    );
    return response.body;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Resource'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextFormField(
              initialValue: "1",
              decoration: const InputDecoration(
                hintText: 'Enter numeric id',
              ),
              onChanged: (s) {
                final intValue = int.tryParse(s);
                if (intValue == null) return;

                userId.value = intValue;
              },
            ),
            const SizedBox(height: 16),
            ResourceBuilder(
              resource: user,
              builder: (_, userState) {
                return userState.on(
                  ready: (data) {
                    return Column(
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        ListTile(
                          title: Text(data),
                          subtitle:
                              Text('refreshing: ${userState.isRefreshing}'),
                        ),
                        userState.isRefreshing
                            ? const CircularProgressIndicator()
                            : ElevatedButton(
                                onPressed: user.refresh,
                                child: const Text('Refresh'),
                              ),
                      ],
                    );
                  },
                  error: (e, _) {
                    return Column(
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        Text(e.toString()),
                        userState.isRefreshing
                            ? const CircularProgressIndicator()
                            : ElevatedButton(
                                onPressed: user.refresh,
                                child: const Text('Refresh'),
                              ),
                      ],
                    );
                  },
                  loading: () {
                    return const RepaintBoundary(
                      child: CircularProgressIndicator(),
                    );
                  },
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}
You should not call resolve() if you're using ResourceBuilder, because it's already performed by it