diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c0d7c3a..574de4c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## Version 1.1.2 + +- BUGFIX: Transactions between accounts now appear in both accounts + ## Version 1.1.1 - FEATURE: Creating new payee show a dialog diff --git a/lib/appState.dart b/lib/appState.dart index ac628787..ebb061ce 100644 --- a/lib/appState.dart +++ b/lib/appState.dart @@ -225,9 +225,12 @@ class AppState extends ChangeNotifier { await computeToBeBudgeted(); notifyListeners(); } else if (transaction.subcatID == Constants.UNASSIGNED_SUBCAT_ID) { - // If the transaction amount is positive, the transaction will remove money from - // outAccount and input it into inAccount. - // Otherwise, it is reversed. + /// If the transaction amount is positive, the transaction will remove money from + /// [outAccount] and input it into [inAccount]. + /// Otherwise, it is reversed. + + /// [outAccount] is ALWAYS the one pointed to by accountID. + /// Therefore, [inAccount] will be the one defined by [-payee.id]. final Account outAccount = accounts.singleWhere((account) => account.id == transaction.accountID); outAccount.balance -= transaction.amount; diff --git a/lib/models/entries.dart b/lib/models/entries.dart index f678a115..83041386 100644 --- a/lib/models/entries.dart +++ b/lib/models/entries.dart @@ -1,4 +1,3 @@ - /// This file will contain the classes for the common objects used throughout the codebase, namely /// [Payee], [MoneyTransaction], and [Account]. @@ -79,13 +78,25 @@ class MoneyTransaction { this.accountID = json[DatabaseConstants.ACCOUNT_ID_OUTSIDE]; this.amount = json[DatabaseConstants.MONEYTRANSACTION_AMOUNT]; this.memo = json[DatabaseConstants.MONEYTRANSACTION_MEMO]; - this.date = DateTime.fromMillisecondsSinceEpoch(json[DatabaseConstants.MONEYTRANSACTION_DATE]); + this.date = DateTime.fromMillisecondsSinceEpoch( + json[DatabaseConstants.MONEYTRANSACTION_DATE]); } @override String toString() { return super.toString() + - """ {id: $id, subcatID: $subcatID, payeeID: $payeeID, accountID: $accountID, amount: $amount, date: $date}"""; + """{id: $id, subcatID: $subcatID, payeeID: $payeeID, accountID: $accountID, amount: $amount, date: $date}\n"""; + } + + MoneyTransaction copy() { + return MoneyTransaction( + id: this.id, + subcatID: this.subcatID, + payeeID: this.payeeID, + accountID: this.accountID, + amount: this.amount, + memo: this.memo, + date: this.date); } } diff --git a/lib/screens/addTransaction/addTransaction.dart b/lib/screens/addTransaction/addTransaction.dart index afe6cfb9..041943ad 100644 --- a/lib/screens/addTransaction/addTransaction.dart +++ b/lib/screens/addTransaction/addTransaction.dart @@ -61,10 +61,7 @@ class _AddTransactionPageController extends State { /// List of values to choose each value from, e.g. [_payee] /// will be chosen from one of the [payees] - List payees; List subcategories; - List accounts; - List payeesAndAccounts = []; AppState appState; @override @@ -76,13 +73,7 @@ class _AddTransactionPageController extends State { amountLength = 16; // Load list of objects from the state/database appState = Provider.of(context, listen: false); - payees = appState.payees; - accounts = appState.accounts; subcategories = appState.subcategories; - - payeesAndAccounts.addAll(payees); - payeesAndAccounts.addAll(accounts); - // Set initial values of the transaction _payee = null; _account = null; @@ -129,6 +120,11 @@ class _AddTransactionPageController extends State { /// a [Payee], whose value is stored in [_payee] and whose /// name is stored in [_payeeFieldName]. handleOnTapPayee() { + + List payeesAndAccounts = []; + payeesAndAccounts.addAll(appState.payees); + payeesAndAccounts.addAll(appState.accounts); + Navigator.push( context, MaterialPageRoute( @@ -151,7 +147,7 @@ class _AddTransactionPageController extends State { Navigator.push( context, MaterialPageRoute( - builder: (context) => SelectValuePage(title: "Accounts", listEntries: accounts)), + builder: (context) => SelectValuePage(title: "Accounts", listEntries: appState.accounts)), ).then((returnElement) { if (returnElement != null) { setState(() { @@ -233,7 +229,7 @@ class _AddTransactionPageController extends State { // Input as payee ID the opposite of the account ID when we select // an account instead of a payee in the 'Payee' field print("_payee is of type ${_payee is Payee ? "Payee" : "Account"}"); - int payeeId = _payee is Payee ? _payee.id : -_account.id; + int payeeId = _payee is Payee ? _payee.id : -_payee.id; appState.addTransaction( subcatId: _selectSubcatId(), diff --git a/lib/screens/addTransaction/selectValue.dart b/lib/screens/addTransaction/selectValue.dart index 750d1552..759f17d2 100644 --- a/lib/screens/addTransaction/selectValue.dart +++ b/lib/screens/addTransaction/selectValue.dart @@ -68,18 +68,18 @@ class SelectValuePageState extends State { @override Widget build(BuildContext context) { - return new Scaffold( + return Scaffold( resizeToAvoidBottomInset: false, - appBar: new AppBar( + appBar: AppBar( title: Text(widget.title), ), - body: new Column( + body: Column( children: [ - new Padding( - padding: new EdgeInsets.only(top: 20.0), + Padding( + padding: EdgeInsets.only(top: 20.0), ), - new TextField( - decoration: new InputDecoration( + TextField( + decoration: InputDecoration( hintText: "Search something", icon: Icon(Icons.search), ), @@ -98,8 +98,8 @@ class SelectValuePageState extends State { context: context, defaultName: searchController.text), ), - new Expanded( - child: new ListView.separated( + Expanded( + child: ListView.separated( shrinkWrap: true, itemCount: widget.listEntries.length, separatorBuilder: (BuildContext context, int index) => @@ -121,7 +121,7 @@ class SelectValuePageState extends State { title: item, onTap: () => handlePopContext(item)); } // There is an error - return new Container(); + return Container(); }, )) ], diff --git a/lib/screens/showTransactions/components/transactionList.dart b/lib/screens/showTransactions/components/transactionList.dart index a86c187b..b12f3c6b 100644 --- a/lib/screens/showTransactions/components/transactionList.dart +++ b/lib/screens/showTransactions/components/transactionList.dart @@ -1,5 +1,8 @@ +import 'dart:collection'; + import 'package:flutter/material.dart'; import 'package:your_budget/appState.dart'; +import 'package:your_budget/models/constants.dart'; import 'package:your_budget/models/entries.dart'; import 'package:your_budget/screens/showTransactions/components/transactionRow.dart'; @@ -25,15 +28,15 @@ class _TransactionListState extends State { @override Widget build(BuildContext context) { - List transactionsOfAccount = widget.appState.transactions - .where((transaction) => transaction.accountID == this.widget.account.id) - .toList(); + List transactionsOfAccount = + _getMoneyTransactions( + widget.appState.transactions, this.widget.account.id); - return new Container( + return Container( child: Scrollbar( isAlwaysShown: true, controller: _scrollController, - child: new ListView.separated( + child: ListView.separated( controller: _scrollController, shrinkWrap: true, itemCount: transactionsOfAccount.length, @@ -41,10 +44,38 @@ class _TransactionListState extends State { Divider(height: 1, color: Colors.black12), itemBuilder: (BuildContext context, int index) { return Card( - child: TransactionRow( - transactionsOfAccount[index], widget.appState.allCategories, widget.isEditable)); + child: TransactionRow(transactionsOfAccount[index], + widget.appState.allCategories, widget.isEditable)); }, ), )); } } + +List _getMoneyTransactions( + UnmodifiableListView transactions, int currentAccountId) { + /// Here, [currentAccountId] is the outgoingAccount. + + List transactionsOfAccount = []; + for (var transaction in transactions) { + bool isAccountPayee = transaction.payeeID < 0; + + bool currentAccountIsPayeeAccount = + -transaction.payeeID == currentAccountId; + bool currentAccountIsStandardAccount = + transaction.accountID == currentAccountId; + + if ((currentAccountIsStandardAccount && !isAccountPayee) || + (currentAccountIsPayeeAccount && isAccountPayee)) { + transactionsOfAccount.add(transaction); + } else if ((currentAccountIsStandardAccount && isAccountPayee)) { + // The transaction is reversed.i.e. removes money from outAccount(accountId) + // into inAccount(payeeId) + MoneyTransaction negativeAmountTransaction = transaction.copy(); + negativeAmountTransaction.amount *= -1; + transactionsOfAccount.add(negativeAmountTransaction); + } + } + + return transactionsOfAccount; +} diff --git a/lib/screens/showTransactions/components/transactionRow.dart b/lib/screens/showTransactions/components/transactionRow.dart index 93a3e11a..cb27d565 100644 --- a/lib/screens/showTransactions/components/transactionRow.dart +++ b/lib/screens/showTransactions/components/transactionRow.dart @@ -28,53 +28,20 @@ class _TransactionRowState extends State { final TextStyle subcategoryStyle = TextStyle(fontSize: 16.0, fontWeight: FontWeight.w600, color: Colors.black); - TextStyle amountStyle; - - void initState() { - amountStyle = TextStyle( + @override + Widget build(BuildContext context) { + String subcategoryName = ""; + String payeeName; + TextStyle amountStyle = TextStyle( fontSize: 22.0, fontWeight: FontWeight.w600, color: widget.moneyTransaction.amount.isNegative ? Constants.RED_COLOR : Constants.GREEN_COLOR); - super.initState(); - } - - @override - Widget build(BuildContext context) { - String subcategoryName = ""; - String payeeName; AppState appState = Provider.of(context, listen: false); - if (appState.payees.isNotEmpty) { - // orElse is for starting balance - Payee payee = appState.payees - .singleWhere((payee) => payee.id == widget.moneyTransaction.payeeID, orElse: () => null); - - payeeName = payee != null ? payee.name : ""; - } else { - payeeName = ""; - } - - /// Extract name of subcategory associated to transaction [moneyTransaction] - if (widget.moneyTransaction.subcatID == Constants.UNASSIGNED_SUBCAT_ID) { - // Transfer between accounts - for (final Account account in appState.accounts) { - if (account.id == -widget.moneyTransaction.payeeID) { - subcategoryName = "To/From " + account.name; - } - } - } else if (widget.moneyTransaction.subcatID == - Constants.TO_BE_BUDGETED_ID_IN_MONEYTRANSACTION) { - //Transaction into to be budgeted - subcategoryName = "To be budgeted"; - } else { - // Transaction into subcategories - var correspondingSubcategory = widget.categories.singleWhere( - ((cat) => cat is SubCategory && cat.id == widget.moneyTransaction.subcatID), - orElse: () => null); - subcategoryName = correspondingSubcategory != null ? correspondingSubcategory.name : ""; - } + payeeName = _setPayeeName(appState); + subcategoryName = _setSubcategoryName(appState); return widget.isEditable ? CheckedRow( @@ -99,4 +66,37 @@ class _TransactionRowState extends State { payeeName, subcategoryStyle); } + + String _setSubcategoryName(AppState appState) { + /// Extract name of subcategory associated to transaction [moneyTransaction] + if (widget.moneyTransaction.subcatID == Constants.UNASSIGNED_SUBCAT_ID) { + // Transfer between accounts + for (final Account account in appState.accounts) { + if (account.id == -widget.moneyTransaction.payeeID) { + return "To/From " + account.name; + } + } + } else if (widget.moneyTransaction.subcatID == + Constants.TO_BE_BUDGETED_ID_IN_MONEYTRANSACTION) { + //Transaction into to be budgeted + return "To be budgeted"; + } + // Transaction into subcategories + var correspondingSubcategory = widget.categories.singleWhere( + ((cat) => cat is SubCategory && cat.id == widget.moneyTransaction.subcatID), + orElse: () => null); + return correspondingSubcategory != null ? correspondingSubcategory.name : ""; + + } + + String _setPayeeName(AppState appState) { + if (appState.payees.isNotEmpty) { + // orElse is for starting balance + Payee payee = appState.payees + .singleWhere((payee) => payee.id == widget.moneyTransaction.payeeID, orElse: () => null); + + return payee != null ? payee.name : ""; + } + return ""; + } } diff --git a/pubspec.yaml b/pubspec.yaml index 5a86b868..a63140da 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.1.1+11 +version: 1.1.2+12 environment: sdk: ">=2.7.0 <3.0.0" diff --git a/version.txt b/version.txt index eb9a4385..328308ff 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.1.1+11 +1.1.2+12