Home > Mobile >  How to build a "Recent files" list?
How to build a "Recent files" list?

Time:01-10

I'm struggling to find a solution to build a widget that displays "Recent Files".

To find the files I have the following

Future<List<File>> findFiles(String prefix) async {
    List<File> files = [];
    await for (var entity
        in directory.list(recursive: true, followLinks: false)) {
      File file = File(entity.path);
      if (p.extension(file.path) == ".json") {
        print("Found in:"   entity.path);
        if (p.basename(file.path).startsWith(prefix)) files.add(file);
      }
    }

    return files;
  }

Then I call it using var files = await FileManager().findFiles("test");

But I am not sure how to build a list view to display the name of each file as it is a Future and needs awaiting.

Any suggestions?

CodePudding user response:

To display the result of your function in a ListView, since your function returns a Future, you should use a FutureBuilder:

FutureBuilder(
      future: findFiles("bla"),
      builder: (BuildContext context, AsyncSnapshot<List<File>> snapshot) {
        if (snapshot.hasData) {
          return ListView.builder(
            itemCount: snapshot.data?.length,
            itemBuilder: (BuildContext context, int index) {
              return Text(snapshot.data?[index].path);
            },
          );
        } else if (snapshot.hasError) {
          return Text("Error: ${snapshot.error}");
        }
        return CircularProgressIndicator();
      },
    )

Here is a YouTube video by the Flutter team explaining FutureBuilder

CodePudding user response:

Here's an example of how you might display a list of strings returned by a Future in a Flutter app using a ListView:

import 'package:flutter/material.dart';

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  Future<List<String>> _futureStringList;

  @override
  void initState() {
    super.initState();
    _futureStringList = findFiles("...");
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: FutureBuilder<List<String>>(
          future: _futureStringList,
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              return ListView.builder(
                itemCount: snapshot.data.length,
                itemBuilder: (context, index) {
                  return ListTile(
                    title: Text(snapshot.data[index]),
                  );
                },
              );
            } else if (snapshot.hasError) {
              return Text("${snapshot.error}");
            }

            // By default, show a loading spinner
            return CircularProgressIndicator();
          },
        ),
      ),
    );
  }

  Future<List<File>> findFiles(String prefix) async {
    // Replace this with your actual code to fetch the string list
    await Future.delayed(Duration(seconds: 2));
    return ['String 1', 'String 2', 'String 3'];
  }
}

In this example, We use a FutureBuilder widget to build the UI based on the state of the Future. The builder callback is called whenever the Future completes or updates, and we use the snapshot to determine the state of the Future and decide what to display.

If the Future has completed successfully, the ListView builder is used to display the list of strings. Each item in the list is represented by a ListTile widget, with the title set to the corresponding string. If the Future has failed, an error message is displayed. If the Future is still pending, a loading spinner is displayed.

The findFiles function is called in the initState method, which is a lifecycle method that is called when the widget is first created. This is done so that the data is fetched as soon as the widget is initialized, which allows the UI to be built and displayed with the data as soon as possible

Calling the findFiles function in initState also ensures that the data is fetched only once, when the widget is first created. If the data were fetched in the build method, it would be fetched again every time the widget is rebuilt, which would be unnecessary and could potentially lead to performance issues.

initState is called once, before build is called. It is a good place to perform one-time setup of your stateful widget, such as initializing variables, allocating resources and fetching data.

You can also use didChangeDependencies method, which is similar to initState , but it will call when some inherited variables change, it would be a good place to perform one-time setup that depend on the inherited widgets, such as fetching data.

  • Related