Merge pull request #144 from cake-tech/CAKE-158-transaction-and-balance-displaying-between-accounts

CAKE-158 | added calculating balance to _onAccountChangeReaction in t…
This commit is contained in:
M 2020-12-04 11:25:59 +02:00
commit 042b17a82f
13 changed files with 186 additions and 58 deletions

View file

@ -7,7 +7,7 @@ class MoneroLabelValidator extends TextValidator {
MoneroLabelValidator({@required CryptoCurrency type}) MoneroLabelValidator({@required CryptoCurrency type})
: super( : super(
errorMessage: S.current.error_text_account_name, errorMessage: S.current.error_text_account_name,
pattern: '^[a-zA-Z0-9_]{1,15}\$', pattern: '^[a-zA-Z0-9_ ]{1,15}\$',
minLength: 1, minLength: 1,
maxLength: 15); maxLength: 15);
} }

View file

@ -49,6 +49,7 @@ import 'package:cake_wallet/store/wallet_list_store.dart';
import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart'; import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart';
import 'package:cake_wallet/view_model/contact_list/contact_view_model.dart'; import 'package:cake_wallet/view_model/contact_list/contact_view_model.dart';
import 'package:cake_wallet/view_model/exchange/exchange_trade_view_model.dart'; import 'package:cake_wallet/view_model/exchange/exchange_trade_view_model.dart';
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
import 'package:cake_wallet/view_model/node_list/node_list_view_model.dart'; import 'package:cake_wallet/view_model/node_list/node_list_view_model.dart';
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart'; import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
import 'package:cake_wallet/view_model/rescan_view_model.dart'; import 'package:cake_wallet/view_model/rescan_view_model.dart';
@ -274,7 +275,7 @@ Future setup(
getIt.registerFactory(() => MoneroAccountListPage( getIt.registerFactory(() => MoneroAccountListPage(
accountListViewModel: getIt.get<MoneroAccountListViewModel>())); accountListViewModel: getIt.get<MoneroAccountListViewModel>()));
getIt.registerFactory(() { /*getIt.registerFactory(() {
final wallet = getIt.get<AppStore>().wallet; final wallet = getIt.get<AppStore>().wallet;
if (wallet is MoneroWallet) { if (wallet is MoneroWallet) {
@ -287,7 +288,20 @@ Future setup(
getIt.registerFactory(() => MoneroAccountEditOrCreatePage( getIt.registerFactory(() => MoneroAccountEditOrCreatePage(
moneroAccountCreationViewModel: moneroAccountCreationViewModel:
getIt.get<MoneroAccountEditOrCreateViewModel>())); getIt.get<MoneroAccountEditOrCreateViewModel>()));*/
getIt.registerFactoryParam<MoneroAccountEditOrCreateViewModel,
AccountListItem, void>(
(AccountListItem account, _) =>
MoneroAccountEditOrCreateViewModel((
getIt.get<AppStore>().wallet as MoneroWallet).accountList,
accountListItem: account));
getIt.registerFactoryParam<MoneroAccountEditOrCreatePage,
AccountListItem, void>((AccountListItem account, _) =>
MoneroAccountEditOrCreatePage(
moneroAccountCreationViewModel:
getIt.get<MoneroAccountEditOrCreateViewModel>(param1: account)));
getIt.registerFactory(() { getIt.registerFactory(() {
final appStore = getIt.get<AppStore>(); final appStore = getIt.get<AppStore>();

View file

@ -40,6 +40,10 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance> with Store {
fullBalance: monero_wallet.getFullBalance(accountIndex: 0), fullBalance: monero_wallet.getFullBalance(accountIndex: 0),
unlockedBalance: monero_wallet.getFullBalance(accountIndex: 0)); unlockedBalance: monero_wallet.getFullBalance(accountIndex: 0));
_onAccountChangeReaction = reaction((_) => account, (Account account) { _onAccountChangeReaction = reaction((_) => account, (Account account) {
balance = MoneroBalance(
fullBalance: monero_wallet.getFullBalance(accountIndex: account.id),
unlockedBalance:
monero_wallet.getUnlockedBalance(accountIndex: account.id));
subaddressList.update(accountIndex: account.id); subaddressList.update(accountIndex: account.id);
subaddress = subaddressList.subaddresses.first; subaddress = subaddressList.subaddresses.first;
address = subaddress.address; address = subaddress.address;
@ -94,7 +98,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance> with Store {
bool _isSavingAfterNewTransaction; bool _isSavingAfterNewTransaction;
Future<void> init() async { Future<void> init() async {
await accountList.update(); accountList.update();
account = accountList.accounts.first; account = accountList.accounts.first;
subaddressList.update(accountIndex: account.id ?? 0); subaddressList.update(accountIndex: account.id ?? 0);
subaddress = subaddressList.getAll().first; subaddress = subaddressList.getAll().first;
@ -255,6 +259,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance> with Store {
monero_wallet.rescanBlockchainAsync(); monero_wallet.rescanBlockchainAsync();
await startSync(); await startSync();
_askForUpdateBalance(); _askForUpdateBalance();
accountList.update();
await _askForUpdateTransactionHistory(); await _askForUpdateTransactionHistory();
await save(); await save();
await walletInfo.save(); await walletInfo.save();
@ -362,17 +367,20 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance> with Store {
void _onNewBlock(int height, int blocksLeft, double ptc) async { void _onNewBlock(int height, int blocksLeft, double ptc) async {
if (walletInfo.isRecovery) { if (walletInfo.isRecovery) {
_askForUpdateTransactionHistory(); await _askForUpdateTransactionHistory();
_askForUpdateBalance(); _askForUpdateBalance();
accountList.update();
} }
if (blocksLeft < 100) { if (blocksLeft < 100) {
await _askForUpdateTransactionHistory();
_askForUpdateBalance(); _askForUpdateBalance();
accountList.update();
syncStatus = SyncedSyncStatus(); syncStatus = SyncedSyncStatus();
await _afterSyncSave(); await _afterSyncSave();
if (walletInfo.isRecovery) { if (walletInfo.isRecovery) {
setAsRecovered(); await setAsRecovered();
} }
} else { } else {
syncStatus = SyncingSyncStatus(blocksLeft, ptc); syncStatus = SyncingSyncStatus(blocksLeft, ptc);

View file

@ -4,6 +4,7 @@ import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
import 'package:cake_wallet/src/screens/restore/wallet_restore_page.dart'; import 'package:cake_wallet/src/screens/restore/wallet_restore_page.dart';
import 'package:cake_wallet/src/screens/seed/pre_seed_page.dart'; import 'package:cake_wallet/src/screens/seed/pre_seed_page.dart';
import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
@ -262,7 +263,8 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.accountCreation: case Routes.accountCreation:
return CupertinoPageRoute<String>( return CupertinoPageRoute<String>(
builder: (_) => getIt.get<MoneroAccountEditOrCreatePage>()); builder: (_) => getIt.get<MoneroAccountEditOrCreatePage>(
param1: settings.arguments as AccountListItem));
case Routes.addressBook: case Routes.addressBook:
return MaterialPageRoute<void>( return MaterialPageRoute<void>(

View file

@ -5,6 +5,7 @@ import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/entities/wallet_type.dart'; import 'package:cake_wallet/entities/wallet_type.dart';
import 'package:cake_wallet/src/screens/dashboard/wallet_menu.dart'; import 'package:cake_wallet/src/screens/dashboard/wallet_menu.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
// FIXME: terrible design. // FIXME: terrible design.
@ -147,7 +148,7 @@ class MenuWidgetState extends State<MenuWidget> {
), ),
if (widget.dashboardViewModel.subname != if (widget.dashboardViewModel.subname !=
null) null)
Text( Observer(builder: (_) => Text(
widget.dashboardViewModel.subname, widget.dashboardViewModel.subname,
style: TextStyle( style: TextStyle(
color: Theme.of(context) color: Theme.of(context)
@ -156,7 +157,7 @@ class MenuWidgetState extends State<MenuWidget> {
.decorationColor, .decorationColor,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
fontSize: 12), fontSize: 12),
) ))
], ],
), ),
)) ))

View file

@ -103,7 +103,12 @@ class MoneroAccountListPage extends StatelessWidget {
accountListViewModel accountListViewModel
.select(account); .select(account);
Navigator.of(context).pop(); Navigator.of(context).pop();
}); },
onEdit: () async =>
await Navigator.of(context)
.pushNamed(
Routes.accountCreation,
arguments: account));
}, },
), ),
isAlwaysShowScrollThumb isAlwaysShowScrollThumb

View file

@ -1,15 +1,19 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:cake_wallet/generated/i18n.dart';
class AccountTile extends StatelessWidget { class AccountTile extends StatelessWidget {
AccountTile({ AccountTile({
@required this.isCurrent, @required this.isCurrent,
@required this.accountName, @required this.accountName,
@required this.onTap @required this.onTap,
@required this.onEdit
}); });
final bool isCurrent; final bool isCurrent;
final String accountName; final String accountName;
final VoidCallback onTap; final Function() onTap;
final Function() onEdit;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -20,7 +24,7 @@ class AccountTile extends StatelessWidget {
? Theme.of(context).textTheme.subtitle.color ? Theme.of(context).textTheme.subtitle.color
: Theme.of(context).textTheme.display4.color; : Theme.of(context).textTheme.display4.color;
return GestureDetector( final Widget cell = GestureDetector(
onTap: onTap, onTap: onTap,
child: Container( child: Container(
height: 77, height: 77,
@ -39,5 +43,17 @@ class AccountTile extends StatelessWidget {
), ),
), ),
); );
return isCurrent ? cell : Slidable(
key: Key(accountName),
child: cell,
actionPane: SlidableDrawerActionPane(),
secondaryActions: <Widget>[
IconSlideAction(
caption: S.of(context).edit,
color: Colors.blue,
icon: Icons.edit,
onTap: () => onEdit?.call())
]);
} }
} }

View file

@ -117,7 +117,7 @@ class ReceivePage extends BasePage {
Icons.arrow_forward_ios, Icons.arrow_forward_ios,
size: 14, size: 14,
color: color:
Theme.of(context).textTheme.display1.color, Theme.of(context).textTheme.display1.color,
)); ));
} }
@ -130,7 +130,7 @@ class ReceivePage extends BasePage {
Icons.add, Icons.add,
size: 20, size: 20,
color: color:
Theme.of(context).textTheme.display1.color, Theme.of(context).textTheme.display1.color,
)); ));
} }
@ -140,13 +140,13 @@ class ReceivePage extends BasePage {
addressListViewModel.address.address; addressListViewModel.address.address;
final backgroundColor = isCurrent final backgroundColor = isCurrent
? Theme.of(context) ? Theme.of(context)
.textTheme .textTheme
.display3 .display3
.decorationColor .decorationColor
: Theme.of(context) : Theme.of(context)
.textTheme .textTheme
.display2 .display2
.decorationColor; .decorationColor;
final textColor = isCurrent final textColor = isCurrent
? Theme.of(context).textTheme.display3.color ? Theme.of(context).textTheme.display3.color
: Theme.of(context).textTheme.display2.color; : Theme.of(context).textTheme.display2.color;
@ -155,8 +155,7 @@ class ReceivePage extends BasePage {
isCurrent: isCurrent, isCurrent: isCurrent,
backgroundColor: backgroundColor, backgroundColor: backgroundColor,
textColor: textColor, textColor: textColor,
onTap: (_) => onTap: (_) => addressListViewModel.setAddress(item),
addressListViewModel.setAddress(item),
onEdit: () => Navigator.of(context).pushNamed( onEdit: () => Navigator.of(context).pushNamed(
Routes.newSubaddress, Routes.newSubaddress,
arguments: item)); arguments: item));
@ -166,11 +165,11 @@ class ReceivePage extends BasePage {
return index != 0 return index != 0
? cell ? cell
: ClipRRect( : ClipRRect(
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
topLeft: Radius.circular(30), topLeft: Radius.circular(30),
topRight: Radius.circular(30)), topRight: Radius.circular(30)),
child: cell, child: cell,
); );
})), })),
], ],
), ),

View file

@ -14,6 +14,7 @@ class AddressCell extends StatelessWidget {
address: item.address, address: item.address,
name: item.name, name: item.name,
isCurrent: isCurrent, isCurrent: isCurrent,
isPrimary: item.isPrimary,
backgroundColor: backgroundColor, backgroundColor: backgroundColor,
textColor: textColor, textColor: textColor,
onTap: onTap, onTap: onTap,
@ -23,6 +24,7 @@ class AddressCell extends StatelessWidget {
{@required this.address, {@required this.address,
@required this.name, @required this.name,
@required this.isCurrent, @required this.isCurrent,
@required this.isPrimary,
@required this.backgroundColor, @required this.backgroundColor,
@required this.textColor, @required this.textColor,
this.onTap, this.onTap,
@ -31,6 +33,7 @@ class AddressCell extends StatelessWidget {
final String address; final String address;
final String name; final String name;
final bool isCurrent; final bool isCurrent;
final bool isPrimary;
final Color backgroundColor; final Color backgroundColor;
final Color textColor; final Color textColor;
final Function(String) onTap; final Function(String) onTap;
@ -56,7 +59,7 @@ class AddressCell extends StatelessWidget {
), ),
)); ));
return isCurrent return (isCurrent || isPrimary)
? cell ? cell
: Slidable( : Slidable(
key: Key(address), key: Key(address),

View file

@ -1,5 +1,10 @@
import 'package:cake_wallet/bitcoin/bitcoin_transaction_info.dart'; import 'package:cake_wallet/bitcoin/bitcoin_transaction_info.dart';
import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart'; import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart';
import 'package:cake_wallet/entities/transaction_history.dart';
import 'package:cake_wallet/monero/account.dart';
import 'package:cake_wallet/monero/monero_balance.dart';
import 'package:cake_wallet/monero/monero_transaction_history.dart';
import 'package:cake_wallet/monero/monero_transaction_info.dart';
import 'package:cake_wallet/monero/monero_wallet.dart'; import 'package:cake_wallet/monero/monero_wallet.dart';
import 'package:cake_wallet/entities/balance_display_mode.dart'; import 'package:cake_wallet/entities/balance_display_mode.dart';
import 'package:cake_wallet/entities/crypto_currency.dart'; import 'package:cake_wallet/entities/crypto_currency.dart';
@ -74,27 +79,45 @@ abstract class DashboardViewModelBase with Store {
wallet ??= appStore.wallet; wallet ??= appStore.wallet;
type = wallet.type; type = wallet.type;
transactions = ObservableList.of(wallet
.transactionHistory.transactions.values
.map((transaction) => TransactionListItem(
transaction: transaction,
balanceViewModel: balanceViewModel,
settingsStore: appStore.settingsStore)));
_reaction = reaction((_) => appStore.wallet, _onWalletChange); _reaction = reaction((_) => appStore.wallet, _onWalletChange);
// FIXME: fixme
connectMapToListWithTransform(
appStore.wallet.transactionHistory.transactions,
transactions,
(TransactionInfo val) => TransactionListItem(
transaction: val,
balanceViewModel: balanceViewModel,
settingsStore: appStore.settingsStore));
final _wallet = wallet; final _wallet = wallet;
if (_wallet is MoneroWallet) { if (_wallet is MoneroWallet) {
subname = _wallet.account?.label; subname = _wallet.account?.label;
_onMoneroAccountChangeReaction = reaction((_) => _wallet.account,
(Account account) => _onMoneroAccountChange(_wallet));
_onMoneroBalanceChangeReaction = reaction((_) =>
_wallet.balance, (MoneroBalance balance) =>
_onMoneroTransactionsUpdate(_wallet));
final _accountTransactions = _wallet
.transactionHistory.transactions.values
.where((tx) => tx.accountIndex == _wallet.account.id).toList();
transactions = ObservableList.of(_accountTransactions
.map((transaction) => TransactionListItem(
transaction: transaction,
balanceViewModel: balanceViewModel,
settingsStore: appStore.settingsStore)));
} else {
transactions = ObservableList.of(wallet
.transactionHistory.transactions.values
.map((transaction) => TransactionListItem(
transaction: transaction,
balanceViewModel: balanceViewModel,
settingsStore: appStore.settingsStore)));
// FIXME: fixme
connectMapToListWithTransform(
appStore.wallet.transactionHistory.transactions,
transactions,
(TransactionInfo val) => TransactionListItem(
transaction: val,
balanceViewModel: balanceViewModel,
settingsStore: appStore.settingsStore));
} }
} }
@ -170,6 +193,10 @@ abstract class DashboardViewModelBase with Store {
ReactionDisposer _reaction; ReactionDisposer _reaction;
ReactionDisposer _onMoneroAccountChangeReaction;
ReactionDisposer _onMoneroBalanceChangeReaction;
Future<void> reconnect() async { Future<void> reconnect() async {
final node = appStore.settingsStore.getCurrentNode(wallet.type); final node = appStore.settingsStore.getCurrentNode(wallet.type);
await wallet.connectToNode(node: node); await wallet.connectToNode(node: node);
@ -179,11 +206,50 @@ abstract class DashboardViewModelBase with Store {
void _onWalletChange(WalletBase wallet) { void _onWalletChange(WalletBase wallet) {
this.wallet = wallet; this.wallet = wallet;
name = wallet.name; name = wallet.name;
if (wallet is MoneroWallet) {
subname = wallet.account?.label;
_onMoneroAccountChangeReaction?.reaction?.dispose();
_onMoneroBalanceChangeReaction?.reaction?.dispose();
_onMoneroAccountChangeReaction = reaction((_) => wallet.account,
(Account account) => _onMoneroAccountChange(wallet));
_onMoneroBalanceChangeReaction = reaction((_) =>
wallet.balance, (MoneroBalance balance) =>
_onMoneroTransactionsUpdate(wallet));
_onMoneroTransactionsUpdate(wallet);
} else {
transactions.clear();
transactions.addAll(wallet.transactionHistory.transactions.values.map(
(transaction) => TransactionListItem(
transaction: transaction,
balanceViewModel: balanceViewModel,
settingsStore: appStore.settingsStore)));
}
}
@action
void _onMoneroAccountChange(MoneroWallet wallet) {
subname = wallet.account?.label;
_onMoneroTransactionsUpdate(wallet);
}
@action
void _onMoneroTransactionsUpdate(MoneroWallet wallet) {
transactions.clear(); transactions.clear();
transactions.addAll(wallet.transactionHistory.transactions.values.map(
(transaction) => TransactionListItem( final _accountTransactions = wallet
transaction: transaction, .transactionHistory.transactions.values
balanceViewModel: balanceViewModel, .where((tx) => tx.accountIndex == wallet.account.id).toList();
settingsStore: appStore.settingsStore)));
transactions.addAll(_accountTransactions
.map((transaction) => TransactionListItem(
transaction: transaction,
balanceViewModel: balanceViewModel,
settingsStore: appStore.settingsStore)));
} }
} }

View file

@ -13,6 +13,7 @@ abstract class MoneroAccountEditOrCreateViewModelBase with Store {
{AccountListItem accountListItem}) {AccountListItem accountListItem})
: state = InitialExecutionState(), : state = InitialExecutionState(),
isEdit = accountListItem != null, isEdit = accountListItem != null,
label = accountListItem?.label??'',
_accountListItem = accountListItem; _accountListItem = accountListItem;
final bool isEdit; final bool isEdit;

View file

@ -2,10 +2,11 @@ import 'package:flutter/foundation.dart';
import 'package:cake_wallet/utils/list_item.dart'; import 'package:cake_wallet/utils/list_item.dart';
class WalletAddressListItem extends ListItem { class WalletAddressListItem extends ListItem {
const WalletAddressListItem({@required this.address, this.name, this.id}) const WalletAddressListItem({@required this.address, @required this.isPrimary,
: super(); this.name, this.id}) : super();
final int id; final int id;
final bool isPrimary;
final String address; final String address;
final String name; final String name;

View file

@ -97,16 +97,28 @@ abstract class WalletAddressListViewModelBase with Store {
final addressList = ObservableList<ListItem>(); final addressList = ObservableList<ListItem>();
if (wallet is MoneroWallet) { if (wallet is MoneroWallet) {
addressList.addAll(wallet.subaddressList.subaddresses.map((subaddress) => final primaryAddress = wallet.subaddressList.subaddresses.first;
WalletAddressListItem( addressList.addAll(wallet.subaddressList.subaddresses.map((subaddress) {
id: subaddress.id, final isPrimary = subaddress == primaryAddress;
name: subaddress.label,
address: subaddress.address))); return WalletAddressListItem(
id: subaddress.id,
isPrimary: isPrimary,
name: subaddress.label,
address: subaddress.address);
}));
} }
if (wallet is BitcoinWallet) { if (wallet is BitcoinWallet) {
final bitcoinAddresses = wallet.addresses.map((addr) => final primaryAddress = wallet.addresses.first;
WalletAddressListItem(name: addr.label, address: addr.address)); final bitcoinAddresses = wallet.addresses.map((addr) {
final isPrimary = addr == primaryAddress;
return WalletAddressListItem(
isPrimary: isPrimary,
name: addr.label,
address: addr.address);
});
addressList.addAll(bitcoinAddresses); addressList.addAll(bitcoinAddresses);
} }