Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/budget #158

Merged
merged 11 commits into from
Mar 27, 2024
Merged
41 changes: 41 additions & 0 deletions lib/model/budget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,35 @@ class BudgetMethods extends SossoldiDatabase {
return item.copy(id: id);
}

Future<Budget> insertOrUpdate(Budget item) async {
final db = await database;

final exists = await checkIfExists(item);
if (exists) {
print("UPDATE ${item.toJson()}");
await db.rawQuery("UPDATE $budgetTable SET amountLimit = ${item.amountLimit} WHERE idCategory = ${item.idCategory}");
} else {
print("INSERT ${item.toJson()}");
await db.insert(budgetTable, item.toJson());
}

return item.copy(id: item.id);
}

Future<bool> checkIfExists(Budget item) async {
final db = await database;

try {
final exists = await db.rawQuery("SELECT * FROM ${budgetTable} WHERE ${item.idCategory} = idCategory");
if(exists.isNotEmpty) {
return true;
}
return false;
} catch (e) {
return false;
}
}

Future<Budget> selectById(int id) async {
final db = await database;

Expand Down Expand Up @@ -135,4 +164,16 @@ class BudgetMethods extends SossoldiDatabase {

return await db.delete(budgetTable, where: '${BudgetFields.id} = ?', whereArgs: [id]);
}

Future<int> deleteByCategory(int id) async {
final db = await database;

return await db.delete(budgetTable, where: '${BudgetFields.idCategory} = ?', whereArgs: [id]);
}

//PER TEST
Future<int> deleteAll() async {
final db = await database;
return await db.rawDelete("DELETE FROM $budgetTable");
}
K-w-e marked this conversation as resolved.
Show resolved Hide resolved
}
161 changes: 161 additions & 0 deletions lib/pages/planning_page/manage_budget_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:sossoldi/providers/budgets_provider.dart';
K-w-e marked this conversation as resolved.
Show resolved Hide resolved

import '../../constants/style.dart';
import '../../model/budget.dart';
import '../../model/category_transaction.dart';
import 'widget/budget_category_selector.dart';
import '../../../providers/categories_provider.dart';

class ManageBudgetPage extends ConsumerStatefulWidget {
final Function() onRefreshBudgets;
const ManageBudgetPage({required this.onRefreshBudgets, super.key});

@override
ConsumerState<ManageBudgetPage> createState() => _ManageBudgetPageState();
}

class _ManageBudgetPageState extends ConsumerState<ManageBudgetPage> {
List<CategoryTransaction> categories = [];
List<Budget> budgets = [];
List<Budget> deletedBudgets = [];

void _loadCategories() async {
categories = await ref.read(categoriesProvider.notifier).getCategories();
budgets = await ref.read(budgetsProvider.notifier).getBudgets();
setState(() {});
}

void updateBudget(Budget updatedBudget, int index) {
setState(() {
deletedBudgets.add(budgets[index]);
budgets[index] = updatedBudget;
});
}

void deleteBudget(Budget removedBudget, int index) {
setState(() {
budgets.removeAt(index);
deletedBudgets.add(removedBudget);
});
}

@override
void initState() {
_loadCategories();
super.initState();
}

@override
Widget build(BuildContext context) {
return Column(
children: [
Padding(
padding: const EdgeInsets.all(15),
child: Text("Select the categories to create your budget",
style: Theme.of(context).textTheme.titleLarge)),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 15),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Category',
textAlign: TextAlign.left,
),
Text(
'Amount',
textAlign: TextAlign.right,
),
],
)),
Expanded(
child: Column(children: [
ListView.builder(
theperu marked this conversation as resolved.
Show resolved Hide resolved
shrinkWrap: true,
itemCount: budgets.length,
itemBuilder: (context, index) {
return Dismissible(
key: Key(budgets[index].idCategory.toString()),
background: Container(
padding: const EdgeInsets.only(right: 20.0),
alignment: Alignment.centerRight,
color: Colors.red,
child: const Text(
'Delete',
textAlign: TextAlign.right,
style: TextStyle(color: Colors.white),
),
),
onDismissed: (direction) {
deleteBudget(budgets[index], index);
},
child: BudgetCategorySelector(
categories: categories,
budget: budgets[index],
initSelectedCategory: categories
.where((element) =>
element.id == budgets[index].idCategory)
.isEmpty
? categories[0]
: categories
.where((element) =>
element.id == budgets[index].idCategory)
.first,
onBudgetChanged: (updatedBudget) {
updateBudget(updatedBudget, index);
},
));
},
),
TextButton.icon(
icon: Icon(
Icons.add_circle,
color: Theme.of(context).colorScheme.secondary,
),
onPressed: () {
setState(() {
budgets.add(Budget(
active: true,
amountLimit: 100,
idCategory: categories[0].id!,
name: categories[0].name));
});
},
label: Text(
"Add category budget",
style: Theme.of(context)
.textTheme
.titleSmall!
.apply(color: Theme.of(context).colorScheme.secondary),
)),
])),
const SizedBox(height: 10),
Text(
"Your monthly budget will be: ${budgets.isEmpty ? 0 : budgets.fold(0, (sum, e) => sum + e.amountLimit.toInt())}€"),
const SizedBox(height: 10),
const Divider(height: 1, color: grey2),
Padding(
padding: const EdgeInsets.all(8),
child: SizedBox(
width: double.infinity,
child: ElevatedButton(
theperu marked this conversation as resolved.
Show resolved Hide resolved
onPressed: () async {
for (var item in deletedBudgets) {
await BudgetMethods().deleteByCategory(item.idCategory);
}
for (var item in budgets) {
await BudgetMethods().insertOrUpdate(item);
}
setState(() {
widget.onRefreshBudgets();
Navigator.of(context).pop();
});
},
child: const Text("Save budget"),
)))
],
);
}
}
51 changes: 41 additions & 10 deletions lib/pages/planning_page/planning_page.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import 'package:flutter/material.dart';
import 'package:sossoldi/model/budget.dart';
K-w-e marked this conversation as resolved.
Show resolved Hide resolved
import 'manage_budget_page.dart';
import 'widget/budget_card.dart';
import 'widget/recurring_payments_card.dart';

Expand All @@ -10,32 +12,61 @@ class PlanningPage extends StatefulWidget {
}

class _PlanningPageState extends State<PlanningPage> {
GlobalKey<_PlanningPageState> _key = GlobalKey<_PlanningPageState>();

void _forceRefresh() {
setState(() {
final key = GlobalKey<_PlanningPageState>();
_key.currentState?.dispose();
_key.currentState?.reassemble();

_key.currentState?._key = key;
});
}

@override
Widget build(BuildContext context) {
return Container(
key: _key,
color: Colors.white,
padding: const EdgeInsetsDirectional.symmetric(horizontal: 10),
child: ListView(
padding: const EdgeInsets.fromLTRB(16, 16, 16, 45),
children: [
Row(
children: [
Text("Monthly budget",
style: Theme.of(context).textTheme.titleLarge),
const Spacer(),
GestureDetector(
onTap: () {
print("Manage budgets");
},
onTap: () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20.0),
topRight: Radius.circular(20.0),
),
),
elevation: 10,
builder: (BuildContext context) {
return FractionallySizedBox(
heightFactor: 0.9,
child: ManageBudgetPage(
onRefreshBudgets: _forceRefresh));
},
);
},
child: Row(children: [
Text("MANAGE",
style: Theme.of(context).textTheme.labelLarge),
SizedBox(width: 5),
Icon(Icons.edit, size: 13)
]))
Text("MANAGE",
style: Theme.of(context).textTheme.labelLarge),
const SizedBox(width: 5),
const Icon(Icons.edit, size: 13)
]))
],
),
const SizedBox(height: 10),
BudgetCard(),
BudgetCard(_forceRefresh),
const SizedBox(height: 20),
Text("Recurring payments",
style: Theme.of(context).textTheme.titleLarge),
Expand Down
Loading
Loading