From 23abacd2526c9d898422de3abc055f89fd9070bb Mon Sep 17 00:00:00 2001
From: OleksandrSobol <dr.alexander.sobol@gmail.com>
Date: Tue, 17 Nov 2020 20:16:58 +0200
Subject: [PATCH] CAKE-158 | made account tile slidable; added onEdit function
 to account tile; added ability to edit wallet account name; added
 isFirstAddress parameter to wallet_address_list_view_model.dart and made
 first address in the address list not editable (receive page); wrapped wallet
 account name in the wallet menu title by observer; added
 _moneroTransactionsChangeReaction to dashboard_view_model.dart

---
 lib/core/monero_account_label_validator.dart  |  2 +-
 lib/di.dart                                   | 18 ++++++++--
 lib/router.dart                               |  4 ++-
 .../dashboard/widgets/menu_widget.dart        |  5 +--
 .../monero_account_list_page.dart             |  7 +++-
 .../monero_accounts/widgets/account_tile.dart | 22 ++++++++++--
 lib/src/screens/receive/receive_page.dart     |  3 ++
 .../screens/receive/widgets/address_cell.dart |  6 +++-
 .../dashboard/dashboard_view_model.dart       | 36 +++++++++++++++++++
 ...ero_account_edit_or_create_view_model.dart |  1 +
 .../wallet_address_list_view_model.dart       |  4 +++
 11 files changed, 97 insertions(+), 11 deletions(-)

diff --git a/lib/core/monero_account_label_validator.dart b/lib/core/monero_account_label_validator.dart
index dcbac668f..2bc0fcccc 100644
--- a/lib/core/monero_account_label_validator.dart
+++ b/lib/core/monero_account_label_validator.dart
@@ -7,7 +7,7 @@ class MoneroLabelValidator extends TextValidator {
   MoneroLabelValidator({@required CryptoCurrency type})
       : super(
       errorMessage: S.current.error_text_account_name,
-      pattern: '^[a-zA-Z0-9_]{1,15}\$',
+      pattern: '^[a-zA-Z0-9_ ]{1,15}\$',
       minLength: 1,
       maxLength: 15);
 }
diff --git a/lib/di.dart b/lib/di.dart
index 1dba56bc1..f7e6fe3b6 100644
--- a/lib/di.dart
+++ b/lib/di.dart
@@ -48,6 +48,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_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_create_or_edit_view_model.dart';
 import 'package:cake_wallet/view_model/rescan_view_model.dart';
@@ -272,7 +273,7 @@ Future setup(
   getIt.registerFactory(() => MoneroAccountListPage(
       accountListViewModel: getIt.get<MoneroAccountListViewModel>()));
 
-  getIt.registerFactory(() {
+  /*getIt.registerFactory(() {
     final wallet = getIt.get<AppStore>().wallet;
 
     if (wallet is MoneroWallet) {
@@ -285,7 +286,20 @@ Future setup(
 
   getIt.registerFactory(() => MoneroAccountEditOrCreatePage(
       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(() {
     final appStore = getIt.get<AppStore>();
diff --git a/lib/router.dart b/lib/router.dart
index acad61d04..2d7877d0b 100644
--- a/lib/router.dart
+++ b/lib/router.dart
@@ -3,6 +3,7 @@ import 'package:cake_wallet/entities/transaction_description.dart';
 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/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/material.dart';
 import 'package:cake_wallet/routes.dart';
@@ -261,7 +262,8 @@ Route<dynamic> createRoute(RouteSettings settings) {
 
     case Routes.accountCreation:
       return CupertinoPageRoute<String>(
-          builder: (_) => getIt.get<MoneroAccountEditOrCreatePage>());
+          builder: (_) => getIt.get<MoneroAccountEditOrCreatePage>(
+            param1: settings.arguments as AccountListItem));
 
     case Routes.addressBook:
       return MaterialPageRoute<void>(
diff --git a/lib/src/screens/dashboard/widgets/menu_widget.dart b/lib/src/screens/dashboard/widgets/menu_widget.dart
index 7701d0ad3..f8de5ba8d 100644
--- a/lib/src/screens/dashboard/widgets/menu_widget.dart
+++ b/lib/src/screens/dashboard/widgets/menu_widget.dart
@@ -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/src/screens/dashboard/wallet_menu.dart';
 import 'package:flutter/rendering.dart';
+import 'package:flutter_mobx/flutter_mobx.dart';
 
 // FIXME: terrible design.
 
@@ -147,7 +148,7 @@ class MenuWidgetState extends State<MenuWidget> {
                                       ),
                                       if (widget.dashboardViewModel.subname !=
                                           null)
-                                        Text(
+                                        Observer(builder: (_) => Text(
                                           widget.dashboardViewModel.subname,
                                           style: TextStyle(
                                               color: Theme.of(context)
@@ -156,7 +157,7 @@ class MenuWidgetState extends State<MenuWidget> {
                                                   .decorationColor,
                                               fontWeight: FontWeight.w500,
                                               fontSize: 12),
-                                        )
+                                        ))
                                     ],
                                   ),
                                 ))
diff --git a/lib/src/screens/monero_accounts/monero_account_list_page.dart b/lib/src/screens/monero_accounts/monero_account_list_page.dart
index 623f3cb90..47404e443 100644
--- a/lib/src/screens/monero_accounts/monero_account_list_page.dart
+++ b/lib/src/screens/monero_accounts/monero_account_list_page.dart
@@ -103,7 +103,12 @@ class MoneroAccountListPage extends StatelessWidget {
                                                   accountListViewModel
                                                       .select(account);
                                                   Navigator.of(context).pop();
-                                                });
+                                                },
+                                                onEdit: () async =>
+                                                await Navigator.of(context)
+                                                    .pushNamed(
+                                                    Routes.accountCreation,
+                                                    arguments: account));
                                           },
                                         ),
                                         isAlwaysShowScrollThumb
diff --git a/lib/src/screens/monero_accounts/widgets/account_tile.dart b/lib/src/screens/monero_accounts/widgets/account_tile.dart
index eb9c7f25d..f07539333 100644
--- a/lib/src/screens/monero_accounts/widgets/account_tile.dart
+++ b/lib/src/screens/monero_accounts/widgets/account_tile.dart
@@ -1,15 +1,19 @@
 import 'package:flutter/material.dart';
+import 'package:flutter_slidable/flutter_slidable.dart';
+import 'package:cake_wallet/generated/i18n.dart';
 
 class AccountTile extends StatelessWidget {
   AccountTile({
     @required this.isCurrent,
     @required this.accountName,
-    @required this.onTap
+    @required this.onTap,
+    @required this.onEdit
   });
 
   final bool isCurrent;
   final String accountName;
-  final VoidCallback onTap;
+  final Function() onTap;
+  final Function() onEdit;
 
   @override
   Widget build(BuildContext context) {
@@ -20,7 +24,7 @@ class AccountTile extends StatelessWidget {
         ? Theme.of(context).textTheme.subtitle.color
         : Theme.of(context).textTheme.display4.color;
 
-    return GestureDetector(
+    final Widget cell = GestureDetector(
       onTap: onTap,
       child: Container(
         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())
+        ]);
   }
 }
\ No newline at end of file
diff --git a/lib/src/screens/receive/receive_page.dart b/lib/src/screens/receive/receive_page.dart
index 1ac4a073b..202784ee8 100644
--- a/lib/src/screens/receive/receive_page.dart
+++ b/lib/src/screens/receive/receive_page.dart
@@ -116,6 +116,8 @@ class ReceivePage extends BasePage {
                     }
 
                     if (item is WalletAddressListItem) {
+                      final isFirst = addressListViewModel.isFirstAddress;
+                      addressListViewModel.isFirstAddress = false;
                       cell = Observer(builder: (_) {
                         final isCurrent = item.address ==
                             addressListViewModel.address.address;
@@ -134,6 +136,7 @@ class ReceivePage extends BasePage {
 
                         return AddressCell.fromItem(item,
                             isCurrent: isCurrent,
+                            isFirstAddress: isFirst,
                             backgroundColor: backgroundColor,
                             textColor: textColor,
                             onTap: (_) => addressListViewModel.setAddress(item),
diff --git a/lib/src/screens/receive/widgets/address_cell.dart b/lib/src/screens/receive/widgets/address_cell.dart
index 6306ae209..cfc63a242 100644
--- a/lib/src/screens/receive/widgets/address_cell.dart
+++ b/lib/src/screens/receive/widgets/address_cell.dart
@@ -6,6 +6,7 @@ import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_i
 class AddressCell extends StatelessWidget {
   factory AddressCell.fromItem(WalletAddressListItem item,
           {@required bool isCurrent,
+          @required bool isFirstAddress,
           @required Color backgroundColor,
           @required Color textColor,
           Function(String) onTap,
@@ -14,6 +15,7 @@ class AddressCell extends StatelessWidget {
           address: item.address,
           name: item.name,
           isCurrent: isCurrent,
+          isFirstAddress: isFirstAddress,
           backgroundColor: backgroundColor,
           textColor: textColor,
           onTap: onTap,
@@ -23,6 +25,7 @@ class AddressCell extends StatelessWidget {
       {@required this.address,
       @required this.name,
       @required this.isCurrent,
+      @required this.isFirstAddress,
       @required this.backgroundColor,
       @required this.textColor,
       this.onTap,
@@ -31,6 +34,7 @@ class AddressCell extends StatelessWidget {
   final String address;
   final String name;
   final bool isCurrent;
+  final bool isFirstAddress;
   final Color backgroundColor;
   final Color textColor;
   final Function(String) onTap;
@@ -56,7 +60,7 @@ class AddressCell extends StatelessWidget {
           ),
         ));
 
-    return isCurrent
+    return (isCurrent || isFirstAddress)
         ? cell
         : Slidable(
             key: Key(address),
diff --git a/lib/view_model/dashboard/dashboard_view_model.dart b/lib/view_model/dashboard/dashboard_view_model.dart
index 62742d848..189c3ea32 100644
--- a/lib/view_model/dashboard/dashboard_view_model.dart
+++ b/lib/view_model/dashboard/dashboard_view_model.dart
@@ -1,6 +1,8 @@
 import 'package:cake_wallet/bitcoin/bitcoin_transaction_info.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_transaction_history.dart';
 import 'package:cake_wallet/monero/monero_wallet.dart';
 import 'package:cake_wallet/entities/balance_display_mode.dart';
 import 'package:cake_wallet/entities/crypto_currency.dart';
@@ -85,6 +87,10 @@ abstract class DashboardViewModelBase with Store {
       _onMoneroAccountChangeReaction = reaction((_) => _wallet.account,
               (Account account) => _onMoneroAccountChange(_wallet));
 
+      _onMoneroTransactionsChangeReaction = reaction((_) => _wallet.transactionHistory,
+              (MoneroTransactionHistory transactionHistory) =>
+                  _onMoneroTransactionsChange(_wallet));
+
       final _accountTransactions = _wallet
           .transactionHistory.transactions.values
           .where((tx) => tx.accountIndex == _wallet.account.id).toList();
@@ -187,6 +193,8 @@ abstract class DashboardViewModelBase with Store {
 
   ReactionDisposer _onMoneroAccountChangeReaction;
 
+  ReactionDisposer _onMoneroTransactionsChangeReaction;
+
   Future<void> reconnect() async {
     final node = appStore.settingsStore.getCurrentNode(wallet.type);
     await wallet.connectToNode(node: node);
@@ -199,6 +207,18 @@ abstract class DashboardViewModelBase with Store {
     transactions.clear();
 
     if (wallet is MoneroWallet) {
+      subname = wallet.account?.label;
+
+      _onMoneroAccountChangeReaction?.reaction?.dispose();
+      _onMoneroTransactionsChangeReaction?.reaction?.dispose();
+
+      _onMoneroAccountChangeReaction = reaction((_) => wallet.account,
+              (Account account) => _onMoneroAccountChange(wallet));
+
+      _onMoneroTransactionsChangeReaction = reaction((_) => wallet.transactionHistory,
+              (MoneroTransactionHistory transactionHistory) =>
+              _onMoneroTransactionsChange(wallet));
+
       final _accountTransactions = wallet
           .transactionHistory.transactions.values
           .where((tx) => tx.accountIndex == wallet.account.id).toList();
@@ -219,6 +239,22 @@ abstract class DashboardViewModelBase with Store {
 
   @action
   void _onMoneroAccountChange(MoneroWallet wallet) {
+    subname = wallet.account?.label;
+    transactions.clear();
+
+    final _accountTransactions = wallet
+        .transactionHistory.transactions.values
+        .where((tx) => tx.accountIndex == wallet.account.id).toList();
+
+    transactions.addAll(_accountTransactions
+        .map((transaction) => TransactionListItem(
+        transaction: transaction,
+        balanceViewModel: balanceViewModel,
+        settingsStore: appStore.settingsStore)));
+  }
+
+  @action
+  void _onMoneroTransactionsChange(MoneroWallet wallet) {
     transactions.clear();
 
     final _accountTransactions = wallet
diff --git a/lib/view_model/monero_account_list/monero_account_edit_or_create_view_model.dart b/lib/view_model/monero_account_list/monero_account_edit_or_create_view_model.dart
index 33e9dd1e5..d32f8eadd 100644
--- a/lib/view_model/monero_account_list/monero_account_edit_or_create_view_model.dart
+++ b/lib/view_model/monero_account_list/monero_account_edit_or_create_view_model.dart
@@ -13,6 +13,7 @@ abstract class MoneroAccountEditOrCreateViewModelBase with Store {
       {AccountListItem accountListItem})
       : state = InitialExecutionState(),
         isEdit = accountListItem != null,
+        label = accountListItem?.label??'',
         _accountListItem = accountListItem;
 
   final bool isEdit;
diff --git a/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart b/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart
index e8c897bfc..de8ba1e9e 100644
--- a/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart
+++ b/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart
@@ -67,6 +67,9 @@ abstract class WalletAddressListViewModelBase with Store {
   @observable
   String amount;
 
+  @observable
+  bool isFirstAddress;
+
   @computed
   WalletType get type => _wallet.type;
 
@@ -97,6 +100,7 @@ abstract class WalletAddressListViewModelBase with Store {
     final addressList = ObservableList<ListItem>();
 
     if (wallet is MoneroWallet) {
+      isFirstAddress = true;
       addressList.addAll(wallet.subaddressList.subaddresses.map((subaddress) =>
           WalletAddressListItem(
               id: subaddress.id,