From 8f54e539187be05fc42a43b2ef09c603b226d207 Mon Sep 17 00:00:00 2001 From: Oleksandr Sobol Date: Mon, 4 May 2020 23:12:36 +0300 Subject: [PATCH] CWA-202 | applied new design to nodes_list_page and new_node_page; created node_list_row widget, alert_with_one_action and alert_with_two_action; deleted reconnect_alert_dialog, wallet_creation_dialog, restore_alert_dialog and pin_alert_dialog --- lib/generated/i18n.dart | 23 ++ lib/src/screens/dashboard/wallet_menu.dart | 24 +- .../widgets/reconnect_alert_dialog.dart | 34 -- .../screens/new_wallet/new_wallet_page.dart | 12 +- .../widgets/wallet_creation_dialog.dart | 56 --- lib/src/screens/nodes/new_node_page.dart | 315 +++++++++------- lib/src/screens/nodes/nodes_list_page.dart | 350 +++++++++--------- .../nodes/{ => widgets}/node_indicator.dart | 4 +- .../screens/nodes/widgets/node_list_row.dart | 63 ++++ .../restore_wallet_from_keys_page.dart | 12 +- .../restore_wallet_from_seed_details.dart | 12 +- .../setup_pin_code/setup_pin_code.dart | 29 +- .../widgets/pin_alert_dialog.dart | 60 --- lib/src/stores/node_list/node_list_store.dart | 9 + .../alert_with_one_action.dart} | 34 +- lib/src/widgets/alert_with_two_actions.dart | 38 ++ lib/src/widgets/base_alert_dialog.dart | 1 - res/values/strings_de.arb | 1 + res/values/strings_en.arb | 1 + res/values/strings_es.arb | 1 + res/values/strings_hi.arb | 1 + res/values/strings_ja.arb | 1 + res/values/strings_ko.arb | 1 + res/values/strings_nl.arb | 1 + res/values/strings_pl.arb | 1 + res/values/strings_pt.arb | 1 + res/values/strings_ru.arb | 1 + res/values/strings_uk.arb | 1 + res/values/strings_zh.arb | 1 + 29 files changed, 549 insertions(+), 539 deletions(-) delete mode 100644 lib/src/screens/dashboard/widgets/reconnect_alert_dialog.dart delete mode 100644 lib/src/screens/new_wallet/widgets/wallet_creation_dialog.dart rename lib/src/screens/nodes/{ => widgets}/node_indicator.dart (90%) create mode 100644 lib/src/screens/nodes/widgets/node_list_row.dart delete mode 100644 lib/src/screens/setup_pin_code/widgets/pin_alert_dialog.dart rename lib/src/{screens/restore/widgets/restore_alert_dialog.dart => widgets/alert_with_one_action.dart} (62%) create mode 100644 lib/src/widgets/alert_with_two_actions.dart diff --git a/lib/generated/i18n.dart b/lib/generated/i18n.dart index d61bfec90..a6c0227d3 100644 --- a/lib/generated/i18n.dart +++ b/lib/generated/i18n.dart @@ -24,6 +24,7 @@ class S implements WidgetsLocalizations { String get account => "Account"; String get accounts => "Accounts"; String get add => "Add"; + String get add_new_node => "Add new node"; String get add_new_word => "Add new word"; String get address_book => "Address Book"; String get address_book_menu => "Address book"; @@ -519,6 +520,8 @@ class $de extends S { @override String get remove => "Löschen"; @override + String get add_new_node => "Neuen Knoten hinzufügen"; + @override String get yesterday => "Gestern"; @override String get expired => "Abgelaufen"; @@ -1101,6 +1104,8 @@ class $hi extends S { @override String get remove => "हटाना"; @override + String get add_new_node => "नया नोड जोड़ें"; + @override String get yesterday => "बिता कल"; @override String get expired => "समय सीमा समाप्त"; @@ -1683,6 +1688,8 @@ class $ru extends S { @override String get remove => "Удалить"; @override + String get add_new_node => "Добавить новую ноду"; + @override String get yesterday => "Вчера"; @override String get expired => "Истекает"; @@ -2265,6 +2272,8 @@ class $ko extends S { @override String get remove => "없애다"; @override + String get add_new_node => "새 노드 추가"; + @override String get yesterday => "어제"; @override String get expired => "만료"; @@ -2847,6 +2856,8 @@ class $pt extends S { @override String get remove => "Remover"; @override + String get add_new_node => "Adicionar novo nó"; + @override String get yesterday => "Ontem"; @override String get expired => "Expirada"; @@ -3429,6 +3440,8 @@ class $uk extends S { @override String get remove => "Видалити"; @override + String get add_new_node => "Додати новий вузол"; + @override String get yesterday => "Вчора"; @override String get expired => "Закінчується"; @@ -4011,6 +4024,8 @@ class $ja extends S { @override String get remove => "削除する"; @override + String get add_new_node => "新しいノードを追加"; + @override String get yesterday => "昨日"; @override String get expired => "期限切れ"; @@ -4597,6 +4612,8 @@ class $pl extends S { @override String get remove => "Usunąć"; @override + String get add_new_node => "Dodaj nowy węzeł"; + @override String get yesterday => "Wczoraj"; @override String get expired => "Przedawniony"; @@ -5179,6 +5196,8 @@ class $es extends S { @override String get remove => "Retirar"; @override + String get add_new_node => "Agregar nuevo nodo"; + @override String get yesterday => "Ayer"; @override String get expired => "Muerto"; @@ -5761,6 +5780,8 @@ class $nl extends S { @override String get remove => "Verwijderen"; @override + String get add_new_node => "Voeg een nieuw knooppunt toe"; + @override String get yesterday => "Gisteren"; @override String get expired => "Verlopen"; @@ -6343,6 +6364,8 @@ class $zh extends S { @override String get remove => "去掉"; @override + String get add_new_node => "添加新節點"; + @override String get yesterday => "昨天"; @override String get expired => "已过期"; diff --git a/lib/src/screens/dashboard/wallet_menu.dart b/lib/src/screens/dashboard/wallet_menu.dart index e3402bdb9..2190a8d34 100644 --- a/lib/src/screens/dashboard/wallet_menu.dart +++ b/lib/src/screens/dashboard/wallet_menu.dart @@ -4,7 +4,7 @@ import 'package:provider/provider.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/stores/wallet/wallet_store.dart'; import 'package:cake_wallet/src/screens/auth/auth_page.dart'; -import 'package:cake_wallet/src/screens/dashboard/widgets/reconnect_alert_dialog.dart'; +import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; class WalletMenu { WalletMenu(this.context); @@ -40,7 +40,7 @@ class WalletMenu { Navigator.of(context).pushNamed(Routes.walletList); break; case 2: - // FIXME: apply Nodes + Navigator.of(context).pushNamed(Routes.nodeList); break; case 3: Navigator.of(context).pushNamed(Routes.auth, @@ -75,16 +75,16 @@ class WalletMenu { await showDialog( context: context, builder: (BuildContext context) { - return ReconnectAlertDialog( - reconnectTitleText: S.of(context).reconnection, - reconnectContentText: S.of(context).reconnect_alert_text, - reconnectLeftActionButtonText: S.of(context).ok, - reconnectRightActionButtonText: S.of(context).cancel, - reconnectActionLeft: () { - walletStore.reconnect(); - Navigator.of(context).pop(); - }, - reconnectActionRight: () => Navigator.of(context).pop() + return AlertWithTwoActions( + alertTitle: S.of(context).reconnection, + alertContent: S.of(context).reconnect_alert_text, + leftButtonText: S.of(context).ok, + rightButtonText: S.of(context).cancel, + actionLeftButton: () { + walletStore.reconnect(); + Navigator.of(context).pop(); + }, + actionRightButton: () => Navigator.of(context).pop() ); }); } diff --git a/lib/src/screens/dashboard/widgets/reconnect_alert_dialog.dart b/lib/src/screens/dashboard/widgets/reconnect_alert_dialog.dart deleted file mode 100644 index 65ebf8829..000000000 --- a/lib/src/screens/dashboard/widgets/reconnect_alert_dialog.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'dart:ui'; -import 'package:cake_wallet/src/widgets/base_alert_dialog.dart'; -import 'package:flutter/cupertino.dart'; - -class ReconnectAlertDialog extends BaseAlertDialog { - ReconnectAlertDialog({ - @required this.reconnectTitleText, - @required this.reconnectContentText, - @required this.reconnectLeftActionButtonText, - @required this.reconnectRightActionButtonText, - @required this.reconnectActionLeft, - @required this.reconnectActionRight - }); - - final String reconnectTitleText; - final String reconnectContentText; - final String reconnectLeftActionButtonText; - final String reconnectRightActionButtonText; - final VoidCallback reconnectActionLeft; - final VoidCallback reconnectActionRight; - - @override - String get titleText => reconnectTitleText; - @override - String get contentText => reconnectContentText; - @override - String get leftActionButtonText => reconnectLeftActionButtonText; - @override - String get rightActionButtonText => reconnectRightActionButtonText; - @override - VoidCallback get actionLeft => reconnectActionLeft; - @override - VoidCallback get actionRight => reconnectActionRight; -} \ No newline at end of file diff --git a/lib/src/screens/new_wallet/new_wallet_page.dart b/lib/src/screens/new_wallet/new_wallet_page.dart index 507fb610b..306164430 100644 --- a/lib/src/screens/new_wallet/new_wallet_page.dart +++ b/lib/src/screens/new_wallet/new_wallet_page.dart @@ -16,7 +16,7 @@ import 'package:cake_wallet/palette.dart'; import 'package:cake_wallet/src/stores/seed_language/seed_language_store.dart'; import 'package:cake_wallet/src/screens/new_wallet/widgets/select_button.dart'; import 'package:cake_wallet/src/screens/seed_language/widgets/seed_language_picker.dart'; -import 'package:cake_wallet/src/screens/new_wallet/widgets/wallet_creation_dialog.dart'; +import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; class NewWalletPage extends BasePage { NewWalletPage( @@ -90,11 +90,11 @@ class _WalletNameFormState extends State { showDialog( context: context, builder: (_) { - return WalletCreationDialog( - dialogTitle: S.current.new_wallet, - dialogContent: state.error, - dialogButtonText: S.of(context).ok, - dialogButtonAction: () => Navigator.of(context).pop() + return AlertWithOneAction( + alertTitle: S.current.new_wallet, + alertContent: state.error, + buttonText: S.of(context).ok, + buttonAction: () => Navigator.of(context).pop() ); }); }); diff --git a/lib/src/screens/new_wallet/widgets/wallet_creation_dialog.dart b/lib/src/screens/new_wallet/widgets/wallet_creation_dialog.dart deleted file mode 100644 index c1d464ebe..000000000 --- a/lib/src/screens/new_wallet/widgets/wallet_creation_dialog.dart +++ /dev/null @@ -1,56 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:cake_wallet/src/widgets/base_alert_dialog.dart'; - -class WalletCreationDialog extends BaseAlertDialog { - WalletCreationDialog({ - @required this.dialogTitle, - @required this.dialogContent, - @required this.dialogButtonText, - @required this.dialogButtonAction, - }); - - final String dialogTitle; - final String dialogContent; - final String dialogButtonText; - final VoidCallback dialogButtonAction; - - @override - String get titleText => dialogTitle; - - @override - String get contentText => dialogContent; - - @override - Widget actionButtons(BuildContext context) { - return Container( - width: 300, - height: 52, - padding: EdgeInsets.only(left: 12, right: 12), - decoration: BoxDecoration( - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(24), - bottomRight: Radius.circular(24) - ), - color: Colors.white - ), - child: ButtonTheme( - minWidth: double.infinity, - child: FlatButton( - onPressed: dialogButtonAction, - highlightColor: Colors.transparent, - splashColor: Colors.transparent, - child: Text( - dialogButtonText, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.w600, - color: Colors.blue, - decoration: TextDecoration.none, - ), - )), - ), - ); - } - -} \ No newline at end of file diff --git a/lib/src/screens/nodes/new_node_page.dart b/lib/src/screens/nodes/new_node_page.dart index f3b9b26f9..9f609f698 100644 --- a/lib/src/screens/nodes/new_node_page.dart +++ b/lib/src/screens/nodes/new_node_page.dart @@ -1,16 +1,21 @@ import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:provider/provider.dart'; import 'package:cake_wallet/palette.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/stores/node_list/node_list_store.dart'; import 'package:cake_wallet/src/widgets/primary_button.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; class NewNodePage extends BasePage { @override String get title => S.current.node_new; + @override + Color get backgroundColor => PaletteDark.historyPanel; + @override Widget body(BuildContext context) => NewNodePageForm(); } @@ -36,130 +41,167 @@ class NewNodeFormState extends State { super.dispose(); } + void onHandleControllers(NodeListStore nodeListStore) { + if (_nodeAddressController.text.isNotEmpty && + _nodePortController.text.isNotEmpty) { + nodeListStore.setDisabledState(false); + } else { + nodeListStore.setDisabledState(true); + } + } + @override Widget build(BuildContext context) { final nodeList = Provider.of(context); - return Form( - key: _formKey, - child: Column( - children: [ - Expanded( - child: Container( - padding: EdgeInsets.only(left: 38.0, right: 38.0, top: 0), - child: Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Row( - children: [ - Expanded( - child: TextFormField( - style: TextStyle(fontSize: 14.0), - decoration: InputDecoration( - hintStyle: - TextStyle(color: Palette.wildDarkBlue), - hintText: S.of(context).node_address, - focusedBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: Palette.cakeGreen, width: 2.0)), - enabledBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: Theme.of(context).focusColor, - width: 1.0))), - controller: _nodeAddressController, - validator: (value) { - nodeList.validateNodeAddress(value); - return nodeList.errorMessage; - }, - ), - ) - ], - ), - SizedBox(height: 10.0), - Row( - children: [ - Expanded( - child: TextFormField( - style: TextStyle(fontSize: 14.0), - keyboardType: TextInputType.numberWithOptions( - signed: false, decimal: false), - decoration: InputDecoration( - hintStyle: - TextStyle(color: Palette.wildDarkBlue), - hintText: S.of(context).node_port, - focusedBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: Palette.cakeGreen, width: 2.0)), - enabledBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: Theme.of(context).focusColor, - width: 1.0))), - controller: _nodePortController, - validator: (value) { - nodeList.validateNodePort(value); - return nodeList.errorMessage; - }, - ), - ) - ], - ), - SizedBox(height: 10.0), - Row( - children: [ - Expanded( - child: TextFormField( - style: TextStyle(fontSize: 14.0), - decoration: InputDecoration( - hintStyle: - TextStyle(color: Palette.wildDarkBlue), - hintText: S.of(context).login, - focusedBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: Palette.cakeGreen, width: 2.0)), - enabledBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: Theme.of(context).focusColor, - width: 1.0))), - controller: _loginController, - validator: (value) => null, - ), - ) - ], - ), - SizedBox(height: 10.0), - Row( - children: [ - Expanded( - child: TextFormField( - style: TextStyle(fontSize: 14.0), - decoration: InputDecoration( - hintStyle: - TextStyle(color: Palette.wildDarkBlue), - hintText: S.of(context).password, - focusedBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: Palette.cakeGreen, width: 2.0)), - enabledBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: Theme.of(context).focusColor, - width: 1.0))), - controller: _passwordController, - validator: (value) => null, - ), - ) - ], - ) - ], - ), - ), - )), - Container( - padding: EdgeInsets.only(bottom: 20.0, left: 20.0, right: 20.0), - child: Row( + _nodeAddressController.addListener(() {onHandleControllers(nodeList);}); + _nodePortController.addListener(() {onHandleControllers(nodeList);}); + + return Container( + color: PaletteDark.historyPanel, + padding: EdgeInsets.only(left: 24, right: 24), + child: ScrollableWithBottomSection( + contentPadding: EdgeInsets.only(bottom: 24.0), + content: Form( + key: _formKey, + child: Column( + children: [ + Row( children: [ - Flexible( - child: Container( + Expanded( + child: TextFormField( + style: TextStyle( + fontSize: 16.0, + color: Colors.white + ), + decoration: InputDecoration( + hintStyle: + TextStyle( + color: PaletteDark.walletCardText, + fontSize: 16 + ), + hintText: S.of(context).node_address, + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: PaletteDark.menuList, + width: 1.0)), + enabledBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: PaletteDark.menuList, + width: 1.0))), + controller: _nodeAddressController, + validator: (value) { + nodeList.validateNodeAddress(value); + return nodeList.errorMessage; + }, + ), + ) + ], + ), + SizedBox(height: 10.0), + Row( + children: [ + Expanded( + child: TextFormField( + style: TextStyle( + fontSize: 16.0, + color: Colors.white + ), + keyboardType: TextInputType.numberWithOptions( + signed: false, decimal: false), + decoration: InputDecoration( + hintStyle: + TextStyle( + color: PaletteDark.walletCardText, + fontSize: 16 + ), + hintText: S.of(context).node_port, + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: PaletteDark.menuList, + width: 1.0)), + enabledBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: PaletteDark.menuList, + width: 1.0))), + controller: _nodePortController, + validator: (value) { + nodeList.validateNodePort(value); + return nodeList.errorMessage; + }, + ), + ) + ], + ), + SizedBox(height: 10.0), + Row( + children: [ + Expanded( + child: TextFormField( + style: TextStyle( + fontSize: 16.0, + color: Colors.white + ), + decoration: InputDecoration( + hintStyle: + TextStyle( + color: PaletteDark.walletCardText, + fontSize: 16 + ), + hintText: S.of(context).login, + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: PaletteDark.menuList, + width: 1.0)), + enabledBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: PaletteDark.menuList, + width: 1.0))), + controller: _loginController, + validator: (value) => null, + ), + ) + ], + ), + SizedBox(height: 10.0), + Row( + children: [ + Expanded( + child: TextFormField( + style: TextStyle( + fontSize: 16.0, + color: Colors.white + ), + decoration: InputDecoration( + hintStyle: + TextStyle( + color: PaletteDark.walletCardText, + fontSize: 16 + ), + hintText: S.of(context).password, + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: PaletteDark.menuList, + width: 1.0)), + enabledBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: PaletteDark.menuList, + width: 1.0))), + controller: _passwordController, + validator: (value) => null, + ), + ) + ], + ) + ], + ) + ), + bottomSectionPadding: EdgeInsets.only(bottom: 24), + bottomSection: Observer( + builder: (_) => Row( + children: [ + Flexible( + child: Container( padding: EdgeInsets.only(right: 8.0), child: PrimaryButton( onPressed: () { @@ -169,17 +211,11 @@ class NewNodeFormState extends State { _passwordController.text = ''; }, text: S.of(context).reset, - color: Theme.of(context) - .accentTextTheme - .button - .backgroundColor, - textColor: Theme.of(context) - .primaryTextTheme - .button - .color), + color: Colors.red, + textColor: Colors.white), )), - Flexible( - child: Container( + Flexible( + child: Container( padding: EdgeInsets.only(left: 8.0), child: PrimaryButton( onPressed: () async { @@ -196,20 +232,15 @@ class NewNodeFormState extends State { Navigator.of(context).pop(); }, text: S.of(context).save, - color: Theme.of(context) - .primaryTextTheme - .button - .backgroundColor, - textColor: Theme.of(context) - .primaryTextTheme - .button - .color, + color: Colors.green, + textColor: Colors.white, + isDisabled: nodeList.disabledState, ), )), - ], - ), - ) - ], - )); + ], + ) + ), + ) + ); } } diff --git a/lib/src/screens/nodes/nodes_list_page.dart b/lib/src/screens/nodes/nodes_list_page.dart index de8a76442..990745cc8 100644 --- a/lib/src/screens/nodes/nodes_list_page.dart +++ b/lib/src/screens/nodes/nodes_list_page.dart @@ -5,10 +5,12 @@ import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/palette.dart'; import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/src/screens/nodes/node_indicator.dart'; +import 'package:cake_wallet/src/screens/nodes/widgets/node_indicator.dart'; import 'package:cake_wallet/src/stores/node_list/node_list_store.dart'; import 'package:cake_wallet/src/stores/settings/settings_store.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:cake_wallet/src/screens/nodes/widgets/node_list_row.dart'; +import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; class NodeListPage extends BasePage { NodeListPage(); @@ -16,76 +18,50 @@ class NodeListPage extends BasePage { @override String get title => S.current.nodes; + @override + Color get backgroundColor => PaletteDark.historyPanel; + @override Widget trailing(context) { final nodeList = Provider.of(context); final settings = Provider.of(context); - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - ButtonTheme( - minWidth: double.minPositive, - child: FlatButton( - onPressed: () async { - await showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: Text( - S.of(context).node_reset_settings_title, - textAlign: TextAlign.center, - ), - content: Text( - S.of(context).nodes_list_reset_to_default_message, - textAlign: TextAlign.center, - ), - actions: [ - FlatButton( - onPressed: () { - Navigator.pop(context); - }, - child: Text(S.of(context).cancel)), - FlatButton( - onPressed: () async { - Navigator.pop(context); - await nodeList.reset(); - await settings.setCurrentNodeToDefault(); - }, - child: Text(S.of(context).reset)) - ], - ); - }); - }, - child: Text( - S.of(context).reset, - style: TextStyle( - fontSize: 16.0, - color: Theme.of(context).primaryTextTheme.subtitle.color), - )), - ), - Container( - width: 28.0, - height: 28.0, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Theme.of(context).selectedRowColor), - child: Stack( - alignment: Alignment.center, - children: [ - Icon(Icons.add, color: Palette.violet, size: 22.0), - ButtonTheme( - minWidth: 28.0, - height: 28.0, - child: FlatButton( - shape: CircleBorder(), - onPressed: () async => - await Navigator.of(context).pushNamed(Routes.newNode), - child: Offstage()), - ) - ], + return Container( + height: 32, + width: 72, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(16)), + color: PaletteDark.menuList + ), + child: ButtonTheme( + minWidth: double.minPositive, + child: FlatButton( + onPressed: () async { + await showDialog( + context: context, + builder: (BuildContext context) { + return AlertWithTwoActions( + alertTitle: S.of(context).node_reset_settings_title, + alertContent: S.of(context).nodes_list_reset_to_default_message, + leftButtonText: S.of(context).reset, + rightButtonText: S.of(context).cancel, + actionLeftButton: () async { + Navigator.of(context).pop(); + await nodeList.reset(); + await settings.setCurrentNodeToDefault(); + }, + actionRightButton: () => Navigator.of(context).pop() + ); + }); + }, + child: Text( + S.of(context).reset, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 10.0, + color: Colors.blue), )), - ], + ), ); } @@ -104,137 +80,141 @@ class NodeListPageBodyState extends State { final nodeList = Provider.of(context); final settings = Provider.of(context); - final currentColor = Theme.of(context).selectedRowColor; - final notCurrentColor = Theme.of(context).backgroundColor; + final trashImage = Image.asset('assets/images/trash.png', height: 32, width: 32, color: Colors.white); + + final currentColor = PaletteDark.menuHeader; + final notCurrentColor = PaletteDark.menuList; + + final currentTextColor = Colors.blue; + final notCurrentTextColor = Colors.white; return Container( - padding: EdgeInsets.only(bottom: 20.0), + height: double.infinity, + color: PaletteDark.historyPanel, + padding: EdgeInsets.only(top: 12), child: Column( + mainAxisSize: MainAxisSize.max, children: [ - Expanded(child: Observer(builder: (context) { - return ListView.separated( - separatorBuilder: (_, __) => Divider( - color: Theme.of(context).dividerTheme.color, height: 1), - itemCount: nodeList.nodes.length, - itemBuilder: (BuildContext context, int index) { - final node = nodeList.nodes[index]; + NodeListRow( + title: S.of(context).add_new_node, + trailing: Icon(Icons.add, color: Colors.white, size: 24.0), + color: PaletteDark.menuList, + textColor: Colors.white, + onTap: () async => + await Navigator.of(context).pushNamed(Routes.newNode), + isDrawTop: true, + isDrawBottom: true), + Expanded( + child: Padding( + padding: EdgeInsets.only(top: 32), + child: Observer( + builder: (_) => ListView.separated( + separatorBuilder: (_, __) => Container( + height: 1, + padding: EdgeInsets.only(left: 24), + color: PaletteDark.menuList, + child: Container( + height: 1, + color: PaletteDark.walletCardTopEndSync, + ), + ), + itemCount: nodeList.nodes.length, + itemBuilder: (BuildContext context, int index) { + final node = nodeList.nodes[index]; - return Observer(builder: (_) { - final isCurrent = settings.node == null - ? false - : node.key == settings.node.key; + final isDrawTop = index == 0 ? true : false; + final isDrawBottom = index == nodeList.nodes.length - 1 ? true : false; - final content = Container( - color: isCurrent ? currentColor : notCurrentColor, - child: ListTile( - title: Text( - node.uri, - style: TextStyle( - fontSize: 16.0, - color: Theme.of(context) - .primaryTextTheme - .title - .color), - ), - trailing: FutureBuilder( - future: nodeList.isNodeOnline(node), - builder: (context, snapshot) { - switch (snapshot.connectionState) { - case ConnectionState.done: - return NodeIndicator( - color: snapshot.data as bool - ? Palette.green - : Palette.red); - default: - return NodeIndicator(); - } - }), - onTap: () async { - if (!isCurrent) { - await showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - content: Text( - S - .of(context) - .change_current_node(node.uri), - textAlign: TextAlign.center, - ), - actions: [ - FlatButton( - onPressed: () => - Navigator.pop(context), - child: Text(S.of(context).cancel)), - FlatButton( - onPressed: () async { + return Observer( + builder: (_) { + final isCurrent = settings.node == null + ? false + : node.key == settings.node.key; + + final content = NodeListRow( + title: node.uri, + trailing: FutureBuilder( + future: nodeList.isNodeOnline(node), + builder: (context, snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.done: + return NodeIndicator( + color: snapshot.data as bool + ? Palette.green + : Palette.red); + default: + return NodeIndicator(); + } + }), + color: isCurrent ? currentColor : notCurrentColor, + textColor: isCurrent ? currentTextColor : notCurrentTextColor, + onTap: () async { + if (!isCurrent) { + await showDialog( + context: context, + builder: (BuildContext context) { + return AlertWithTwoActions( + alertTitle: S.current.nodes, + alertContent: S.of(context) + .change_current_node(node.uri), + leftButtonText: S.of(context).change, + rightButtonText: S.of(context).cancel, + actionLeftButton: () async { Navigator.of(context).pop(); await settings.setCurrentNode( node: node); }, - child: Text(S.of(context).change)), - ], - ); - }); - } - }, - )); + actionRightButton: () => Navigator.of(context).pop() + ); + }); + } + }, + isDrawTop: isDrawTop, + isDrawBottom: isDrawBottom); - return isCurrent - ? content - : Dismissible( - key: Key('${node.key}'), - confirmDismiss: (direction) async { - return await showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: Text( - S.of(context).remove_node, - textAlign: TextAlign.center, - ), - content: Text( - S.of(context).remove_node_message, - textAlign: TextAlign.center, - ), - actions: [ - FlatButton( - onPressed: () => - Navigator.pop(context, false), - child: Text(S.of(context).cancel)), - FlatButton( - onPressed: () => - Navigator.pop(context, true), - child: Text(S.of(context).remove)), - ], - ); - }); - }, - onDismissed: (direction) async => - await nodeList.remove(node: node), - direction: DismissDirection.endToStart, - background: Container( - padding: EdgeInsets.only(right: 10.0), - alignment: AlignmentDirectional.centerEnd, - color: Palette.red, - child: Column( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - const Icon( - CupertinoIcons.delete, - color: Colors.white, - ), - Text( - S.of(context).delete, - style: TextStyle(color: Colors.white), - ) - ], - )), - child: content); - }); - }); - })) + return isCurrent + ? content + : Dismissible( + key: Key('${node.key}'), + confirmDismiss: (direction) async { + return await showDialog( + context: context, + builder: (BuildContext context) { + return AlertWithTwoActions( + alertTitle: S.of(context).remove_node, + alertContent: S.of(context).remove_node_message, + leftButtonText: S.of(context).remove, + rightButtonText: S.of(context).cancel, + actionLeftButton: () => + Navigator.pop(context, true), + actionRightButton: () => + Navigator.pop(context, false) + ); + }); + }, + onDismissed: (direction) async => + await nodeList.remove(node: node), + direction: DismissDirection.endToStart, + background: Container( + padding: EdgeInsets.only(right: 10.0, top: 2), + alignment: AlignmentDirectional.centerEnd, + color: Palette.red, + child: Column( + children: [ + trashImage, + Text( + S.of(context).delete, + style: TextStyle(color: Colors.white), + ) + ], + )), + child: content); + }, + ); + }) + ), + ) + ) ], ), ); diff --git a/lib/src/screens/nodes/node_indicator.dart b/lib/src/screens/nodes/widgets/node_indicator.dart similarity index 90% rename from lib/src/screens/nodes/node_indicator.dart rename to lib/src/screens/nodes/widgets/node_indicator.dart index 8d46e03a5..cf1557428 100644 --- a/lib/src/screens/nodes/node_indicator.dart +++ b/lib/src/screens/nodes/widgets/node_indicator.dart @@ -9,8 +9,8 @@ class NodeIndicator extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - width: 10.0, - height: 10.0, + width: 8.0, + height: 8.0, decoration: BoxDecoration(shape: BoxShape.circle, color: color), ); } diff --git a/lib/src/screens/nodes/widgets/node_list_row.dart b/lib/src/screens/nodes/widgets/node_list_row.dart new file mode 100644 index 000000000..2e3dd4017 --- /dev/null +++ b/lib/src/screens/nodes/widgets/node_list_row.dart @@ -0,0 +1,63 @@ +import 'package:flutter/material.dart'; +import 'package:cake_wallet/palette.dart'; + +class NodeListRow extends StatelessWidget { + NodeListRow({ + @required this.title, + @required this.trailing, + @required this.color, + @required this.textColor, + @required this.onTap, + @required this.isDrawTop, + @required this.isDrawBottom}); + + final String title; + final Widget trailing; + final Color color; + final Color textColor; + final VoidCallback onTap; + final bool isDrawTop; + final bool isDrawBottom; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + isDrawTop + ? Container( + width: double.infinity, + height: 1, + color: PaletteDark.walletCardTopEndSync, + ) + : Offstage(), + Container( + width: double.infinity, + height: 56, + color: color, + child: ListTile( + contentPadding: EdgeInsets.only( + left: 24, + right: 24, + ), + title: Text( + title, + style: TextStyle( + fontSize: 14, + color: textColor + ), + textAlign: TextAlign.left), + trailing: trailing, + onTap: onTap, + ) + ), + isDrawBottom + ? Container( + width: double.infinity, + height: 1, + color: PaletteDark.walletCardTopEndSync, + ) + : Offstage(), + ], + ); + } +} diff --git a/lib/src/screens/restore/restore_wallet_from_keys_page.dart b/lib/src/screens/restore/restore_wallet_from_keys_page.dart index 8c6ecbffc..6a8d1b1d6 100644 --- a/lib/src/screens/restore/restore_wallet_from_keys_page.dart +++ b/lib/src/screens/restore/restore_wallet_from_keys_page.dart @@ -16,7 +16,7 @@ import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart'; import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; import 'package:cake_wallet/palette.dart'; import 'package:cake_wallet/src/stores/seed_language/seed_language_store.dart'; -import 'package:cake_wallet/src/screens/restore/widgets/restore_alert_dialog.dart'; +import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; class RestoreWalletFromKeysPage extends BasePage { RestoreWalletFromKeysPage( @@ -91,11 +91,11 @@ class _RestoreFromKeysFromState extends State { showDialog( context: context, builder: (BuildContext context) { - return RestoreAlertDialog( - restoreTitle: S.current.restore_title_from_keys, - restoreContent: state.error, - restoreButtonText: S.of(context).ok, - restoreButtonAction: () => Navigator.of(context).pop(), + return AlertWithOneAction( + alertTitle: S.current.restore_title_from_keys, + alertContent: state.error, + buttonText: S.of(context).ok, + buttonAction: () => Navigator.of(context).pop() ); }); }); diff --git a/lib/src/screens/restore/restore_wallet_from_seed_details.dart b/lib/src/screens/restore/restore_wallet_from_seed_details.dart index 76214f45e..1a2f85eab 100644 --- a/lib/src/screens/restore/restore_wallet_from_seed_details.dart +++ b/lib/src/screens/restore/restore_wallet_from_seed_details.dart @@ -11,7 +11,7 @@ import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart'; import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; import 'package:cake_wallet/src/widgets/primary_button.dart'; import 'package:cake_wallet/palette.dart'; -import 'package:cake_wallet/src/screens/restore/widgets/restore_alert_dialog.dart'; +import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; class RestoreWalletFromSeedDetailsPage extends BasePage { @override @@ -64,11 +64,11 @@ class _RestoreFromSeedDetailsFormState showDialog( context: context, builder: (BuildContext context) { - return RestoreAlertDialog( - restoreTitle: S.current.restore_wallet_restore_description, - restoreContent: state.error, - restoreButtonText: S.of(context).ok, - restoreButtonAction: () => Navigator.of(context).pop(), + return AlertWithOneAction( + alertTitle: S.current.restore_title_from_seed, + alertContent: state.error, + buttonText: S.of(context).ok, + buttonAction: () => Navigator.of(context).pop() ); }); }); diff --git a/lib/src/screens/setup_pin_code/setup_pin_code.dart b/lib/src/screens/setup_pin_code/setup_pin_code.dart index 301dfd5ea..0a41a9099 100644 --- a/lib/src/screens/setup_pin_code/setup_pin_code.dart +++ b/lib/src/screens/setup_pin_code/setup_pin_code.dart @@ -8,7 +8,7 @@ import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/stores/settings/settings_store.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/palette.dart'; -import 'package:cake_wallet/src/screens/setup_pin_code/widgets/pin_alert_dialog.dart'; +import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; class SetupPinCodePage extends BasePage { SetupPinCodePage({this.onPinCodeSetup}); @@ -64,27 +64,28 @@ class _SetupPinCodeFormState showDialog( context: context, builder: (BuildContext context) { - return PinAlertDialog( - pinTitleText: S.current.setup_pin, - pinContentText: S.of(context).setup_successful, - pinActionButtonText: S.of(context).ok, - pinBarrierDismissible: false, - pinAction: () { + return AlertWithOneAction( + alertTitle: S.current.setup_pin, + alertContent: S.of(context).setup_successful, + buttonText: S.of(context).ok, + buttonAction: () { Navigator.of(context).pop(); widget.onPinCodeSetup(context, pin); reset(); - }); + }, + alertBarrierDismissible: false, + ); }); } else { showDialog( context: context, builder: (BuildContext context) { - return PinAlertDialog( - pinTitleText: S.current.setup_pin, - pinContentText: S.of(context).pin_is_incorrect, - pinActionButtonText: S.of(context).ok, - pinBarrierDismissible: true, - pinAction: () => Navigator.of(context).pop()); + return AlertWithOneAction( + alertTitle: S.current.setup_pin, + alertContent: S.of(context).pin_is_incorrect, + buttonText: S.of(context).ok, + buttonAction: () => Navigator.of(context).pop() + ); }); reset(); diff --git a/lib/src/screens/setup_pin_code/widgets/pin_alert_dialog.dart b/lib/src/screens/setup_pin_code/widgets/pin_alert_dialog.dart deleted file mode 100644 index 426195301..000000000 --- a/lib/src/screens/setup_pin_code/widgets/pin_alert_dialog.dart +++ /dev/null @@ -1,60 +0,0 @@ -import 'dart:ui'; -import 'package:cake_wallet/src/widgets/base_alert_dialog.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; - -class PinAlertDialog extends BaseAlertDialog { - PinAlertDialog({ - @required this.pinTitleText, - @required this.pinContentText, - @required this.pinActionButtonText, - @required this.pinAction, - @required this.pinBarrierDismissible - }); - - final String pinTitleText; - final String pinContentText; - final String pinActionButtonText; - final VoidCallback pinAction; - final bool pinBarrierDismissible; - - @override - String get titleText => pinTitleText; - @override - String get contentText => pinContentText; - @override - bool get barrierDismissible => pinBarrierDismissible; - - @override - Widget actionButtons(BuildContext context) { - return Container( - width: 300, - height: 52, - padding: EdgeInsets.only(left: 12, right: 12), - decoration: BoxDecoration( - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(24), - bottomRight: Radius.circular(24) - ), - color: Colors.white - ), - child: ButtonTheme( - minWidth: double.infinity, - child: FlatButton( - onPressed: pinAction, - highlightColor: Colors.transparent, - splashColor: Colors.transparent, - child: Text( - pinActionButtonText, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.w600, - color: Colors.blue, - decoration: TextDecoration.none, - ), - )), - ), - ); - } -} \ No newline at end of file diff --git a/lib/src/stores/node_list/node_list_store.dart b/lib/src/stores/node_list/node_list_store.dart index c1fc4c117..8a8bd2e0b 100644 --- a/lib/src/stores/node_list/node_list_store.dart +++ b/lib/src/stores/node_list/node_list_store.dart @@ -12,6 +12,7 @@ class NodeListStore = NodeListBase with _$NodeListStore; abstract class NodeListBase with Store { NodeListBase({this.nodesSource}) { nodes = ObservableList(); + disabledState = true; _onNodesChangeSubscription = nodesSource.watch().listen((e) => update()); update(); } @@ -25,6 +26,9 @@ abstract class NodeListBase with Store { @observable String errorMessage; + @observable + bool disabledState; + Box nodesSource; StreamSubscription _onNodesChangeSubscription; @@ -61,6 +65,11 @@ abstract class NodeListBase with Store { @action Future reset() async => await resetToDefault(nodesSource); + @action + void setDisabledState(bool isDisable) { + disabledState = isDisable; + } + Future isNodeOnline(Node node) async { try { return await node.requestNode(node.uri, diff --git a/lib/src/screens/restore/widgets/restore_alert_dialog.dart b/lib/src/widgets/alert_with_one_action.dart similarity index 62% rename from lib/src/screens/restore/widgets/restore_alert_dialog.dart rename to lib/src/widgets/alert_with_one_action.dart index 1f41163a0..704243591 100644 --- a/lib/src/screens/restore/widgets/restore_alert_dialog.dart +++ b/lib/src/widgets/alert_with_one_action.dart @@ -1,24 +1,29 @@ import 'package:flutter/material.dart'; import 'package:cake_wallet/src/widgets/base_alert_dialog.dart'; -class RestoreAlertDialog extends BaseAlertDialog { - RestoreAlertDialog({ - @required this.restoreTitle, - @required this.restoreContent, - @required this.restoreButtonText, - @required this.restoreButtonAction, +class AlertWithOneAction extends BaseAlertDialog { + AlertWithOneAction({ + @required this.alertTitle, + @required this.alertContent, + @required this.buttonText, + @required this.buttonAction, + this.alertBarrierDismissible = true }); - final String restoreTitle; - final String restoreContent; - final String restoreButtonText; - final VoidCallback restoreButtonAction; + final String alertTitle; + final String alertContent; + final String buttonText; + final VoidCallback buttonAction; + final bool alertBarrierDismissible; @override - String get titleText => restoreTitle; + String get titleText => alertTitle; @override - String get contentText => restoreContent; + String get contentText => alertContent; + + @override + bool get barrierDismissible => alertBarrierDismissible; @override Widget actionButtons(BuildContext context) { @@ -36,11 +41,11 @@ class RestoreAlertDialog extends BaseAlertDialog { child: ButtonTheme( minWidth: double.infinity, child: FlatButton( - onPressed: restoreButtonAction, + onPressed: buttonAction, highlightColor: Colors.transparent, splashColor: Colors.transparent, child: Text( - restoreButtonText, + buttonText, textAlign: TextAlign.center, style: TextStyle( fontSize: 15, @@ -52,5 +57,4 @@ class RestoreAlertDialog extends BaseAlertDialog { ), ); } - } \ No newline at end of file diff --git a/lib/src/widgets/alert_with_two_actions.dart b/lib/src/widgets/alert_with_two_actions.dart new file mode 100644 index 000000000..c2831675e --- /dev/null +++ b/lib/src/widgets/alert_with_two_actions.dart @@ -0,0 +1,38 @@ +import 'dart:ui'; +import 'package:cake_wallet/src/widgets/base_alert_dialog.dart'; +import 'package:flutter/cupertino.dart'; + +class AlertWithTwoActions extends BaseAlertDialog { + AlertWithTwoActions({ + @required this.alertTitle, + @required this.alertContent, + @required this.leftButtonText, + @required this.rightButtonText, + @required this.actionLeftButton, + @required this.actionRightButton, + this.alertBarrierDismissible = true + }); + + final String alertTitle; + final String alertContent; + final String leftButtonText; + final String rightButtonText; + final VoidCallback actionLeftButton; + final VoidCallback actionRightButton; + final bool alertBarrierDismissible; + + @override + String get titleText => alertTitle; + @override + String get contentText => alertContent; + @override + String get leftActionButtonText => leftButtonText; + @override + String get rightActionButtonText => rightButtonText; + @override + VoidCallback get actionLeft => actionLeftButton; + @override + VoidCallback get actionRight => actionRightButton; + @override + bool get barrierDismissible => alertBarrierDismissible; +} \ No newline at end of file diff --git a/lib/src/widgets/base_alert_dialog.dart b/lib/src/widgets/base_alert_dialog.dart index 494b69ab4..d85ae21fc 100644 --- a/lib/src/widgets/base_alert_dialog.dart +++ b/lib/src/widgets/base_alert_dialog.dart @@ -134,7 +134,6 @@ class BaseAlertDialog extends StatelessWidget { color: PaletteDark.menuHeader ), child: Column( - //mainAxisSize: MainAxisSize.max, children: [ Container( width: 300, diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index ae54ff092..d73782715 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -124,6 +124,7 @@ "remove_node_message" : "Möchten Sie den ausgewählten Knoten wirklich entfernen?", "remove" : "Löschen", "delete" : "Löschen", + "add_new_node" : "Neuen Knoten hinzufügen", "use" : "Wechseln zu ", diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index 2dcd6d01a..218aaa582 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -124,6 +124,7 @@ "remove_node_message" : "Are you sure that you want to remove selected node?", "remove" : "Remove", "delete" : "Delete", + "add_new_node" : "Add new node", "use" : "Switch to ", diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index 87444dbcb..0231d495a 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -124,6 +124,7 @@ "remove_node_message" : "¿Está seguro de que desea eliminar el nodo seleccionado?", "remove" : "Retirar", "delete" : "Borrar", + "add_new_node" : "Agregar nuevo nodo", "use" : "Cambiar a ", diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index fa614d81c..58b329d1a 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -124,6 +124,7 @@ "remove_node_message" : "क्या आप वाकई चयनित नोड को निकालना चाहते हैं?", "remove" : "हटाना", "delete" : "हटाएं", + "add_new_node" : "नया नोड जोड़ें", "use" : "पर स्विच ", diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index d40c510d3..bab090edf 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -124,6 +124,7 @@ "remove_node_message" : "選択したノードを削除してもよろしいですか?", "remove" : "削除する", "delete" : "削除する", + "add_new_node" : "新しいノードを追加", "use" : "切り替える ", diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index bdf28dfdf..bc49d48de 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -124,6 +124,7 @@ "remove_node_message" : "선택한 노드를 제거 하시겠습니까?", "remove" : "없애다", "delete" : "지우다", + "add_new_node" : "새 노드 추가", "use" : "로 전환 ", diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index f60c5bd03..24844e3b5 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -124,6 +124,7 @@ "remove_node_message" : "Weet u zeker dat u het geselecteerde knooppunt wilt verwijderen?", "remove" : "Verwijderen", "delete" : "Delete", + "add_new_node" : "Voeg een nieuw knooppunt toe", "use" : "Overschakelen naar ", diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index 86dbbc88e..1f9f69dc8 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -124,6 +124,7 @@ "remove_node_message" : "Czy na pewno chcesz usunąć wybrany węzeł?", "remove" : "Usunąć", "delete" : "Kasować", + "add_new_node" : "Dodaj nowy węzeł", "use" : "Przełącz na ", diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index 40b7f8d12..599965f11 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -124,6 +124,7 @@ "remove_node_message" : "Você realmente deseja remover o nó selecionado?", "remove" : "Remover", "delete" : "Excluir", + "add_new_node" : "Adicionar novo nó", "use" : "Trocar para PIN de ", diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index a5e379202..c9889526d 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -124,6 +124,7 @@ "remove_node_message" : "Вы уверены, что хотите удалить текущую ноду?", "remove" : "Удалить", "delete" : "Удалить", + "add_new_node" : "Добавить новую ноду", "use" : "Переключиться на ", diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index ce77826ed..1758acc96 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -124,6 +124,7 @@ "remove_node_message" : "Ви впевнені, що хочете видалити поточний вузол?", "remove" : "Видалити", "delete" : "Видалити", + "add_new_node" : "Додати новий вузол", "use" : "Переключитися на ", diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index 63246d329..01c75bb28 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -124,6 +124,7 @@ "remove_node_message" : "您确定要删除所选节点吗?", "remove" : "去掉", "delete" : "删除", + "add_new_node" : "添加新節點", "use" : "切換到 ",