I have been scowering the internet and trying to find a way to structure and builda friend system using Flutter and Firebase. I have settled on the following structure, but am certainly open to new suggestions:

I have a collection containing all existing users. Where each document is the users uid. Furthermore each document again has a few collections containging the friend data. I keep track of which users have sent the user in question a friendrequest, and which friend requests have been sent out by the user in question. Last but not least ofcourse a list of users which are actually his friends. Initial sctructure

All 3 of these sub collection simply hold more uid's, since I dont want to store a copy of the actual user data here. sub collection structure. This is because when a user updates his personal information I have to also update all of the information which belong to all the friends, resulting in a huge number of reads and writes. So with these uid's I want to backtrack to the initial user collection to find his/her information and display it

So my idea was to have a StreamBuilder which has a snapshot of all the friends of the current user. These snapshots can then be used to track back to the user collection and fetch that user's data. However I have many doubts on this structure since it isnt very asynchronous and is giving me errors. Because the index of the Listview is continuing onward while the data isnt loaded yet.

And I want them added to a list so I can manage the state of the isSelected variable and the ProfilePicture. Also if there is a better way of doing this please enlighten me!

I know it is quite the long question, but could somebody please help me out on this one :)

return StreamBuilder<QuerySnapshot>(
    stream: FirebaseFirestore.instance
        .collection('users')
        .doc(FirebaseAuth.instance.currentUser?.uid)
        .collection('friends')
        .snapshots(),
    builder:
        (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshots) {
      if (snapshots.hasError) {
        return const Text("Er is iets fout gegaan!");
      }
      if (snapshots.connectionState == ConnectionState.waiting) {
        return const Center(
          child: CircularProgressIndicator(),
        );
      }
      if (snapshots.data!.docs.isEmpty) {
        return Column(children: const [
          Icon(
            Icons.info,
            color: Colors.grey,
            size: 50,
          ),
          Text(
            "Voeg eerst vrienden toe!",
            style: TextStyle(color: Colors.grey, fontSize: 26),
          )
        ]);
      }

      return Expanded(
          child: ListView.builder(
              itemCount: snapshots.data!.docs.length,
              itemBuilder: (context, index) {
                return FutureBuilder<DocumentSnapshot>(
                  future: FirebaseFirestore.instance
                      .collection("users")
                      .doc(snapshots.data!.docs[index].id)
                      .get(),
                  builder: (context, snapshot) {
                    if (snapshot.connectionState == ConnectionState.done) {
                      var data =
                          snapshot.data!.data() as Map<String, dynamic>;
                      allReceiptDebtors.add(ReceiptDebtor(
                          snapshots.data!.docs[index].id,
                          data['email'],
                          data['username'],
                          ShowProfilePicture()
                              .show(data['image'], data['username']),
                          false,
                          false));
                      print(index);
                      print(allReceiptDebtors);

                      return ListTile(
                        title: Text(
                          allReceiptDebtors[index].username,
                          maxLines: 1,
                          overflow: TextOverflow.ellipsis,
                          style: const TextStyle(
                              color: Colors.black54,
                              fontSize: 16,
                              fontWeight: FontWeight.bold),
                        ),
                        subtitle: Text(
                          allReceiptDebtors[index].email,
                          overflow: TextOverflow.ellipsis,
                        ),
                        leading: Container(
                          width: 40,
                          height: 40,
                          alignment: Alignment.center,
                          child: allReceiptDebtors[index].profilePicture,
                        ),
                        trailing: Visibility(
                          maintainSize: true,
                          maintainAnimation: true,
                          maintainState: true,
                          visible: allReceiptDebtors[index].isSelected,
                          child: const Icon(
                            Icons.check_rounded,
                            color: SplitlyColors.gold,
                          ),
                        ),
                        onTap: () {
                          setState(() {
                            if (!allReceiptDebtors[index].isSelected) {
                              allReceiptDebtors[index].isSelected = true;
                            } else {
                              allReceiptDebtors[index].isSelected = false;
                            }
                          });
                        },
                      );
                    }

                    return Container();
                  },
                );
              }));
    });

class ReceiptDebtor {
  final String docId;
  final String email, username;
  final Widget? profilePicture;
  List items = [];
  bool isSelected;
  bool isExpanded;

  ReceiptDebtor(this.docId, this.email, this.username, this.profilePicture,
      this.isSelected, this.isExpanded);
}