Search code examples
flutterdartsqfliteflutter-listview

How to get the index value whilst not getting duplicates within ListView.builder?


I'm trying to show the week's budget spending & timeline only when the user has put in the spending information.

One spending each week

This is the expected result and all seems to be working nicely until I add in more than just one spending in each week.

Here's what happens:

More than one spending a week

The problem that I understand is that the ListView.builder gets the date that is between "Initial" and "End" and builds the widgets. So because there's 2 spending between those dates, then it builds 2 of those widgets. The problem is I just can't seem to figure out a way to show them without duplication.

Here's my code:

Widget build(BuildContext context) {
    return ListView.builder(
      shrinkWrap: true,
      controller: ScrollController(),
      itemCount: snapshot.data!.length,
      padding: const EdgeInsets.only(bottom: 8),
      itemBuilder: (context, index) {
        final spending = snapshot.data![index];

        DateTime spendingDate = DateTime.parse(spending.date);
        var initial =
            DateTime(initialDate.year, initialDate.month, initialDate.day - 1);
        var end = DateTime(endDate.year, endDate.month, endDate.day + 1);

        return spendingDate.isAfter(initial) && spendingDate.isBefore(end)
            ? Column(
                children: [
                  WeekDivider(label: label, dateEstimation: dateEstimation),
                  WeeklySpendingStream(
                    color: color,
                    snapshot: snapshot,
                    initialDate: initialDate,
                    endDate: endDate,
                  ),
                ],
              )
            : const SizedBox();
      },
    );
  }

WeeklySpendingStreamCode:

Widget build(BuildContext context) {
    return ListView.builder(
      shrinkWrap: true,
      controller: ScrollController(),
      itemCount: snapshot.data!.length,
      padding: const EdgeInsets.only(bottom: 8),
      itemBuilder: (context, index) {
        final spending = snapshot.data![index];

        DateTime spendingDate = DateTime.parse(spending.date);
        var initial =
            DateTime(initialDate.year, initialDate.month, initialDate.day - 1);
        var end = DateTime(endDate.year, endDate.month, endDate.day + 1);

        if (spendingDate.isAfter(initial) && spendingDate.isBefore(end)) {
          return SwipeActionCell(
            editModeOffset: 0,
            fullSwipeFactor: 0.50,
            key: ObjectKey(snapshot.data![index]),
            trailingActions: [
              SwipeAction(
                performsFirstActionWithFullSwipe: true,
                color: Colors.transparent,
                content: Container(
                    decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(30),
                      color: Colors.red,
                    ),
                    child: getIconButton(Colors.red, IconlyBold.delete)),
                onTap: (handler) async {
                  handler(true);
                  await Future.delayed(const Duration(milliseconds: 100));
                  snapshot.data!.removeAt(index);
                  SpendingDatabaseHelper.instance.removeMethod(spending.id!);
                },
              ),
            ],
            child: SpendingCard(
              beneficiary: spending.beneficiary,
              budgetSpent: currency.format(int.parse(spending.budgetSpent)),
              date: DateFormat("dd-MM-yyyy")
                  .format(DateTime.parse(spending.date)),
              colorValue: color,
            ),
          );
        } else {
          return const SizedBox();
        }
      },
    );
  }

The output of snapshot.data:

[
{id: 8, budgetName: 🍣 Food & Beverage, beneficiary: ddd, budgetSpent: 1, date: 2022-02-21}, 
{id: 7, budgetName: 🍣 Food & Beverage, beneficiary: dfgvsd, budgetSpent: 1, date: 2022-02-14}, 
{id: 4, budgetName: 🍣 Food & Beverage, beneficiary: ddd, budgetSpent: 1, date: 2022-02-11}, 
{id: 10, budgetName: 🍣 Food & Beverage, beneficiary: ddd, budgetSpent: 1, date: 2022-02-11}, 
{id: 5, budgetName: 🍣 Food & Beverage, beneficiary: asxasd, budgetSpent: 1, date: 2022-02-06}
]

Would really appreciate any suggestions/ideas of how this can be resolved. Thanks in advance!


Solution

  • Nevermind, I somehow found the solution by getting the data using ".where" and checking whether it is empty or not. It worked nicely.

    var initial = DateTime(initialDate.year, initialDate.month, initialDate.day - 1);
        var end = DateTime(endDate.year, endDate.month, endDate.day + 1);
    
        final spending = snapshot.data!.where((s) =>
            DateTime.parse(s.date).isAfter(initial) &&
            DateTime.parse(s.date).isBefore(end));
    
        return spending.isNotEmpty ||
                DateTime.now().isAfter(initial) && DateTime.now().isBefore(end)
            ? spending.isEmpty
                ? Column(
                    children: [
                      WeekDivider(label: label, dateEstimation: dateEstimation),
                      const Padding(
                        padding: EdgeInsets.only(top: 8, bottom: 16),
                        child: Text(
                          'No spending this week',
                          style: kCaption,
                        ),
                      ),
                    ],
                  )
                : ListView(
                    shrinkWrap: true,
                    controller: ScrollController(),
                    padding: const EdgeInsets.only(bottom: 8),
                    children: [
                      Column(
                        children: [
                          WeekDivider(label: label, dateEstimation: dateEstimation),
                          WeeklySpendingStream(
                            color: color,
                            snapshot: snapshot,
                            initialDate: initialDate,
                            endDate: endDate,
                          ),
                        ],
                      )
                    ],
                  )
            : const SizedBox();
      }