As we can have multiple recipes in our app, in order to deal with the files in our app we need two screens: one that shows the list of all the available files, and one that reads the content of a single file.
Let’s start with the screen containing the list of files: this is how the UI will look like when it’s complete. This shows all the files that were saved, and some information about the files themselves, based on the settings. When you click on one of the files, you can read the text content within the file.
OK, back to our project, let’s create a new file in the lib folder, and call it file_list_screen.dart.
First, let’s import material.dart. Next, let’s create a stateful widget with the stful shortcut, and call this FileListScreen.
In the settings that we have saved previously there is some information about how this screen should look: in particular, we need to retrieve the name of the list of recipes, and whether we should show the file size and the date of the file.
Let’s create the state variables that we need to store this data: a string for the listname, that will be empty at first, then a boolean that we can call showSize, and we can set to false at first, and another boolean for the showDate value, that we’ll also set to false.
String _listName = '';
bool _showSize = false;
bool _showDate = false;
Just ignore the linter warnings: we’ll fix everything in a moment.
Now let’s create a method, that we can call getSettings: here we can choose whether we want to use SharedPreferences or Flutter Secure Storage. For this kind of data, that really contains nothing sensitive, I would probably choose SharedPreferences.
This will be asynchronous anyway, as getting the instance is async. So it returns a Future, of void, we can call it getSettings, and mark it async.
Inside the method, let’s retrieve the SPHelper class instance: it’s a final, prefs, that will await SPHelper getInstance.
final prefs = await SPHelper.getInstance();
Once we have our instance, let’s set our state variables calling the getter methods: for the listName, we can call prefs.getList name. For the _showSize boolean, we can call prefs.getShowFileSize, and for the _showDate field, let’s call getShowDate.
Once our variables are set, let’s call the setState method to update the UI of the screen.
_listName = prefs.getListName();
_showSize = prefs.getShowFileSize();
_showDate = prefs.getShowDate();
setState(() {});
Now let’s override the initState method, so that we can call this new method.
@override
void initState() {
super.initState();
getSettings();
}
There’s one more method we need to write: the method that retrieves the list of files we want to show on the screen. This will return a Future, containing a List of FileSystemEntity objects.
A FileSystemEntity is an abstract class in Dart’s dart:io library. A FileSystemEntity can be a file, a directory, or a link (You also have the File, Directory and Link classes of course, but a FileSystemEntity is the ancestor of all of them)
We can call this _getFiles, and mark it as async. In the method, first let’s declare a final directory, that awaits the getApplicationDocuments method (which as you might remember is taken form the pathprovider package).
Next, let’s return directory.listSync().whereType().toList();
The listSync() method, called on a directory object, lists all the content in a directory (and this includes files, subdirectories, and links). listSync() already returns a List objects.
WhereType filters out all the objects that are not of Files. So this leaves us with a list of files, Finally toList() converts the result into a list.
So basically the _getFiles method is gets a list of all the files in the app’s documents directory.
Future<List<FileSystemEntity>> _getFiles() async {
final directory = await getApplicationDocumentsDirectory();
return directory.listSync().whereType<File>().toList();
}
OK, let’s also call getFiles in the initState method.
Right, now that the plumbing is ready, let’s get to the design of our screen.