'How to insert a pull to refresh along with web query?

I'm having a really hard time inserting a user option pull down and update a FutureBuilder in my app in Flutter. I researched and tried in many ways to make the app perform the query as soon as the screen opens and also that when pulling down, the app updates the list, requesting the information again from the server. I wanted you to help me with this, and maybe, it could be someone's doubt later on. I'll put my code below, currently, the code performs the query only when opening the page.

import 'dart:convert';
import 'package:conditioned/conditioned.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:onpay/navigationDrawer/navigationDrawer.dart';
import 'package:http/http.dart' as http;
import 'package:onpay/ui/theme/colors.dart';
import 'package:onpay/utilities/API.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:onpay/utilities/User.dart';

class Historic extends StatefulWidget {
  @override
  _HistoricState createState() => _HistoricState();
}

class _HistoricState extends State<Historic> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        iconTheme: IconThemeData(color: kPrimaryColor),
        title: const Text(
          'fragments.historic.title',
          style: TextStyle(color: kPrimaryColor),
        ).tr(),
        backgroundColor: Colors.white,
        elevation: 0,
      ),
      drawer: NavigationDrawer(menu: "historic"),
      body: HistoryContent(),
    );
  }
}

class HistoryContent extends StatelessWidget {
  static Future<List<HistoryRequest>> fetchHistory(http.Client client) async {
    final response = await client.get(
      Uri.parse(
        baseUrl + 'user/history.php?mail=$userMail',
      ),
    );
    return compute(parseHistory, response.body);
  }

  static List<HistoryRequest> parseHistory(String responseBody) {
    final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();

    return parsed
        .map<HistoryRequest>((json) => HistoryRequest.fromJson(json))
        .toList();
  }

  const HistoryContent({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: FutureBuilder<List<HistoryRequest>>(
        future: fetchHistory(http.Client()),
        builder: (context, snapshot) {
          if (snapshot.hasError) {
            return Center(
              child: Text(snapshot.error.toString()),
            );
          } else if (snapshot.hasData) {
            return HistoryList(history: snapshot.data!);
          } else {
            return Container(
              decoration: new BoxDecoration(color: Colors.white),
              child: Center(
                child: CircularProgressIndicator(),
              ),
            );
          }
        },
      ),
    );
  }
}

class HistoryList extends StatelessWidget {
  const HistoryList({Key? key, required this.history}) : super(key: key);

  final List<HistoryRequest> history;

  @override
  Widget build(BuildContext context) {
    Size size = MediaQuery.of(context).size;
    return Scaffold(
      backgroundColor: Colors.white,
      body: Container(
        decoration: new BoxDecoration(color: Colors.white),
        child: ListView.builder(
          shrinkWrap: true,
          itemCount: history.length,
          itemBuilder: (context, index) {
            return Stack(
              children: [
                Padding(
                  padding: EdgeInsets.fromLTRB(40.0, 30.0, 40.0, 30.0),
                  child: Row(
                    children: [
                      SizedBox(width: size.width * 0.15),
                      SizedBox(
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Conditioned(
                              cases: [
                                Case(
                                  history[index].type == "0",
                                  builder: () =>
                                      Text('fragments.historic.entered_the_app')
                                          .tr(namedArgs: {'appname': appName}),
                                ),
                                Case(
                                  history[index].type == "1",
                                  builder: () =>
                                      Text('fragments.historic.login').tr(),
                                ),
                                Case(
                                  history[index].type == "2",
                                  builder: () => Text(
                                          'fragments.historic.password_recovered')
                                      .tr(),
                                ),
                                Case(
                                  history[index].type == "3",
                                  builder: () => Text(
                                          'fragments.historic.activate_account')
                                      .tr(),
                                ),
                                Case(
                                  history[index].type == "4",
                                  builder: () =>
                                      Text('fragments.historic.deposit').tr(),
                                ),
                                Case(
                                  history[index].type == "5",
                                  builder: () =>
                                      Text('fragments.historic.withdrawal')
                                          .tr(),
                                ),
                                Case(
                                  history[index].type == "6",
                                  builder: () =>
                                      Text('fragments.historic.new_wallet')
                                          .tr(),
                                ),
                              ],
                              defaultBuilder: () =>
                                  Text('fragments.historic.unknown_event').tr(),
                            ),
                            Text(
                              history[index].device.toString(),
                              style:
                                  TextStyle(color: Colors.grey, fontSize: 12),
                            ),
                            Text(
                              history[index].createdAt.toString(),
                              style:
                                  TextStyle(color: Colors.grey, fontSize: 12),
                            ),
                            Conditioned(
                              cases: [
                                Case(
                                  history[index].ip!.isNotEmpty,
                                  builder: () => Text(
                                    'IP: ' + history[index].ip.toString(),
                                    style: TextStyle(
                                        color: Colors.grey, fontSize: 12),
                                  ),
                                ),
                              ],
                              defaultBuilder: () => Text(""),
                            ),
                          ],
                        ),
                        width: size.width * 0.6,
                      ),
                    ],
                  ),
                ),
                Positioned(
                  left: 50,
                  child: new Container(
                    height: size.height * 0.7,
                    width: 1.0,
                    color: Colors.grey.shade400,
                  ),
                ),
                Positioned(
                  bottom: 12,
                  child: Padding(
                    padding: const EdgeInsets.all(25.0),
                    child: Conditioned(
                      cases: [
                        Case(
                          history[index].type == "0",
                          builder: () => Container(
                            child: Icon(
                              Icons.star_rate_rounded,
                              color: Colors.white,
                            ),
                            height: 48.0,
                            width: 48.0,
                            decoration: new BoxDecoration(
                              color: Colors.green,
                              borderRadius: BorderRadius.circular(50),
                            ),
                          ),
                        ),
                        Case(
                          history[index].type == "1",
                          builder: () => Container(
                            child: Icon(
                              Icons.login_outlined,
                              color: Colors.white,
                            ),
                            height: 48.0,
                            width: 48.0,
                            decoration: new BoxDecoration(
                              color: Colors.grey,
                              borderRadius: BorderRadius.circular(50),
                            ),
                          ),
                        ),
                        Case(
                          history[index].type == "2",
                          builder: () => Container(
                            child: Icon(
                              Icons.password_outlined,
                              color: Colors.white,
                            ),
                            height: 48.0,
                            width: 48.0,
                            decoration: new BoxDecoration(
                              color: Colors.blue,
                              borderRadius: BorderRadius.circular(50),
                            ),
                          ),
                        ),
                        Case(
                          history[index].type == "3",
                          builder: () => Container(
                            child: Icon(
                              Icons.verified_outlined,
                              color: Colors.white,
                            ),
                            height: 48.0,
                            width: 48.0,
                            decoration: new BoxDecoration(
                              color: Colors.teal,
                              borderRadius: BorderRadius.circular(50),
                            ),
                          ),
                        ),
                        Case(
                          history[index].type == "4",
                          builder: () => Container(
                            child: Icon(
                              Icons.payments_outlined,
                              color: Colors.white,
                            ),
                            height: 48.0,
                            width: 48.0,
                            decoration: new BoxDecoration(
                              color: Colors.cyan,
                              borderRadius: BorderRadius.circular(50),
                            ),
                          ),
                        ),
                        Case(
                          history[index].type == "5",
                          builder: () => Container(
                            child: Icon(
                              Icons.payments_outlined,
                              color: Colors.white,
                            ),
                            height: 48.0,
                            width: 48.0,
                            decoration: new BoxDecoration(
                              color: Colors.redAccent,
                              borderRadius: BorderRadius.circular(50),
                            ),
                          ),
                        ),
                        Case(
                          history[index].type == "6",
                          builder: () => Container(
                            child: Icon(
                              Icons.account_balance_wallet_outlined,
                              color: Colors.white,
                            ),
                            height: 48.0,
                            width: 48.0,
                            decoration: new BoxDecoration(
                              color: Colors.amber,
                              borderRadius: BorderRadius.circular(50),
                            ),
                          ),
                        ),
                      ],
                      defaultBuilder: () => Container(
                        child: Icon(
                          Icons.help_outline_outlined,
                          color: Colors.white,
                        ),
                        height: 48.0,
                        width: 48.0,
                        decoration: new BoxDecoration(
                          color: Colors.grey,
                          borderRadius: BorderRadius.circular(50),
                        ),
                      ),
                    ),
                  ),
                ),
              ],
            );
          },
        ),
      ),
    );
  }
}

class HistoryRequest {
  final bool success;
  final String title, message;

  final String? type, device, ip, createdAt, updatedAt;

  const HistoryRequest(
      {required this.success,
      required this.title,
      required this.message,
      this.type,
      this.device,
      this.ip,
      this.createdAt,
      this.updatedAt});

  factory HistoryRequest.fromJson(Map<String, dynamic> json) {
    return HistoryRequest(
      success: json['success'],
      title: json['title'],
      message: json['message'],
      createdAt: json['created_at'],
      updatedAt: json['updated_at'],
      type: json['type'],
      device: json['device'],
      ip: json['ip'],
    );
  }
}

How could I insert a pull to refresh in this scenario? I appreciate the immense help.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source