Search code examples
flutterdartflutter-providersqfliteflutter-listview

Flutter - How to get the value of a provider call function that requires 'await' within a variable?


I'm trying to make a budget app where each budget has its own spending history. Each of those spending histories would have a variable called 'budgetName' which I can compile and total the amount of spending by using sqflite code as below.

return await db.rawQuery("select sum(budgetSpent) as total from spending where budgetName ='" + budgetTitle + "'");

and this works if I try to use a .then((value) {print(value);}) when calling the sqflite function and see the value of each budget's spendings in the debug console.

But the problem is that I need the 'budgetTitle' when calling the function so it can compare with the spending's 'budgetName' to get the total spending amount.

So what I have right now is I try to get the spending amount like below:

child: BudgetCard(
  budgetName: budget.budgetName,
  budgetSpent: '${Provider.of<SpendingDatabaseHelper>(context, listen: false).getSpecificSpending(budget.budgetName}',
  maxBudget: currency.format(int.parse(budget.maxBudget)),
  svgIcon: iconListBudgetCards[budget.iconValue],
  color: colorSwatch[budget.colorValue],
  percentage: 0.5),
),

But it only returns Instance of 'Future<dynamic>' because it needs the 'await' before getting the value. But I couldn't find another way of doing this because it needs the 'budgetTitle' to be passed on.

Any help, ideas, or suggestions are highly appreciated! thank you in advance.

Here is the database code:

String? budgetSpendingAmount;

getSpecificSpending(budgetTitle) async {
    dynamic result =
        await SpendingDatabaseHelper.instance.getSpendingAmount(budgetTitle);
    String a = result.toString();
    debugPrint('A: $a');
    if (a == '[{total: null}]') {
      a = currency.format(int.parse('000'.trim()));
      budgetSpendingAmount = a;
      print(budgetSpendingAmount);
    } else {
      String? b = a.replaceAll(RegExp(r'[{\}\[\]\-]+'), '');
      String c = b.substring(b.indexOf(":") + 1);
      budgetSpendingAmount = currency.format(int.parse(c.trim()));
    }
    notifyListeners();
  }

  Future getSpendingAmount(String budgetTitle) async {
    Database db = await instance.database;
    return await db.rawQuery("select sum(budgetSpent) as total from spending where ='" + budgetTitle + "'");
  }

Here is the full code of where I call the function to get the spending amount data:

Widget build(BuildContext context) {
    return FutureBuilder<List<Budget>>(
      future: Provider.of<BudgetDatabaseHelper>(context).getBudgets(),

      /// Displaying the data from the list
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return const Center();
        }
        return snapshot.data!.isEmpty
            ? const Flexible(
                child: Center(
                    child: Padding(
                padding: EdgeInsets.only(bottom: 80.0),
                child: Text(
                  'You don\'t have any budget',
                  style: kCaption,
                ),
              )))
            : Flexible(
                child: ListView.builder(
                  physics: const BouncingScrollPhysics(),
                  itemCount: snapshot.data!.length,
                  itemBuilder: (context, index) {
                    final budget = snapshot.data![index];
                    return Dismissible(
                      key: UniqueKey(),
                      background: const Align(
                        alignment: Alignment.centerRight,
                        child: Padding(
                          padding: EdgeInsets.only(bottom: 12.0, right: 24),
                          child: Icon(
                            IconlyLight.delete,
                            color: cRed,
                            size: 24,
                          ),
                        ),
                      ),
                      direction: DismissDirection.endToStart,
                      onDismissed: (direction) {
                        snapshot.data!.removeAt(index);
                        Provider.of<BudgetDatabaseHelper>(context,
                                listen: false)
                            .removeMethod(budget.id!, budget.budgetName);
                      },
                      child: GestureDetector(
                        onTap: () => showModalBottomSheet(
                          backgroundColor: Colors.transparent,
                          context: context,
                          enableDrag: true,
                          isScrollControlled: true,
                          builder: (context) {
                            return DraggableScrollableSheet(
                              snap: true,
                              minChildSize: 0.43,
                              maxChildSize: 0.85,
                              initialChildSize: 0.43,
                              snapSizes: const [0.43, 0.85],
                              builder: (context, scrollController) {
                                return ClipRRect(
                                  borderRadius: const BorderRadius.only(
                                      topLeft: Radius.circular(32),
                                      topRight: Radius.circular(32)),
                                  child: Container(
                                    color: cWhite,
                                    child: SingleChildScrollView(
                                      controller: scrollController,
                                      physics: const BouncingScrollPhysics(),
                                      child: BudgetDetails(
                                        id: budget.id!,
                                        budgetName: budget.budgetName,
                                        budgetSpent: 'budgetSpent',
                                        colorValue:
                                            colorSwatch[budget.colorValue],
                                        maxBudget: currency.format(
                                            int.parse(budget.maxBudget)),
                                        svgIcon: iconListBudgetDetails[
                                            budget.iconValue],
                                      ),
                                    ),
                                  ),
                                );
                              },
                            );
                          },
                        ),
                        child: BudgetCard(
                            budgetName: budget.budgetName,
                            budgetSpent: '${Provider.of<SpendingDatabaseHelper>(context, listen: false).getSpecificSpending(budget.budgetName}',
                            maxBudget: currency.format(int.parse(budget.maxBudget)),
                            svgIcon: iconListBudgetCards[budget.iconValue],
                            color: colorSwatch[budget.colorValue],
                            percentage: 0.5),
                      ),
                    );
                  },
                ),
              );
      },
    );
  }

Solution

  • Use provider in a widget tree is not a good idea. Make a statefullWidget

    Make a getter in your SpendingDatabaseHelper like this

    String? _budgetSpendingAmount;
    
    String get budgetSpendingAmount=> _budgetSpendingAmount;
    

    and initialize it like this _budgetSpendingAmount = currency.format(int.parse(c.trim()));

    So using this getter you can access this value anywhere in widget tree

    Future<void> _getSpecificSpending(String budgetName)async{
    
    try{
        await Provider.of<SpendingDatabaseHelper>(context, listen: false).getSpecificSpending(budgetName);
    } catch(e){
         print('error :$e');
    }
    
    
    }
    

    and in your widget tree write something like this

    child:  FutureBuilder(
              future : _getSpecificSpending(budget.budgetName)
              builder: (ctx,snapshot){
          
    var spendDataProv=Provider.of<SpendingDatabaseHelper>(context, listen: false);
                 
    return snapshot.connectionState==ConnectionState.waiting ?
                     CircularProgressIndicator() :
             BudgetCard(
                            budgetName: budget.budgetName,
                            budgetSpent:spendDataProv.budgetSpendingAmount ,
                            maxBudget: currency.format(int.parse(budget.maxBudget)),
                            svgIcon: iconListBudgetCards[budget.iconValue],
                            color: colorSwatch[budget.colorValue],
                            percentage: 0.5)
              },
        )