Flutter: Create list of directories with StreamBuilder

46 views Asked by At

I want to create a widget that lists all of the sub directories in a given directory. I have elected to use StreamBuilder to achieve this, here is my app:

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as path;

void main() {
  runApp(ArmyMakerApp());
}

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

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => ArmyMakerAppState(),
      child: MaterialApp(
        title: 'Army Maker',
        theme: ThemeData(
          useMaterial3: true,
          colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
        ),
        home: ArmiesPage(),
      ),
    );
  }
}

class ArmyMakerAppState extends ChangeNotifier {}

class ArmiesPage extends StatefulWidget {
  @override
  State<ArmiesPage> createState() => _ArmiesPageState();
}

class _ArmiesPageState extends State<ArmiesPage> {
  Stream<FileSystemEntity>? _repositories;

  List<FileSystemEntity> _repositoriesList = [];

  _ArmiesPageState() {
    getRepositoriesDirectory().then((repositoriesDirectory) => setState(() {
          _repositories = repositoriesDirectory.list(recursive: false);
        }));
  }

  @override
  Widget build(BuildContext context) {
    final Stream<FileSystemEntity>? repositories = _repositories;

    return StreamBuilder(
        stream: repositories,
        builder:
            (BuildContext context, AsyncSnapshot<FileSystemEntity> snapshot) {

          if (snapshot.hasData) {
            _repositoriesList.add(snapshot.data!);
          }

          return Scaffold(
            body: ListView.builder(
                itemCount: _repositoriesList.length,
                itemBuilder: (BuildContext context, int index) {
                  return ListTile(title: Text(_repositoriesList[index].path));
                }),
          );
        });
  }
}

Future<Directory> getDocumentsDirectory() async {
  final rootDocumentsDirectory = await getApplicationDocumentsDirectory();

  final documentsDirectory =
      Directory(path.join(rootDocumentsDirectory.path, "army_maker"));

  return documentsDirectory;
}

Future<Directory> getRepositoriesDirectory() async {
  final directory = await getDocumentsDirectory();

  return Directory(path.join(directory.path, 'repositories'));
}

In theory, repositoriesList should be extended to contain all the files in ~/Documents/army_maker/repositories. But not only does this not happen but the behavior of my widget appears to be completely arbitrary. For testing purposes I have created a single subdirectory ~/Documents/army_maker/repositories/foo. Now when, when I start my app, _ArmiesPageState.build is called four times in total, two of which add foo to _repositoriesList. I would expect build to only be called once. Why is this happening and how can I fix it?

0

There are 0 answers