From 78614bd02192a0755def8c39d37135bc5c9f7d4a Mon Sep 17 00:00:00 2001 From: gltron Date: Sat, 29 Jun 2024 17:05:50 +0200 Subject: [PATCH] added account filter --- .../transaction/models/transaction_line.dart | 12 ++- lib/domains/transaction/transaction_bloc.dart | 93 ++++++++++++++----- .../transaction/transaction_event.dart | 6 ++ .../transaction/transaction_state.dart | 10 +- .../transactions/widgets/account_filter.dart | 36 +++++++ .../transactions/widgets/category_filter.dart | 3 +- .../widgets/transactions_actions.dart | 3 + .../widgets/transactions_list.dart | 8 +- .../transactions/models/transaction.dart | 20 ++-- 9 files changed, 148 insertions(+), 43 deletions(-) create mode 100644 lib/pages/transactions/widgets/account_filter.dart diff --git a/lib/domains/transaction/models/transaction_line.dart b/lib/domains/transaction/models/transaction_line.dart index cbb82e0..9c19353 100644 --- a/lib/domains/transaction/models/transaction_line.dart +++ b/lib/domains/transaction/models/transaction_line.dart @@ -1,11 +1,15 @@ +import 'package:equatable/equatable.dart'; import 'package:krezus/repositories/transactions/models/transaction.dart'; -class TransactionLine { - Transaction transaction; - double subTotal; +class TransactionLine extends Equatable{ + final Transaction transaction; + final double subTotal; - TransactionLine({ + const TransactionLine({ required this.transaction, required this.subTotal, }); + + @override + List get props => [transaction, subTotal]; } \ No newline at end of file diff --git a/lib/domains/transaction/transaction_bloc.dart b/lib/domains/transaction/transaction_bloc.dart index 65e3fdb..39e40f5 100644 --- a/lib/domains/transaction/transaction_bloc.dart +++ b/lib/domains/transaction/transaction_bloc.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:equatable/equatable.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:formz/formz.dart'; @@ -7,6 +9,7 @@ import 'package:krezus/domains/transaction/models/transaction_date.dart'; import 'package:krezus/domains/transaction/models/transaction_description.dart'; import 'package:krezus/domains/transaction/models/transaction_line.dart'; import 'package:krezus/domains/transaction/models/transaction_value.dart'; +import 'package:krezus/repositories/metadata/models/account.dart'; import 'package:krezus/repositories/metadata/models/category.dart'; import 'package:krezus/repositories/transactions/models/transaction.dart'; import 'package:krezus/repositories/transactions/transactions_repository.dart'; @@ -33,18 +36,19 @@ class TransactionBloc extends Bloc { on(_onTransactionSetCurrent); on(_onTransactionDeleteCurrent); on(_onTransactionFilterCategory); + on(_onTransactionFilterAccount); _transactionsRepository .getTransactionsStream() .listen((transactions) => add(TransactionsLoad(transactions))); } - _onAccountLoad(TransactionsLoad event, Emitter emit) { + FutureOr _onAccountLoad(TransactionsLoad event, Emitter emit) { var computeResult = _computeTransactionLine(event.transactions); emit(state.copyWith( transactions: event.transactions, transactionsLines: computeResult.list, - transactionsLinesFiltered: _applyCategoryFilter(computeResult.list), + transactionsLinesFiltered: _applyFilters(computeResult.list), globalTotal: computeResult.globalTotal, accountsTotals: computeResult.accountsTotals, )); @@ -73,7 +77,7 @@ class TransactionBloc extends Bloc { return (list: output, globalTotal: globalTotal, accountsTotals: accountsTotals, categories: categories.toList()); } - _onTransactionDateChange( + FutureOr _onTransactionDateChange( TransactionDateChange event, Emitter emit ) { final transactionDate = TransactionDate.dirty(event.date); @@ -83,7 +87,7 @@ class TransactionBloc extends Bloc { )); } - _onTransactionCategoryChange( + FutureOr _onTransactionCategoryChange( TransactionCategoryChange event, Emitter emit ) { final transactionCategory = TransactionCategory.dirty(event.category); @@ -93,7 +97,7 @@ class TransactionBloc extends Bloc { )); } - _onTransactionDescriptionChange( + FutureOr _onTransactionDescriptionChange( TransactionDescriptionChange event, Emitter emit ) { final transactionDescription = TransactionDescription.dirty(event.description); @@ -103,7 +107,7 @@ class TransactionBloc extends Bloc { )); } - _onTransactionAccountChange( + FutureOr _onTransactionAccountChange( TransactionAccountChange event, Emitter emit ) { final transactionAccount = TransactionAccount.dirty(event.account); @@ -113,7 +117,7 @@ class TransactionBloc extends Bloc { )); } - _onTransactionValueChange( + FutureOr _onTransactionValueChange( TransactionValueChange event, Emitter emit ) { try { @@ -131,19 +135,19 @@ class TransactionBloc extends Bloc { } } - _onTransactionOpenAddDialog( + FutureOr _onTransactionOpenAddDialog( TransactionOpenAddDialog event, Emitter emit ) { emit(state.copyWith(showAddDialog: true)); } - _onTransactionHideAddDialog( + FutureOr _onTransactionHideAddDialog( TransactionHideAddDialog event, Emitter emit ) { emit(state.copyWith(showAddDialog: false)); } - _onTransactionAddDialog( + FutureOr _onTransactionAddDialog( TransactionAdd event, Emitter emit ) { if (state.isValid) { @@ -174,14 +178,14 @@ class TransactionBloc extends Bloc { // transactionValue: const TransactionValue.pure(), transactions: transactions, transactionsLines: computeResult.list, - transactionsLinesFiltered: _applyCategoryFilter(computeResult.list), + transactionsLinesFiltered: _applyFilters(computeResult.list), globalTotal: computeResult.globalTotal, accountsTotals: computeResult.accountsTotals, )); } } - _onTransactionSetCurrent( + FutureOr _onTransactionSetCurrent( TransactionSetCurrent event, Emitter emit ) { Transaction? transaction = event.transaction; @@ -206,7 +210,7 @@ class TransactionBloc extends Bloc { } } - _onTransactionDeleteCurrent( + FutureOr _onTransactionDeleteCurrent( TransactionDeleteCurrent event, Emitter emit ) { Transaction? currentTransaction = state.currentTransaction; @@ -224,33 +228,72 @@ class TransactionBloc extends Bloc { transactionValue: const TransactionValue.pure(), transactions: transactions, transactionsLines: computeResult.list, - transactionsLinesFiltered: _applyCategoryFilter(computeResult.list), + transactionsLinesFiltered: _applyFilters(computeResult.list), globalTotal: computeResult.globalTotal, accountsTotals: computeResult.accountsTotals, )); } } - - _onTransactionFilterCategory(TransactionFilterCategory event, Emitter emit) { - List transactionsLinesFiltered = state.transactionsLines; - String? categoryLabel = event.category?.label; - if (categoryLabel != null) { - transactionsLinesFiltered = state.transactionsLines.where((transaction) => transaction.transaction.category == categoryLabel).toList(); - } + FutureOr _onTransactionFilterCategory(TransactionFilterCategory event, Emitter emit) { + emit(TransactionState( + globalTotal: state.globalTotal, + accountsTotals: state.accountsTotals, + transactions: state.transactions, + transactionsLines: state.transactionsLines, + transactionsLinesFiltered: state.transactionsLinesFiltered, + transactionDate: state.transactionDate, + transactionCategory: state.transactionCategory, + transactionDescription: state.transactionDescription, + transactionAccount: state.transactionAccount, + transactionValue: state.transactionValue, + isValid: state.isValid, + showAddDialog: state.showAddDialog, + currentTransaction: state.currentTransaction, + categoryFilter: event.category, + accountFilter: state.accountFilter, + )); emit(state.copyWith( - transactionsLinesFiltered: transactionsLinesFiltered, - categoryFilter: event.category, + transactionsLinesFiltered: _applyFilters(state.transactionsLines), )); } - List _applyCategoryFilter(List transactionsLines) { + FutureOr _onTransactionFilterAccount(TransactionFilterAccount event, Emitter emit) { + emit(TransactionState( + globalTotal: state.globalTotal, + accountsTotals: state.accountsTotals, + transactions: state.transactions, + transactionsLines: state.transactionsLines, + transactionsLinesFiltered: state.transactionsLinesFiltered, + transactionDate: state.transactionDate, + transactionCategory: state.transactionCategory, + transactionDescription: state.transactionDescription, + transactionAccount: state.transactionAccount, + transactionValue: state.transactionValue, + isValid: state.isValid, + showAddDialog: state.showAddDialog, + currentTransaction: state.currentTransaction, + categoryFilter: state.categoryFilter, + accountFilter: event.account, + )); + emit(state.copyWith( + transactionsLinesFiltered: _applyFilters(state.transactionsLines), + )); + } + + List _applyFilters(List transactionsLines) { List transactionsLinesFiltered = transactionsLines; String? categoryLabel = state.categoryFilter?.label; if (categoryLabel != null) { - transactionsLinesFiltered = state.transactionsLines.where((transaction) => transaction.transaction.category == categoryLabel).toList(); + transactionsLinesFiltered = transactionsLinesFiltered.where((transaction) => transaction.transaction.category == categoryLabel).toList(); } + + String? accountLabel = state.accountFilter?.label; + if (accountLabel != null) { + transactionsLinesFiltered = transactionsLinesFiltered.where((transaction) => transaction.transaction.account == accountLabel).toList(); + } + return transactionsLinesFiltered; } } \ No newline at end of file diff --git a/lib/domains/transaction/transaction_event.dart b/lib/domains/transaction/transaction_event.dart index 40ac595..2b7ce6f 100644 --- a/lib/domains/transaction/transaction_event.dart +++ b/lib/domains/transaction/transaction_event.dart @@ -77,4 +77,10 @@ final class TransactionFilterCategory extends TransactionEvent { final Category? category; const TransactionFilterCategory(this.category); +} + +final class TransactionFilterAccount extends TransactionEvent { + final Account? account; + + const TransactionFilterAccount(this.account); } \ No newline at end of file diff --git a/lib/domains/transaction/transaction_state.dart b/lib/domains/transaction/transaction_state.dart index b63793e..ce334ca 100644 --- a/lib/domains/transaction/transaction_state.dart +++ b/lib/domains/transaction/transaction_state.dart @@ -8,6 +8,7 @@ final class TransactionState extends Equatable { final List transactionsLines; final List transactionsLinesFiltered; final Category? categoryFilter; + final Account? accountFilter; final TransactionDate transactionDate; final TransactionCategory transactionCategory; @@ -34,6 +35,7 @@ final class TransactionState extends Equatable { this.showAddDialog = false, this.currentTransaction, this.categoryFilter, + this.accountFilter, }); TransactionState copyWith({ @@ -51,6 +53,7 @@ final class TransactionState extends Equatable { bool? showAddDialog, Transaction? currentTransaction, Category? categoryFilter, + Account? accountFilter, }) { return TransactionState( globalTotal: globalTotal ?? this.globalTotal, @@ -66,12 +69,16 @@ final class TransactionState extends Equatable { isValid: isValid ?? this.isValid, showAddDialog: showAddDialog ?? this.showAddDialog, currentTransaction: currentTransaction ?? this.currentTransaction, - categoryFilter: categoryFilter, + categoryFilter: categoryFilter ?? this.categoryFilter, + accountFilter: accountFilter ?? this.accountFilter, ); } @override List get props => [ + transactions, + transactionsLines, + transactionsLinesFiltered, transactionDate, transactionCategory, transactionDescription, @@ -81,6 +88,7 @@ final class TransactionState extends Equatable { showAddDialog, currentTransaction, categoryFilter, + accountFilter, ]; } \ No newline at end of file diff --git a/lib/pages/transactions/widgets/account_filter.dart b/lib/pages/transactions/widgets/account_filter.dart new file mode 100644 index 0000000..2eb2ece --- /dev/null +++ b/lib/pages/transactions/widgets/account_filter.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:krezus/domains/account/account_bloc.dart'; +import 'package:krezus/domains/transaction/transaction_bloc.dart'; +import 'package:krezus/repositories/metadata/models/account.dart'; + +class AccountFilter extends StatelessWidget { + const AccountFilter({super.key}); + + @override + Widget build(BuildContext context) { + final accountState = context.watch().state; + + return BlocBuilder( + buildWhen: (previous, current) => previous.accountFilter != current.accountFilter, + builder: (context, state) => SizedBox( + width: 300, + child: DropdownButtonFormField( + value: state.accountFilter, + onChanged: (value) => context.read().add(TransactionFilterAccount(value!)), + items: accountState.accounts.map((e) => DropdownMenuItem(value: e, child: Text(e.label))).toList(), + decoration: InputDecoration( + suffixIcon: IconButton( + icon: const Icon(Icons.filter_alt_off), + onPressed: () => context.read().add(const TransactionFilterAccount(null)), + ), + hintText: 'Account', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/pages/transactions/widgets/category_filter.dart b/lib/pages/transactions/widgets/category_filter.dart index c5b61bc..377c7ec 100644 --- a/lib/pages/transactions/widgets/category_filter.dart +++ b/lib/pages/transactions/widgets/category_filter.dart @@ -10,10 +10,11 @@ class CategoryFilter extends StatelessWidget { @override Widget build(BuildContext context) { final categoryState = context.watch().state; + return BlocBuilder( buildWhen: (previous, current) => previous.categoryFilter != current.categoryFilter, builder: (context, state) => SizedBox( - width: 500, + width: 300, child: DropdownButtonFormField( value: state.categoryFilter, onChanged: (value) => context.read().add(TransactionFilterCategory(value!)), diff --git a/lib/pages/transactions/widgets/transactions_actions.dart b/lib/pages/transactions/widgets/transactions_actions.dart index 32089f9..aaf49b8 100644 --- a/lib/pages/transactions/widgets/transactions_actions.dart +++ b/lib/pages/transactions/widgets/transactions_actions.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:krezus/domains/transaction/transaction_bloc.dart'; +import 'package:krezus/pages/transactions/widgets/account_filter.dart'; import 'package:krezus/pages/transactions/widgets/category_filter.dart'; import 'package:krezus/pages/transactions/widgets/transaction_add_dialog.dart'; @@ -31,6 +32,7 @@ class TransactionsActions extends StatelessWidget { ], ), const CategoryFilter(), + const AccountFilter(), ], ); } @@ -47,6 +49,7 @@ class TransactionsActions extends StatelessWidget { ), ), const CategoryFilter(), + const AccountFilter(), IconButton( onPressed: () => TransactionAddDialog.show(context, null), icon: const Icon( diff --git a/lib/pages/transactions/widgets/transactions_list.dart b/lib/pages/transactions/widgets/transactions_list.dart index 6ca4868..9a02a0c 100644 --- a/lib/pages/transactions/widgets/transactions_list.dart +++ b/lib/pages/transactions/widgets/transactions_list.dart @@ -15,10 +15,10 @@ class TransactionsList extends StatelessWidget { itemCount: state.transactionsLinesFiltered.length, itemBuilder: (context, index) => TransactionLine( transaction: state.transactionsLinesFiltered[index].transaction, - subTotal: state.transactionsLinesFiltered[index].subTotal - ) - ) - ) + subTotal: state.transactionsLinesFiltered[index].subTotal, + ), + ), + ), ); } } \ No newline at end of file diff --git a/lib/repositories/transactions/models/transaction.dart b/lib/repositories/transactions/models/transaction.dart index b0d3bea..a48655e 100644 --- a/lib/repositories/transactions/models/transaction.dart +++ b/lib/repositories/transactions/models/transaction.dart @@ -1,14 +1,15 @@ +import 'package:equatable/equatable.dart'; import 'package:uuid/uuid.dart'; -class Transaction { - String uuid; - DateTime date; - String category; - String description; - String account; - double value; +class Transaction extends Equatable { + final String uuid; + final DateTime date; + final String category; + final String description; + final String account; + final double value; - Transaction({ + const Transaction({ required this.uuid, required this.date, required this.category, @@ -36,4 +37,7 @@ class Transaction { 'account': account, 'value': value.toString(), }; + + @override + List get props => [uuid, date, category, description, account, value]; } \ No newline at end of file