Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 3 additions & 29 deletions lib/pages/planning/manage_budget_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../model/budget.dart';
import '../../model/category_transaction.dart';
import '../../providers/currency_provider.dart';
import '../../services/database/repositories/budget_repository.dart';
import '../../ui/device.dart';
import '../../ui/extensions.dart';
import '../../ui/snack_bars/snack_bar.dart';
Expand Down Expand Up @@ -59,22 +58,6 @@ class _ManageBudgetPageState extends ConsumerState<ManageBudgetPage> {
});
}

Future<void> updateBudget(Budget updatedBudget, int index) async {
setState(() {
deletedBudgets.add(budgets[index]);
budgets[index] = updatedBudget;
});
await ref.read(budgetsProvider.notifier).refreshBudgets();
}

Future<void> deleteBudget(Budget removedBudget, int index) async {
setState(() {
budgets.removeAt(index);
deletedBudgets.add(removedBudget);
});
await ref.read(budgetsProvider.notifier).refreshBudgets();
}

void handleEmptyCategories() {
showSnackBar(
context,
Expand Down Expand Up @@ -156,18 +139,9 @@ class _ManageBudgetPageState extends ConsumerState<ManageBudgetPage> {
width: double.infinity,
child: ElevatedButton(
onPressed: () async {
for (var item in deletedBudgets) {
await ref
.read(budgetRepositoryProvider)
.deleteByCategory(item.idCategory);
}
for (var item in budgets) {
await ref
.read(budgetRepositoryProvider)
.insertOrUpdate(item);
}

await ref.read(budgetsProvider.notifier).refreshBudgets();
await ref
.read(budgetsProvider.notifier)
.saveBudget(budgets, deletedBudgets);

if (context.mounted) {
Navigator.of(context).pop();
Expand Down
1 change: 1 addition & 0 deletions lib/pages/planning/widget/edit_recurring_transaction.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../../../constants/style.dart';
import '../../../providers/categories_provider.dart';
import '../../../providers/recurring_transactions_provider.dart';
import '../../../providers/transactions_provider.dart';
import '../../../ui/device.dart';
import '../../../ui/extensions.dart';
Expand Down
399 changes: 141 additions & 258 deletions lib/pages/planning/widget/older_recurring_payments.dart

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions lib/pages/planning/widget/recurring_payments_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../../../constants/style.dart';
import '../../../providers/recurring_transactions_provider.dart';
import 'recurring_payment_card.dart';
import '../../../model/recurring_transaction.dart';
import '../../../providers/categories_provider.dart';
Expand All @@ -18,10 +19,10 @@ class RecurringPaymentSection extends ConsumerWidget {

void addRecurringPayment() {
ref.read(selectedRecurringPayProvider.notifier).setValue(true);
ref.read(selectedBankAccountProvider.notifier).setAccount(null);
ref.read(selectedCategoryProvider.notifier).setCategory(null);
ref.read(intervalProvider.notifier).setValue(Recurrence.monthly);
ref.read(endDateProvider.notifier).setDate(null);
ref.invalidate(selectedBankAccountProvider);
ref.invalidate(selectedCategoryProvider);
ref.invalidate(endDateProvider);
Navigator.of(context).pushNamed(
"/add-page",
arguments: {'recurrencyEditingPermitted': false},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import '../../../constants/style.dart';
import '../../../model/transaction.dart';
import '../../../providers/accounts_provider.dart';
import '../../../providers/categories_provider.dart';
import '../../../providers/recurring_transactions_provider.dart';
import '../../../providers/transactions_provider.dart';
import '../../../ui/device.dart';
import '../../../ui/extensions.dart';
Expand Down
18 changes: 16 additions & 2 deletions lib/providers/budgets_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,21 @@ class Budgets extends _$Budgets {
});
}

Future<void> refreshBudgets() async {
ref.invalidateSelf();
Future<void> saveBudget(
List<Budget> updatedBudgets,
List<Budget> deletedBudgets,
) async {
state = const AsyncLoading();
state = await AsyncValue.guard(() async {
for (var item in deletedBudgets) {
await ref
.read(budgetRepositoryProvider)
.deleteByCategory(item.idCategory);
}
for (var item in updatedBudgets) {
await ref.read(budgetRepositoryProvider).insertOrUpdate(item);
}
return _getBudgets();
});
}
}
189 changes: 189 additions & 0 deletions lib/providers/recurring_transactions_provider.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import 'package:intl/intl.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

import '../model/recurring_transaction.dart';
import '../model/transaction.dart';
import '../services/database/repositories/recurring_transactions_repository.dart';
import '../services/database/repositories/transactions_repository.dart';
import 'accounts_provider.dart';
import 'categories_provider.dart';
import 'transactions_provider.dart';

part 'recurring_transactions_provider.g.dart';

@Riverpod(keepAlive: true)
class SelectedRecurringTransactionUpdate
extends _$SelectedRecurringTransactionUpdate {
@override
RecurringTransaction? build() => null;

void setValue(RecurringTransaction? value) => state = value;
}

@Riverpod(keepAlive: true)
class RecurringTransactionsNotifier extends _$RecurringTransactionsNotifier {
@override
Future<List<RecurringTransaction>> build() {
return _getRecurringTransactions();
}

Future<List<RecurringTransaction>> _getRecurringTransactions() async {
final transactions = await ref
.read(recurringTransactionRepositoryProvider)
.selectAllActive();
return transactions;
}

Future<RecurringTransaction?> create(
num amount,
String label,
TransactionType type,
) async {
state = const AsyncLoading();

final date = ref.read(selectedDateProvider);
final toDate = ref.read(endDateProvider);
final bankAccount = ref.read(selectedBankAccountProvider)!;
final category = ref.read(selectedCategoryProvider);
final recurrency = ref.read(intervalProvider);

RecurringTransaction transaction = RecurringTransaction(
amount: amount,
fromDate: date,
toDate: toDate,
note: label,
type: type,
idBankAccount: bankAccount.id!,
idCategory: category!.id!,
recurrency: recurrency,
createdAt: date,
updatedAt: date,
lastInsertion: date,
);

// Here we need the recurringTransaction just inserted, to get and return a model with also his ID
RecurringTransaction? insertedTransaction;

state = await AsyncValue.guard(() async {
insertedTransaction = await ref
.read(recurringTransactionRepositoryProvider)
.insert(transaction);

// check if fromDate is today, and add the first recurrence of the transaction
DateTime now = DateTime.now();

if (date.year == now.year &&
date.month == now.month &&
date.day == now.day) {
final transaction = Transaction(
date: date,
amount: amount,
type: type,
note: label,
idBankAccount: bankAccount.id!,
idCategory: category.id!,
idRecurringTransaction: insertedTransaction!.id,
recurring: true,
);
await ref.read(transactionsRepositoryProvider).insert(transaction);
}
return await _getRecurringTransactions();
});

return insertedTransaction;
}

Future<void> updateTransaction(num amount, String label) async {
final bankAccount = ref.read(selectedBankAccountProvider)!;
final recurrency = ref.read(intervalProvider);
final category = ref.read(selectedCategoryProvider);

final RecurringTransaction transaction = ref
.read(selectedRecurringTransactionUpdateProvider)!
.copy(
fromDate: ref.read(selectedDateProvider),
toDate: ref.read(endDateProvider),
recurrency: recurrency,
amount: amount,
note: label,
idBankAccount: bankAccount.id!,
idCategory: category?.id,
updatedAt: DateTime.now(),
);

state = const AsyncLoading();
state = await AsyncValue.guard(() async {
await ref
.read(recurringTransactionRepositoryProvider)
.updateItem(transaction);
return await _getRecurringTransactions();
});
}

Future<void> transactionSelect(RecurringTransaction transaction) async {
ref
.read(selectedRecurringTransactionUpdateProvider.notifier)
.setValue(transaction);
ref.read(selectedRecurringPayProvider.notifier).setValue(true);
ref.read(selectedCategoryProvider.notifier).state = ref
.read(categoriesProvider)
.value!
.firstWhere((element) => element.id == transaction.idCategory);
ref.read(selectedBankAccountProvider.notifier).state = ref
.read(accountsProvider)
.value!
.firstWhere((element) => element.id == transaction.idBankAccount);
ref.read(intervalProvider.notifier).setValue(transaction.recurrency);
ref.read(endDateProvider.notifier).setDate(transaction.toDate);
}

Future<void> delete(int transactionId) async {
state = const AsyncLoading();
state = await AsyncValue.guard(() async {
await ref
.read(recurringTransactionRepositoryProvider)
.deleteById(transactionId);
return _getRecurringTransactions();
});
}
}

class RecurringPaymentsGrouped {
final int year;
final Map<String, num> transactionsByMonth;

RecurringPaymentsGrouped({
required this.year,
required this.transactionsByMonth,
});
}

@riverpod
Future<List<RecurringPaymentsGrouped>> recurringPayments(
Ref ref,
int id,
) async {
final transactions = await ref
.read(transactionsRepositoryProvider)
.getRecurrenceTransactionsById(id: id);

Map<int, Map<String, num>> groupedData = {};
for (var transaction in transactions) {
final year = transaction.date.year;
final month = DateFormat.MMMM().format(transaction.date);

groupedData.putIfAbsent(year, () => {});
groupedData[year]!.putIfAbsent(month, () => 0);
groupedData[year]![month] = groupedData[year]![month]! + transaction.amount;
}
List<RecurringPaymentsGrouped> result = [];
groupedData.forEach((year, transactionsByMonth) {
result.add(
RecurringPaymentsGrouped(
year: year,
transactionsByMonth: transactionsByMonth,
),
);
});
return result;
}
Loading