complete budget page
This commit is contained in:
@@ -4,55 +4,66 @@ import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:tunas/repositories/metadata/models/budget.dart';
|
||||
import 'package:tunas/repositories/metadata/metadata_repository.dart';
|
||||
import 'package:tunas/repositories/transactions/transactions_repository.dart';
|
||||
|
||||
part 'budget_event.dart';
|
||||
part 'budget_state.dart';
|
||||
|
||||
class BudgetBloc extends Bloc<BudgetEvent, BudgetState> {
|
||||
final MetadataRepository _metadataRepository;
|
||||
final TransactionsRepository _transactionsRepository;
|
||||
Timer? setValueTimer;
|
||||
|
||||
BudgetBloc({required MetadataRepository metadataRepository}) : _metadataRepository = metadataRepository, super(const BudgetState()) {
|
||||
BudgetBloc({required MetadataRepository metadataRepository, required TransactionsRepository transactionsRepository}) : _metadataRepository = metadataRepository, _transactionsRepository = transactionsRepository, super(const BudgetState()) {
|
||||
on<BudgetsLoad>(_onBudgetsLoad);
|
||||
on<BudgetAdd>(_onBudgetAdd);
|
||||
on<BudgetRemove>(_onBudgetRemove);
|
||||
on<BudgetSetValue>(_onBudgetSetValue);
|
||||
on<BudgetSetLabel>(_onBudgetSetLabel);
|
||||
on<BudgetCompareNext>(_onBudgetCompareNext);
|
||||
on<BudgetComparePrevious>(_onBudgetComparePrevious);
|
||||
on<BudgetSetCompare>(_onBudgetSetCompare);
|
||||
on<BudgetSetInitial>(_onBudgetSetInitial);
|
||||
|
||||
_metadataRepository
|
||||
.getBudgetsStream()
|
||||
.listen((budgets) => add(BudgetsLoad(budgets)));
|
||||
|
||||
_transactionsRepository
|
||||
.getTransactionsStream()
|
||||
.listen((transactions) => add(BudgetSetCompare()));
|
||||
}
|
||||
|
||||
_onBudgetsLoad(
|
||||
BudgetsLoad event, Emitter<BudgetState> emit
|
||||
) {
|
||||
emit(state.copyWith(
|
||||
budgets: event.budgets,
|
||||
));
|
||||
emit(_computeState(event.budgets, null));
|
||||
}
|
||||
|
||||
FutureOr<void> _onBudgetAdd(BudgetAdd event, Emitter<BudgetState> emit) async {
|
||||
FutureOr<void> _onBudgetAdd(BudgetAdd event, Emitter<BudgetState> emit) {
|
||||
Budget budget = Budget(
|
||||
label: event.label,
|
||||
);
|
||||
|
||||
emit(_computeState(await _saveBudget(budget)));
|
||||
List<Budget> budgets = _computeBudgets(budget);
|
||||
_saveBudget(budgets);
|
||||
emit(_computeState(budgets, null));
|
||||
}
|
||||
|
||||
FutureOr<void> _onBudgetRemove(BudgetRemove event, Emitter<BudgetState> emit) async {
|
||||
FutureOr<void> _onBudgetRemove(BudgetRemove event, Emitter<BudgetState> emit) {
|
||||
List<Budget> budgets = _metadataRepository.getBudgets();
|
||||
Budget budgetToRemove = event.budget;
|
||||
|
||||
budgets.removeWhere((budget) => budget.label == budgetToRemove.label);
|
||||
emit(_computeState(await _metadataRepository.saveBudgets(budgets)));
|
||||
emit(_computeState(_metadataRepository.saveBudgets(budgets), null));
|
||||
}
|
||||
|
||||
FutureOr<void> _onBudgetSetValue(BudgetSetValue event, Emitter<BudgetState> emit) async {
|
||||
void _onBudgetSetValue(BudgetSetValue event, Emitter<BudgetState> emit) {
|
||||
Budget budgetToUpdate = event.budget;
|
||||
double newValue = event.value;
|
||||
|
||||
if (state.remainingBudget - (event.value - budgetToUpdate.value) < 0) {
|
||||
return;
|
||||
newValue = event.budget.value + state.remainingBudget;
|
||||
}
|
||||
|
||||
// if (state.remainingBudget - event.value < 0 && state.remainingBudget < 10) {
|
||||
@@ -60,18 +71,112 @@ class BudgetBloc extends Bloc<BudgetEvent, BudgetState> {
|
||||
// } else {
|
||||
// budgetToUpdate.value = event.value;
|
||||
// }
|
||||
budgetToUpdate.value = event.value;
|
||||
budgetToUpdate.value = newValue;
|
||||
List<Budget> budgets = _computeBudgets(budgetToUpdate);
|
||||
emit(_computeState(budgets, null));
|
||||
|
||||
emit(_computeState(await _saveBudget(budgetToUpdate)));
|
||||
setValueTimer?.cancel();
|
||||
setValueTimer = Timer(
|
||||
const Duration(milliseconds: 100),
|
||||
() {
|
||||
_saveBudget(budgets);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
FutureOr<void> _onBudgetCompareNext(BudgetCompareNext event, Emitter<BudgetState> emit) {
|
||||
void _onBudgetSetLabel(BudgetSetLabel event, Emitter<BudgetState> emit) {
|
||||
Budget budgetToUpdate = event.budget;
|
||||
|
||||
budgetToUpdate.label = event.label;
|
||||
List<Budget> budgets = _computeBudgets(budgetToUpdate);
|
||||
_saveBudget(budgets);
|
||||
emit(_computeState(budgets, null));
|
||||
}
|
||||
|
||||
FutureOr<void> _onBudgetComparePrevious(BudgetComparePrevious event, Emitter<BudgetState> emit) {
|
||||
void _onBudgetCompareNext(BudgetCompareNext event, Emitter<BudgetState> emit) {
|
||||
num compareMonth = state.compareMonth;
|
||||
num compareYear = state.compareYear;
|
||||
if (state.compareMonth == 12) {
|
||||
compareMonth = 1;
|
||||
compareYear++;
|
||||
} else {
|
||||
compareMonth++;
|
||||
}
|
||||
|
||||
if (state.lastDate != null && state.lastDate!.isBefore(DateTime(compareYear.toInt(), compareMonth.toInt()))) {
|
||||
return;
|
||||
}
|
||||
|
||||
final compareResult = _computeCompareBudget(state.budgets, compareYear, compareMonth);
|
||||
emit(state.copyWith(
|
||||
compareBudgets: compareResult.$1,
|
||||
otherBudgets: compareResult.$2,
|
||||
compareMonth: compareMonth,
|
||||
compareYear: compareYear,
|
||||
));
|
||||
}
|
||||
|
||||
Future<List<Budget>> _saveBudget(Budget budgetToSave) async {
|
||||
void _onBudgetComparePrevious(BudgetComparePrevious event, Emitter<BudgetState> emit) {
|
||||
num compareMonth = state.compareMonth;
|
||||
num compareYear = state.compareYear;
|
||||
if (state.compareMonth == 1) {
|
||||
compareMonth = 12;
|
||||
compareYear--;
|
||||
} else {
|
||||
compareMonth--;
|
||||
}
|
||||
|
||||
if (state.firstDate != null && state.firstDate!.isAfter(DateTime(compareYear.toInt(), compareMonth.toInt()))) {
|
||||
return;
|
||||
}
|
||||
|
||||
final compareResult = _computeCompareBudget(state.budgets, compareYear, compareMonth);
|
||||
emit(state.copyWith(
|
||||
compareBudgets: compareResult.$1,
|
||||
otherBudgets: compareResult.$2,
|
||||
compareMonth: compareMonth,
|
||||
compareYear: compareYear,
|
||||
));
|
||||
}
|
||||
|
||||
_onBudgetSetCompare(BudgetSetCompare event, Emitter<BudgetState> emit) {
|
||||
DateTime firstDate = DateTime.now();
|
||||
DateTime lastDate = DateTime.fromMicrosecondsSinceEpoch(0);
|
||||
|
||||
for (var transaction in _transactionsRepository.getTransactions()) {
|
||||
if (firstDate.compareTo(transaction.date) > 0) {
|
||||
firstDate = transaction.date;
|
||||
}
|
||||
|
||||
if (lastDate.compareTo(transaction.date) < 0) {
|
||||
lastDate = transaction.date;
|
||||
}
|
||||
}
|
||||
|
||||
num compareMonth = state.compareMonth;
|
||||
num compareYear = state.compareYear;
|
||||
|
||||
if (compareMonth == 1 && compareYear == 2000) {
|
||||
compareMonth = lastDate.month;
|
||||
compareYear = lastDate.year;
|
||||
}
|
||||
|
||||
final compareResult = _computeCompareBudget(state.budgets, compareYear, compareMonth);
|
||||
emit(state.copyWith(
|
||||
firstDate: firstDate,
|
||||
lastDate: lastDate,
|
||||
compareMonth: compareMonth,
|
||||
compareYear: compareYear,
|
||||
compareBudgets: compareResult.$1,
|
||||
otherBudgets: compareResult.$2,
|
||||
));
|
||||
}
|
||||
|
||||
void _onBudgetSetInitial(BudgetSetInitial event, Emitter<BudgetState> emit) {
|
||||
emit(_computeState(state.budgets, event.value));
|
||||
}
|
||||
|
||||
List<Budget> _computeBudgets(Budget budgetToSave) {
|
||||
List<Budget> budgets = _metadataRepository.getBudgets();
|
||||
|
||||
try {
|
||||
@@ -85,14 +190,48 @@ class BudgetBloc extends Bloc<BudgetEvent, BudgetState> {
|
||||
}
|
||||
}
|
||||
|
||||
// _metadataRepository.saveBudgets(budgets);
|
||||
return budgets;
|
||||
}
|
||||
|
||||
BudgetState _computeState(List<Budget> budgets) {
|
||||
List<Budget> _saveBudget(List<Budget> budgets) {
|
||||
return _metadataRepository.saveBudgets(budgets);
|
||||
}
|
||||
|
||||
(List<Budget> compareBudgets, List<Budget> otherBudgets) _computeCompareBudget(List<Budget> budgets, num year, num month) {
|
||||
Map<String, Budget> compareBudgetMap = { for (var budget in budgets) budget.label : Budget(label: budget.label)};
|
||||
Budget otherBudget = Budget(label: 'Hors budget');
|
||||
Map<String, Budget> otherBudgetMap = {};
|
||||
List<Budget> compareBudgets = [];
|
||||
_transactionsRepository.getTransactions()
|
||||
.where((transaction) => transaction.value < 0 && transaction.date.year == year && transaction.date.month == month)
|
||||
.forEach((transaction) {
|
||||
Budget? budget = compareBudgetMap[transaction.category];
|
||||
if (budget == null) {
|
||||
otherBudget.value += transaction.value.abs();
|
||||
Budget? otherBudgetFromMap = otherBudgetMap[transaction.category];
|
||||
if (otherBudgetFromMap == null) {
|
||||
otherBudgetMap[transaction.category] = Budget(label: transaction.category, value: transaction.value.abs());
|
||||
} else {
|
||||
otherBudgetFromMap.value += transaction.value.abs();
|
||||
}
|
||||
} else {
|
||||
budget.value += transaction.value.abs();
|
||||
}
|
||||
});
|
||||
|
||||
compareBudgets.addAll(compareBudgetMap.values);
|
||||
compareBudgets.add(otherBudget);
|
||||
return (compareBudgets, otherBudgetMap.values.toList()..sort((a, b) => b.value.compareTo(a.value)));
|
||||
}
|
||||
|
||||
BudgetState _computeState(List<Budget> budgets, double? initialBudget) {
|
||||
final compareResult = _computeCompareBudget(state.budgets, state.compareYear, state.compareMonth);
|
||||
return state.copyWith(
|
||||
budgets: budgets,
|
||||
remainingBudget: state.initialBudget - budgets.map((budget) => budget.value).reduce((value, element) => value + element),
|
||||
initialBudget: (initialBudget ?? state.initialBudget),
|
||||
remainingBudget: (initialBudget ?? state.initialBudget) - budgets.map((budget) => budget.value).reduce((value, element) => value + element),
|
||||
compareBudgets: compareResult.$1,
|
||||
otherBudgets: compareResult.$2,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -43,5 +43,24 @@ final class BudgetSetValue extends BudgetEvent {
|
||||
List<Object> get props => [budget, value];
|
||||
}
|
||||
|
||||
final class BudgetSetLabel extends BudgetEvent {
|
||||
final Budget budget;
|
||||
final String label;
|
||||
|
||||
const BudgetSetLabel(this.budget, this.label);
|
||||
|
||||
@override
|
||||
List<Object> get props => [budget, label];
|
||||
}
|
||||
|
||||
final class BudgetCompareNext extends BudgetEvent {}
|
||||
final class BudgetComparePrevious extends BudgetEvent {}
|
||||
final class BudgetComparePrevious extends BudgetEvent {}
|
||||
final class BudgetSetCompare extends BudgetEvent {}
|
||||
final class BudgetSetInitial extends BudgetEvent {
|
||||
final double value;
|
||||
|
||||
const BudgetSetInitial(this.value);
|
||||
|
||||
@override
|
||||
List<Object> get props => [value];
|
||||
}
|
||||
@@ -5,21 +5,46 @@ final class BudgetState {
|
||||
final double initialBudget;
|
||||
final double remainingBudget;
|
||||
|
||||
final List<Budget> compareBudgets;
|
||||
final List<Budget> otherBudgets;
|
||||
final num compareYear;
|
||||
final num compareMonth;
|
||||
final DateTime? firstDate;
|
||||
final DateTime? lastDate;
|
||||
|
||||
const BudgetState({
|
||||
this.budgets = const [],
|
||||
this.initialBudget = 2300.0,
|
||||
this.remainingBudget = 2300.0,
|
||||
this.compareBudgets = const [],
|
||||
this.otherBudgets = const [],
|
||||
this.compareYear = 2000,
|
||||
this.compareMonth = 1,
|
||||
this.firstDate,
|
||||
this.lastDate,
|
||||
});
|
||||
|
||||
BudgetState copyWith({
|
||||
List<Budget>? budgets,
|
||||
double? initialBudget,
|
||||
double? remainingBudget,
|
||||
List<Budget>? compareBudgets,
|
||||
List<Budget>? otherBudgets,
|
||||
num? compareYear,
|
||||
num? compareMonth,
|
||||
DateTime? firstDate,
|
||||
DateTime? lastDate,
|
||||
}) {
|
||||
return BudgetState(
|
||||
budgets: budgets ?? this.budgets,
|
||||
initialBudget: initialBudget ?? this.initialBudget,
|
||||
remainingBudget: remainingBudget ?? this.remainingBudget,
|
||||
compareBudgets: compareBudgets ?? this.compareBudgets,
|
||||
otherBudgets: otherBudgets ?? this.otherBudgets,
|
||||
compareYear: compareYear ?? this.compareYear,
|
||||
compareMonth: compareMonth ?? this.compareMonth,
|
||||
firstDate: firstDate ?? this.firstDate,
|
||||
lastDate: lastDate ?? this.lastDate,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user