From d748f12e4441a7383c0a86c169c94053a4815314 Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Tue, 4 Oct 2022 14:54:39 +0200 Subject: [PATCH 01/47] Allow marking Monero Nodes as trusted --- cw_core/lib/node.dart | 11 +++++++++-- .../screens/nodes/node_create_or_edit_page.dart | 17 ++++++++++++++++- .../node_create_or_edit_view_model.dart | 9 +++++++-- res/values/strings_de.arb | 1 + res/values/strings_en.arb | 1 + res/values/strings_es.arb | 1 + res/values/strings_fr.arb | 1 + res/values/strings_hi.arb | 1 + res/values/strings_hr.arb | 1 + res/values/strings_it.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 | 2 +- res/values/strings_ru.arb | 1 + res/values/strings_uk.arb | 1 + res/values/strings_zh.arb | 1 + 18 files changed, 47 insertions(+), 6 deletions(-) diff --git a/cw_core/lib/node.dart b/cw_core/lib/node.dart index 7de2e84b6..dd5969b99 100644 --- a/cw_core/lib/node.dart +++ b/cw_core/lib/node.dart @@ -20,7 +20,8 @@ class Node extends HiveObject with Keyable { @required WalletType type, this.login, this.password, - this.useSSL}) { + this.useSSL, + this.trusted}) { uriRaw = uri; this.type = type; } @@ -30,7 +31,8 @@ class Node extends HiveObject with Keyable { login = map['login'] as String, password = map['password'] as String, typeRaw = map['typeRaw'] as int, - useSSL = map['useSSL'] as bool; + useSSL = map['useSSL'] as bool, + trusted = map['trusted'] as bool ?? false; static const typeId = 1; static const boxName = 'Nodes'; @@ -50,8 +52,13 @@ class Node extends HiveObject with Keyable { @HiveField(4) bool useSSL; + @HiveField(5) + bool trusted; + bool get isSSL => useSSL ?? false; + bool get isTrusted => trusted ?? false; + Uri get uri { switch (type) { case WalletType.monero: diff --git a/lib/src/screens/nodes/node_create_or_edit_page.dart b/lib/src/screens/nodes/node_create_or_edit_page.dart index 6cfa67285..857bde023 100644 --- a/lib/src/screens/nodes/node_create_or_edit_page.dart +++ b/lib/src/screens/nodes/node_create_or_edit_page.dart @@ -174,7 +174,22 @@ class NodeCreateOrEditPage extends BasePage { caption: S.of(context).use_ssl, )) ], - )) + )), + Padding( + padding: EdgeInsets.only(top: 20), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Observer( + builder: (_) => StandardCheckbox( + value: nodeCreateOrEditViewModel.trusted, + onChanged: (value) => + nodeCreateOrEditViewModel.trusted = value, + caption: S.of(context).trusted, + )) + ], + )), ] ], )), diff --git a/lib/view_model/node_list/node_create_or_edit_view_model.dart b/lib/view_model/node_list/node_create_or_edit_view_model.dart index ef7e03189..c14bdda5e 100644 --- a/lib/view_model/node_list/node_create_or_edit_view_model.dart +++ b/lib/view_model/node_list/node_create_or_edit_view_model.dart @@ -14,7 +14,8 @@ abstract class NodeCreateOrEditViewModelBase with Store { NodeCreateOrEditViewModelBase(this._nodeSource, this._wallet) : state = InitialExecutionState(), connectionState = InitialExecutionState(), - useSSL = false; + useSSL = false, + trusted = false; @observable ExecutionState state; @@ -37,6 +38,9 @@ abstract class NodeCreateOrEditViewModelBase with Store { @observable bool useSSL; + @observable + bool trusted; + @computed bool get isReady => (address?.isNotEmpty ?? false) && (port?.isNotEmpty ?? false); @@ -64,6 +68,7 @@ abstract class NodeCreateOrEditViewModelBase with Store { login = ''; password = ''; useSSL = false; + trusted = false; } @action @@ -72,7 +77,7 @@ abstract class NodeCreateOrEditViewModelBase with Store { state = IsExecutingState(); final node = Node(uri: uri, type: _wallet.type, login: login, password: password, - useSSL: useSSL); + useSSL: useSSL, trusted: trusted); await _nodeSource.add(node); state = ExecutedSuccessfullyState(); } catch (e) { diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index 3457f8ab2..fa04a6a8e 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -436,6 +436,7 @@ "provider_error" : "${provider}-Fehler", "use_ssl" : "SSL verwenden", + "trusted" : "Vertrauenswürdige", "color_theme" : "Farbthema", "light_theme" : "Hell", diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index ef8e6e495..4a46d36c8 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -436,6 +436,7 @@ "provider_error" : "${provider} error", "use_ssl" : "Use SSL", + "trusted" : "Trusted", "color_theme" : "Color theme", "light_theme" : "Light", diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index 7c996134e..756ac3e11 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -436,6 +436,7 @@ "provider_error" : "${provider} error", "use_ssl" : "Utilice SSL", + "trusted" : "de confianza", "color_theme" : "Tema de color", "light_theme" : "Ligera", diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb index b347086ae..04462943e 100644 --- a/res/values/strings_fr.arb +++ b/res/values/strings_fr.arb @@ -434,6 +434,7 @@ "provider_error" : "Erreur de ${provider}", "use_ssl" : "Utiliser SSL", + "trusted" : "de confiance", "color_theme" : "Thème", "light_theme" : "Clair", diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index 83c0808c4..f8bad76e2 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -436,6 +436,7 @@ "provider_error" : "${provider} त्रुटि", "use_ssl" : "उपयोग SSL", + "trusted" : "भरोसा", "color_theme" : "रंग विषय", "light_theme" : "रोशनी", diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index 97d4d335c..0e27e3a2c 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -436,6 +436,7 @@ "provider_error" : "${provider} greška", "use_ssl" : "Koristi SSL", + "trusted" : "vjerovao", "color_theme" : "Shema boja", "light_theme" : "Svijetla", diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb index cd779471f..ea9bbd5be 100644 --- a/res/values/strings_it.arb +++ b/res/values/strings_it.arb @@ -436,6 +436,7 @@ "provider_error" : "${provider} errore", "use_ssl" : "Usa SSL", + "trusted" : "di fiducia", "color_theme" : "Colore tema", "light_theme" : "Bianco", diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index 2b3920862..5ae3a5a1a 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -436,6 +436,7 @@ "provider_error" : "${provider} エラー", "use_ssl" : "SSLを使用する", + "trusted" : "信頼できる", "color_theme" : "カラーテーマ", "light_theme" : "光", diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index 85ece0603..f934784ba 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -436,6 +436,7 @@ "provider_error" : "${provider} 오류", "use_ssl" : "SSL 사용", + "trusted" : "신뢰할 수 있는", "color_theme" : "색상 테마", "light_theme" : "빛", diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index 15da6fd7b..428da3d76 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -436,6 +436,7 @@ "provider_error" : "${provider} fout", "use_ssl" : "Gebruik SSL", + "trusted" : "vertrouwd", "color_theme" : "Kleur thema", "light_theme" : "Licht", diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index 26d8a38d4..fda0ea721 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -436,6 +436,7 @@ "provider_error" : "${provider} pomyłka", "use_ssl" : "Użyj SSL", + "trusted" : "zaufany", "color_theme" : "Motyw kolorystyczny", "light_theme" : "Lekki", diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index bfb4a2d0a..6a55cf534 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -436,6 +436,7 @@ "provider_error" : "${provider} erro", "use_ssl" : "Use SSL", + "trusted" : "confiável", "color_theme" : "Tema de cor", "light_theme" : "Luz", @@ -544,7 +545,6 @@ "create_account": "Criar conta", "privacy_policy": "Política de privacidade", "welcome_to_cakepay": "Bem-vindo ao Cake Pay!", - "create_account": "Registar-se", "forgot_password": "Esqueci a senha", "reset_password": "Redefinir senha", "gift_cards": "Cartões de presente", diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index 94a5b3c0b..ebc4a615c 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -436,6 +436,7 @@ "provider_error" : "${provider} ошибка", "use_ssl" : "Использовать SSL", + "trusted" : "доверенный", "color_theme" : "Цветовая тема", "light_theme" : "Светлая", diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index b139750be..efbd5a3b8 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -435,6 +435,7 @@ "provider_error" : "${provider} помилка", "use_ssl" : "Використати SSL", + "trusted" : "довіряють", "color_theme" : "Кольорова тема", "light_theme" : "Світла", diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index 487c6be52..83990cf2e 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -435,6 +435,7 @@ "provider_error" : "${provider} 错误", "use_ssl" : "使用SSL", + "trusted" : "值得信赖", "color_theme" : "主题", "light_theme" : "艳丽", From c37bfb2e83d2fe2ff48d911256b689dd8b53a03d Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Wed, 5 Oct 2022 15:57:17 +0200 Subject: [PATCH 02/47] Add Advanced privacy settings page and initial view model --- .../advanced_privacy_settings_page.dart | 173 ++++++++++++++++++ .../privacy_settings_view_model.dart | 54 ++++++ 2 files changed, 227 insertions(+) create mode 100644 lib/src/screens/new_wallet/advanced_privacy_settings_page.dart create mode 100644 lib/view_model/privacy_settings_view_model.dart diff --git a/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart new file mode 100644 index 000000000..149b65d2e --- /dev/null +++ b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart @@ -0,0 +1,173 @@ +import 'package:cake_wallet/entities/generate_name.dart'; +import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart'; +import 'package:cake_wallet/view_model/privacy_settings_view_model.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/core/wallet_name_validator.dart'; +import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:cake_wallet/src/widgets/primary_button.dart'; +import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; + +class AdvancedPrivacySettingsPage extends BasePage { + AdvancedPrivacySettingsPage(this.privacySettingsViewModel); + + final PrivacySettingsViewModel privacySettingsViewModel; + + @override + String get title => S.current.privacy_settings; + + @override + Widget body(BuildContext context) => + AdvancedPrivacySettingsBody(privacySettingsViewModel); +} + +class AdvancedPrivacySettingsBody extends StatefulWidget { + const AdvancedPrivacySettingsBody(this.privacySettingsViewModel, {Key key}) + : super(key: key); + + final PrivacySettingsViewModel privacySettingsViewModel; + + @override + _AdvancedPrivacySettingsBodyState createState() => + _AdvancedPrivacySettingsBodyState(privacySettingsViewModel); +} + +class _AdvancedPrivacySettingsBodyState + extends State { + _AdvancedPrivacySettingsBodyState(this.privacySettingsViewModel); + + final PrivacySettingsViewModel privacySettingsViewModel; + + final _formKey = GlobalKey(); + + final TextEditingController _controller = TextEditingController(); + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.only(top: 24), + child: ScrollableWithBottomSection( + contentPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24), + content: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + ...privacySettingsViewModel.settings.map( + (item) => Observer( + builder: (_) => SettingsSwitcherCell( + title: item.title, + value: item.value(), + onValueChange: item.onValueChange, + ), + ), + ), + Observer( + builder: (_) { + if (privacySettingsViewModel.addCustomNode) { + return Padding( + padding: EdgeInsets.only(top: 24), + child: Form( + key: _formKey, + child: TextFormField( + onChanged: (value) {}, + controller: _controller, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.w600, + color: + Theme.of(context).primaryTextTheme.title.color), + decoration: InputDecoration( + hintStyle: TextStyle( + fontSize: 18.0, + fontWeight: FontWeight.w500, + color: Theme.of(context) + .accentTextTheme + .display3 + .color), + hintText: S.of(context).wallet_name, + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context) + .accentTextTheme + .display3 + .decorationColor, + width: 1.0), + ), + enabledBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context) + .accentTextTheme + .display3 + .decorationColor, + width: 1.0), + ), + suffixIcon: IconButton( + onPressed: () async { + final rName = await generateName(); + FocusManager.instance.primaryFocus?.unfocus(); + + setState(() { + _controller.text = rName; + _controller.selection = + TextSelection.fromPosition( + TextPosition(offset: _controller.text.length), + ); + }); + }, + icon: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(6.0), + color: Theme.of(context).hintColor, + ), + width: 34, + height: 34, + child: Image.asset( + 'assets/images/refresh_icon.png', + color: Theme.of(context) + .primaryTextTheme + .display1 + .decorationColor, + ), + ), + ), + ), + validator: WalletNameValidator(), + ), + ), + ); + } + return const SizedBox(); + }, + ), + ], + ), + bottomSectionPadding: EdgeInsets.all(24), + bottomSection: Column( + children: [ + LoadingPrimaryButton( + onPressed: () {}, + text: S.of(context).continue_text, + color: Theme.of(context).accentTextTheme.body2.color, + textColor: Colors.white, + ), + const SizedBox(height: 25), + Padding( + padding: EdgeInsets.symmetric( + horizontal: MediaQuery.of(context).size.width * 0.15), + child: Text( + S.of(context).settings_can_be_changed_later, + textAlign: TextAlign.center, + style: TextStyle( + color: Theme.of(context).accentTextTheme.display3.color, + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/view_model/privacy_settings_view_model.dart b/lib/view_model/privacy_settings_view_model.dart new file mode 100644 index 000000000..ce5a3f7a6 --- /dev/null +++ b/lib/view_model/privacy_settings_view_model.dart @@ -0,0 +1,54 @@ +import 'package:cake_wallet/view_model/settings/switcher_list_item.dart'; +import 'package:cw_core/wallet_type.dart'; +import 'package:mobx/mobx.dart'; +import 'package:cake_wallet/generated/i18n.dart'; + +part 'privacy_settings_view_model.g.dart'; + +class PrivacySettingsViewModel = PrivacySettingsViewModelBase + with _$PrivacySettingsViewModel; + +abstract class PrivacySettingsViewModelBase with Store { + PrivacySettingsViewModelBase(this.type) { + _disableFiat = false; + _disableExchange = false; + _addCustomNode = false; + + settings = [ + SwitcherListItem( + title: "Disable Fiat API", + // title: S.current.disable_fiat, + value: () => _disableFiat, + onValueChange: (_, bool value) => _disableFiat = value, + ), + SwitcherListItem( + title: "Disable Exchange", + // title: S.current.disable_exchange, + value: () => _disableExchange, + onValueChange: (_, bool value) => _disableExchange = value, + ), + SwitcherListItem( + title: "Add New Custom Node", + // title: S.current.add_custom_node, + value: () => _addCustomNode, + onValueChange: (_, bool value) => _addCustomNode = value, + ), + ]; + } + + List settings; + + @observable + bool _disableFiat; + + @observable + bool _disableExchange; + + @observable + bool _addCustomNode; + + final WalletType type; + + @computed + bool get addCustomNode => _addCustomNode; +} From 6bbedde9b7920ec090037a4ed16a89bf5f7a9b64 Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Wed, 5 Oct 2022 15:58:25 +0200 Subject: [PATCH 03/47] Add privacy settings route Add text translation --- lib/di.dart | 4 +++ lib/router.dart | 9 +++++ lib/routes.dart | 1 + .../screens/new_wallet/new_wallet_page.dart | 35 ++++++++++++------- res/values/strings_de.arb | 5 ++- res/values/strings_en.arb | 5 ++- res/values/strings_es.arb | 5 ++- res/values/strings_fr.arb | 5 ++- res/values/strings_hi.arb | 5 ++- res/values/strings_hr.arb | 5 ++- res/values/strings_it.arb | 5 ++- res/values/strings_ja.arb | 5 ++- res/values/strings_ko.arb | 5 ++- res/values/strings_nl.arb | 5 ++- res/values/strings_pl.arb | 5 ++- res/values/strings_pt.arb | 5 ++- res/values/strings_ru.arb | 5 ++- res/values/strings_uk.arb | 5 ++- res/values/strings_zh.arb | 5 ++- 19 files changed, 97 insertions(+), 27 deletions(-) diff --git a/lib/di.dart b/lib/di.dart index 5cc698d27..8dfbfd788 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -25,6 +25,7 @@ import 'package:cake_wallet/src/screens/dashboard/widgets/balance_page.dart'; import 'package:cake_wallet/view_model/ionia/ionia_account_view_model.dart'; import 'package:cake_wallet/view_model/ionia/ionia_gift_cards_list_view_model.dart'; import 'package:cake_wallet/view_model/ionia/ionia_purchase_merch_view_model.dart'; +import 'package:cake_wallet/view_model/privacy_settings_view_model.dart'; import 'package:cw_core/unspent_coins_info.dart'; import 'package:cake_wallet/core/backup_service.dart'; import 'package:cw_core/wallet_service.dart'; @@ -786,5 +787,8 @@ Future setup( (IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo) => IoniaPaymentStatusPage(getIt.get(param1: paymentInfo, param2: committedInfo))); + getIt.registerFactoryParam((type, _) => + PrivacySettingsViewModel(type)); + _isSetupFinished = true; } diff --git a/lib/router.dart b/lib/router.dart index 051e07cb0..b19fb198e 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -10,6 +10,7 @@ import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_redeem_page.dar import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_tip_page.dart'; import 'package:cake_wallet/src/screens/ionia/cards/ionia_gift_card_detail_page.dart'; import 'package:cake_wallet/src/screens/ionia/cards/ionia_more_options_page.dart'; +import 'package:cake_wallet/src/screens/new_wallet/advanced_privacy_settings_page.dart'; import 'package:cake_wallet/src/screens/order_details/order_details_page.dart'; import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart'; import 'package:cake_wallet/src/screens/restore/restore_from_backup_page.dart'; @@ -19,6 +20,7 @@ import 'package:cake_wallet/src/screens/support/support_page.dart'; import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart'; import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart'; import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart'; +import 'package:cake_wallet/view_model/privacy_settings_view_model.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:cake_wallet/routes.dart'; @@ -471,6 +473,13 @@ Route createRoute(RouteSettings settings) { param1: paymentInfo, param2: commitedInfo)); + case Routes.privacySettings: + final type = settings.arguments as WalletType; + final privacySettingsViewModel = getIt.get(param1: type); + + return CupertinoPageRoute( + builder: (_) => AdvancedPrivacySettingsPage(privacySettingsViewModel)); + default: return MaterialPageRoute( builder: (_) => Scaffold( diff --git a/lib/routes.dart b/lib/routes.dart index 7431d71df..8b0a6ca03 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -76,4 +76,5 @@ class Routes { static const ioniaPaymentStatusPage = '/ionia_payment_status_page'; static const ioniaMoreOptionsPage = '/ionia_more_options_page'; static const ioniaCustomRedeemPage = '/ionia_custom_redeem_page'; + static const privacySettings = '/privacy_settings'; } diff --git a/lib/src/screens/new_wallet/new_wallet_page.dart b/lib/src/screens/new_wallet/new_wallet_page.dart index 2ea1eca94..8aef74445 100644 --- a/lib/src/screens/new_wallet/new_wallet_page.dart +++ b/lib/src/screens/new_wallet/new_wallet_page.dart @@ -198,18 +198,29 @@ class _WalletNameFormState extends State { ] ]), bottomSectionPadding: - EdgeInsets.only(left: 24, right: 24, bottom: 24), - bottomSection: Observer( - builder: (context) { - return LoadingPrimaryButton( - onPressed: _confirmForm, - text: S.of(context).seed_language_next, - color: Colors.green, - textColor: Colors.white, - isLoading: _walletNewVM.state is IsExecutingState, - isDisabled: _walletNewVM.name.isEmpty, - ); - }, + EdgeInsets.all(24), + bottomSection: Column( + children: [ + Observer( + builder: (context) { + return LoadingPrimaryButton( + onPressed: _confirmForm, + text: S.of(context).seed_language_next, + color: Colors.green, + textColor: Colors.white, + isLoading: _walletNewVM.state is IsExecutingState, + isDisabled: _walletNewVM.name.isEmpty, + ); + }, + ), + const SizedBox(height: 25), + GestureDetector( + onTap: () { + Navigator.of(context).pushNamed(Routes.privacySettings); + }, + child: Text(S.of(context).advanced_privacy_settings), + ), + ], )), ); } diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index fa04a6a8e..fa896eb97 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -644,5 +644,8 @@ "choose_from_available_options": "Wähle aus verfügbaren Optionen:", "custom_redeem_amount": "Benutzerdefinierter Einlösungsbetrag", "add_custom_redemption": "Benutzerdefinierte Einlösung hinzufügen", - "remaining": "Rest" + "remaining": "Rest", + "advanced_privacy_settings": "Erweiterte Datenschutzeinstellungen", + "privacy_settings": "Datenschutzeinstellungen", + "settings_can_be_changed_later": "Diese Einstellungen können später in den App-Einstellungen geändert werden" } diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index 4a46d36c8..a79f66cc2 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -644,5 +644,8 @@ "choose_from_available_options": "Choose from the available options:", "custom_redeem_amount": "Custom Redeem Amount", "add_custom_redemption": "Add Custom Redemption", - "remaining": "remaining" + "remaining": "remaining", + "advanced_privacy_settings": "Advanced Privacy Settings", + "privacy_settings": "Privacy Settings", + "settings_can_be_changed_later": "These settings can be changed later in the app settings" } diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index 756ac3e11..b953ccd45 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -644,5 +644,8 @@ "choose_from_available_options": "Elija entre las opciones disponibles:", "custom_redeem_amount": "Cantidad de canje personalizada", "add_custom_redemption": "Agregar redención personalizada", - "remaining": "restante" + "remaining": "restante", + "advanced_privacy_settings": "Configuración avanzada de privacidad", + "privacy_settings": "La configuración de privacidad", + "settings_can_be_changed_later": "Estas configuraciones se pueden cambiar más tarde en la configuración de la aplicación" } diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb index 04462943e..b62ae92a4 100644 --- a/res/values/strings_fr.arb +++ b/res/values/strings_fr.arb @@ -642,5 +642,8 @@ "choose_from_available_options": "Choisissez parmi les options disponibles :", "custom_redeem_amount": "Montant d'échange personnalisé", "add_custom_redemption": "Ajouter un remboursement personnalisé", - "remaining": "restant" + "remaining": "restant", + "advanced_privacy_settings": "Paramètres de confidentialité avancés", + "privacy_settings": "Paramètres de confidentialité", + "settings_can_be_changed_later": "Ces paramètres peuvent être modifiés ultérieurement dans les paramètres de l'application" } diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index f8bad76e2..932118e9a 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -644,5 +644,8 @@ "choose_from_available_options": "उपलब्ध विकल्पों में से चुनें:", "custom_redeem_amount": "कस्टम रिडीम राशि", "add_custom_redemption": "कस्टम रिडेम्पशन जोड़ें", - "remaining": "शेष" + "remaining": "शेष", + "advanced_privacy_settings": "उन्नत गोपनीयता सेटिंग्स", + "privacy_settings": "गोपनीय सेटिंग", + "settings_can_be_changed_later": "इन सेटिंग्स को बाद में ऐप सेटिंग में बदला जा सकता है" } diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index 0e27e3a2c..7eebebdc9 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -644,5 +644,8 @@ "choose_from_available_options": "Odaberite neku od dostupnih opcija:", "custom_redeem_amount": "Prilagođeni iznos otkupa", "add_custom_redemption": "Dodaj prilagođeni otkup", - "remaining": "preostalo" + "remaining": "preostalo", + "advanced_privacy_settings": "Napredne postavke privatnosti", + "privacy_settings": "Postavke privatnosti", + "settings_can_be_changed_later": "Te se postavke mogu promijeniti kasnije u postavkama aplikacije" } diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb index ea9bbd5be..a1333dae4 100644 --- a/res/values/strings_it.arb +++ b/res/values/strings_it.arb @@ -644,5 +644,8 @@ "choose_from_available_options": "Scegli tra le opzioni disponibili:", "custom_redeem_amount": "Importo di riscatto personalizzato", "add_custom_redemption": "Aggiungi riscatto personalizzato", - "remaining": "rimanente" + "remaining": "rimanente", + "advanced_privacy_settings": "Impostazioni avanzate sulla privacy", + "privacy_settings": "Impostazioni della privacy", + "settings_can_be_changed_later": "Queste impostazioni possono essere modificate in seguito nelle impostazioni dell'app" } diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index 5ae3a5a1a..733dc4a00 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -644,5 +644,8 @@ "choose_from_available_options": "利用可能なオプションから選択してください:", "custom_redeem_amount": "カスタム交換金額", "add_custom_redemption": "カスタム引き換えを追加", - "remaining": "残り" + "remaining": "残り", + "advanced_privacy_settings": "高度なプライバシー設定", + "privacy_settings": "プライバシー設定", + "settings_can_be_changed_later": "これらの設定は、後でアプリの設定で変更できます" } diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index f934784ba..c1069c003 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -644,5 +644,8 @@ "choose_from_available_options": "사용 가능한 옵션에서 선택:", "custom_redeem_amount": "사용자 지정 상환 금액", "add_custom_redemption": "사용자 지정 상환 추가", - "remaining": "남은" + "remaining": "남은", + "advanced_privacy_settings": "고급 개인 정보 설정", + "privacy_settings": "개인 정보 설정", + "settings_can_be_changed_later": "이 설정은 나중에 앱 설정에서 변경할 수 있습니다." } diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index 428da3d76..fc3ab96cd 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -644,5 +644,8 @@ "choose_from_available_options": "Kies uit de beschikbare opties:", "custom_redeem_amount": "Aangepast inwisselbedrag", "add_custom_redemption": "Voeg aangepaste inwisseling toe", - "remaining": "resterende" + "remaining": "resterende", + "advanced_privacy_settings": "Geavanceerde privacy-instellingen", + "privacy_settings": "Privacy instellingen", + "settings_can_be_changed_later": "Deze instellingen kunnen later worden gewijzigd in de app-instellingen" } diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index fda0ea721..eb5f9d06c 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -644,5 +644,8 @@ "choose_from_available_options": "Wybierz z dostępnych opcji:", "custom_redeem_amount": "Niestandardowa kwota wykorzystania", "add_custom_redemption": "Dodaj niestandardowe wykorzystanie", - "remaining": "pozostałe" + "remaining": "pozostałe", + "advanced_privacy_settings": "Zaawansowane ustawienia prywatności", + "privacy_settings": "Ustawienia prywatności", + "settings_can_be_changed_later": "Te ustawienia można później zmienić w ustawieniach aplikacji" } diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index 6a55cf534..a33bbb060 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -643,5 +643,8 @@ "choose_from_available_options": "Escolha entre as opções disponíveis:", "custom_redeem_amount": "Valor de resgate personalizado", "add_custom_redemption": "Adicionar resgate personalizado", - "remaining": "restante" + "remaining": "restante", + "advanced_privacy_settings": "Configurações de privacidade avançadas", + "privacy_settings": "Configurações de privacidade", + "settings_can_be_changed_later": "Essas configurações podem ser alteradas posteriormente nas configurações do aplicativo" } diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index ebc4a615c..efa90deec 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -644,5 +644,8 @@ "choose_from_available_options": "Выберите из доступных вариантов:", "custom_redeem_amount": "Пользовательская сумма погашения", "add_custom_redemption": "Добавить пользовательское погашение", - "remaining": "осталось" + "remaining": "осталось", + "advanced_privacy_settings": "Расширенные настройки конфиденциальности", + "privacy_settings": "Настройки конфиденциальности", + "settings_can_be_changed_later": "Эти настройки можно изменить позже в настройках приложения." } diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index efbd5a3b8..fbc47a619 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -643,5 +643,8 @@ "choose_from_available_options": "Виберіть із доступних варіантів:", "custom_redeem_amount": "Власна сума викупу", "add_custom_redemption": "Додати спеціальне погашення", - "remaining": "залишилося" + "remaining": "залишилося", + "advanced_privacy_settings": "Розширені налаштування конфіденційності", + "privacy_settings": "Параметри конфіденційності", + "settings_can_be_changed_later": "Ці параметри можна змінити пізніше в налаштуваннях програми" } diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index 83990cf2e..ae2acd73a 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -642,5 +642,8 @@ "choose_from_available_options": "从可用选项中选择:", "custom_redeem_amount": "自定义兑换金额", "add_custom_redemption": "添加自定义兑换", - "remaining": "剩余" + "remaining": "剩余", + "advanced_privacy_settings": "高级隐私设置", + "privacy_settings": "隐私设置", + "settings_can_be_changed_later": "稍后可以在应用设置中更改这些设置" } From 299df3c087ace7f188d204db8c1623222cbd2f20 Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Wed, 5 Oct 2022 19:28:11 +0200 Subject: [PATCH 04/47] Separate node form to be more reusable Add node form to privacy settings --- lib/di.dart | 25 +-- lib/router.dart | 4 +- .../advanced_privacy_settings_page.dart | 91 ++--------- .../nodes/node_create_or_edit_page.dart | 94 +---------- lib/src/screens/nodes/widgets/node_form.dart | 151 ++++++++++++++++++ .../node_create_or_edit_view_model.dart | 13 +- 6 files changed, 191 insertions(+), 187 deletions(-) create mode 100644 lib/src/screens/nodes/widgets/node_form.dart diff --git a/lib/di.dart b/lib/di.dart index 8dfbfd788..b7f8ce949 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -343,7 +343,7 @@ Future setup( onAuthenticationFinished: onAuthFinished, closable: closable ?? false)); - getIt.registerFactory(() => + getIt.registerFactory(() => BalancePage(dashboardViewModel: getIt.get(), settingsStore: getIt.get())); getIt.registerFactory(() => DashboardPage( balancePage: getIt.get(), walletViewModel: getIt.get(), addressListViewModel: getIt.get())); @@ -478,8 +478,9 @@ Future setup( getIt.registerFactory(() => NodeListPage(getIt.get())); - getIt.registerFactory(() => - NodeCreateOrEditViewModel(_nodeSource, getIt.get().wallet)); + getIt.registerFactoryParam( + (WalletType type, _) => + NodeCreateOrEditViewModel(_nodeSource, type ?? getIt.get().wallet.type)); getIt.registerFactory( () => NodeCreateOrEditPage(getIt.get())); @@ -672,7 +673,7 @@ Future setup( getIt.registerFactoryParam( (String qrData, bool isLight) => FullscreenQRPage(qrData: qrData, isLight: isLight,)); - + getIt.registerFactory(() => IoniaApi()); getIt.registerFactory(() => AnyPayApi()); @@ -692,7 +693,7 @@ Future setup( getIt.registerFactoryParam((double amount, merchant) { return IoniaMerchPurchaseViewModel( - ioniaAnyPayService: getIt.get(), + ioniaAnyPayService: getIt.get(), amount: amount, ioniaMerchant: merchant, ); @@ -734,31 +735,31 @@ Future setup( ioniaService: getIt.get(), giftCard: giftCard); }); - + getIt.registerFactoryParam((List args, _) { final amount = args[0] as double; final merchant = args[1] as IoniaMerchant; final tip = args[2] as IoniaTip; - + return IoniaCustomTipViewModel(amount: amount, tip: tip, ioniaMerchant: merchant); }); - + getIt.registerFactoryParam((IoniaGiftCard giftCard, _) { return IoniaGiftCardDetailPage(getIt.get(param1: giftCard)); }); getIt.registerFactoryParam((List args, _){ final giftCard = args.first as IoniaGiftCard; - - return IoniaMoreOptionsPage(giftCard); + + return IoniaMoreOptionsPage(giftCard); }); getIt.registerFactoryParam((IoniaGiftCard giftCard, _) => IoniaCustomRedeemViewModel(giftCard)); getIt.registerFactoryParam((List args, _){ final giftCard = args.first as IoniaGiftCard; - - return IoniaCustomRedeemPage(getIt.get(param1: giftCard) ); + + return IoniaCustomRedeemPage(getIt.get(param1: giftCard) ); }); diff --git a/lib/router.dart b/lib/router.dart index b19fb198e..fd820b764 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -20,6 +20,7 @@ import 'package:cake_wallet/src/screens/support/support_page.dart'; import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart'; import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart'; import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart'; +import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart'; import 'package:cake_wallet/view_model/privacy_settings_view_model.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -476,9 +477,10 @@ Route createRoute(RouteSettings settings) { case Routes.privacySettings: final type = settings.arguments as WalletType; final privacySettingsViewModel = getIt.get(param1: type); + final nodeCreateViewModel = getIt.get(param1: type); return CupertinoPageRoute( - builder: (_) => AdvancedPrivacySettingsPage(privacySettingsViewModel)); + builder: (_) => AdvancedPrivacySettingsPage(privacySettingsViewModel, nodeCreateViewModel)); default: return MaterialPageRoute( diff --git a/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart index 149b65d2e..e22afeb92 100644 --- a/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart +++ b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart @@ -1,49 +1,50 @@ -import 'package:cake_wallet/entities/generate_name.dart'; +import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart'; +import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart'; import 'package:cake_wallet/view_model/privacy_settings_view_model.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/core/wallet_name_validator.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/widgets/primary_button.dart'; import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; class AdvancedPrivacySettingsPage extends BasePage { - AdvancedPrivacySettingsPage(this.privacySettingsViewModel); + AdvancedPrivacySettingsPage(this.privacySettingsViewModel, this.nodeViewModel); final PrivacySettingsViewModel privacySettingsViewModel; + final NodeCreateOrEditViewModel nodeViewModel; @override String get title => S.current.privacy_settings; @override Widget body(BuildContext context) => - AdvancedPrivacySettingsBody(privacySettingsViewModel); + AdvancedPrivacySettingsBody(privacySettingsViewModel, nodeViewModel); } class AdvancedPrivacySettingsBody extends StatefulWidget { - const AdvancedPrivacySettingsBody(this.privacySettingsViewModel, {Key key}) + const AdvancedPrivacySettingsBody(this.privacySettingsViewModel, this.nodeViewModel, {Key key}) : super(key: key); final PrivacySettingsViewModel privacySettingsViewModel; + final NodeCreateOrEditViewModel nodeViewModel; @override _AdvancedPrivacySettingsBodyState createState() => - _AdvancedPrivacySettingsBodyState(privacySettingsViewModel); + _AdvancedPrivacySettingsBodyState(privacySettingsViewModel, nodeViewModel); } class _AdvancedPrivacySettingsBodyState extends State { - _AdvancedPrivacySettingsBodyState(this.privacySettingsViewModel); + _AdvancedPrivacySettingsBodyState(this.privacySettingsViewModel, this.nodeViewModel); final PrivacySettingsViewModel privacySettingsViewModel; + final NodeCreateOrEditViewModel nodeViewModel; final _formKey = GlobalKey(); - final TextEditingController _controller = TextEditingController(); - @override Widget build(BuildContext context) { return Container( @@ -67,75 +68,9 @@ class _AdvancedPrivacySettingsBodyState if (privacySettingsViewModel.addCustomNode) { return Padding( padding: EdgeInsets.only(top: 24), - child: Form( - key: _formKey, - child: TextFormField( - onChanged: (value) {}, - controller: _controller, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 20.0, - fontWeight: FontWeight.w600, - color: - Theme.of(context).primaryTextTheme.title.color), - decoration: InputDecoration( - hintStyle: TextStyle( - fontSize: 18.0, - fontWeight: FontWeight.w500, - color: Theme.of(context) - .accentTextTheme - .display3 - .color), - hintText: S.of(context).wallet_name, - focusedBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: Theme.of(context) - .accentTextTheme - .display3 - .decorationColor, - width: 1.0), - ), - enabledBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: Theme.of(context) - .accentTextTheme - .display3 - .decorationColor, - width: 1.0), - ), - suffixIcon: IconButton( - onPressed: () async { - final rName = await generateName(); - FocusManager.instance.primaryFocus?.unfocus(); - - setState(() { - _controller.text = rName; - _controller.selection = - TextSelection.fromPosition( - TextPosition(offset: _controller.text.length), - ); - }); - }, - icon: Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(6.0), - color: Theme.of(context).hintColor, - ), - width: 34, - height: 34, - child: Image.asset( - 'assets/images/refresh_icon.png', - color: Theme.of(context) - .primaryTextTheme - .display1 - .decorationColor, - ), - ), - ), - ), - validator: WalletNameValidator(), - ), + child: NodeForm( + formKey: _formKey, + nodeViewModel: nodeViewModel, ), ); } diff --git a/lib/src/screens/nodes/node_create_or_edit_page.dart b/lib/src/screens/nodes/node_create_or_edit_page.dart index 857bde023..e4864cc91 100644 --- a/lib/src/screens/nodes/node_create_or_edit_page.dart +++ b/lib/src/screens/nodes/node_create_or_edit_page.dart @@ -1,16 +1,13 @@ import 'package:cake_wallet/core/execution_state.dart'; +import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; -import 'package:cake_wallet/src/widgets/standard_checkbox.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:mobx/mobx.dart'; import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/core/node_address_validator.dart'; -import 'package:cake_wallet/core/node_port_validator.dart'; import 'package:cake_wallet/src/widgets/primary_button.dart'; -import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart'; @@ -108,91 +105,10 @@ class NodeCreateOrEditPage extends BasePage { padding: EdgeInsets.only(left: 24, right: 24), child: ScrollableWithBottomSection( contentPadding: EdgeInsets.only(bottom: 24.0), - content: Form( - key: _formKey, - child: Column( - children: [ - Row( - children: [ - Expanded( - child: BaseTextFormField( - controller: _addressController, - hintText: S.of(context).node_address, - validator: NodeAddressValidator(), - ) - ) - ], - ), - SizedBox(height: 10.0), - Row( - children: [ - Expanded( - child: BaseTextFormField( - controller: _portController, - hintText: S.of(context).node_port, - keyboardType: TextInputType.numberWithOptions( - signed: false, decimal: false), - validator: NodePortValidator(), - ) - ) - ], - ), - SizedBox(height: 10.0), - if (nodeCreateOrEditViewModel.hasAuthCredentials) ...[ - Row( - children: [ - Expanded( - child: BaseTextFormField( - controller: _loginController, - hintText: S.of(context).login, - ) - ) - ], - ), - SizedBox(height: 10.0), - Row( - children: [ - Expanded( - child: BaseTextFormField( - controller: _passwordController, - hintText: S.of(context).password, - ) - ) - ], - ), - Padding( - padding: EdgeInsets.only(top: 20), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - mainAxisSize: MainAxisSize.max, - children: [ - Observer( - builder: (_) => StandardCheckbox( - value: nodeCreateOrEditViewModel.useSSL, - onChanged: (value) => - nodeCreateOrEditViewModel.useSSL = value, - caption: S.of(context).use_ssl, - )) - ], - )), - Padding( - padding: EdgeInsets.only(top: 20), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - mainAxisSize: MainAxisSize.max, - children: [ - Observer( - builder: (_) => StandardCheckbox( - value: nodeCreateOrEditViewModel.trusted, - onChanged: (value) => - nodeCreateOrEditViewModel.trusted = value, - caption: S.of(context).trusted, - )) - ], - )), - ] - ], - )), + content: NodeForm( + formKey: _formKey, + nodeViewModel: nodeCreateOrEditViewModel, + ), bottomSectionPadding: EdgeInsets.only(bottom: 24), bottomSection: Observer( builder: (_) => Row( diff --git a/lib/src/screens/nodes/widgets/node_form.dart b/lib/src/screens/nodes/widgets/node_form.dart new file mode 100644 index 000000000..757032a2a --- /dev/null +++ b/lib/src/screens/nodes/widgets/node_form.dart @@ -0,0 +1,151 @@ +import 'package:cake_wallet/core/node_address_validator.dart'; +import 'package:cake_wallet/core/node_port_validator.dart'; +import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; +import 'package:cake_wallet/src/widgets/standard_checkbox.dart'; +import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:mobx/mobx.dart'; + +class NodeForm extends StatelessWidget { + NodeForm({ + @required this.nodeViewModel, + @required this.formKey, + }) : _addressController = TextEditingController(), + _portController = TextEditingController(), + _loginController = TextEditingController(), + _passwordController = TextEditingController() { + reaction((_) => nodeViewModel.address, (String address) { + if (address != _addressController.text) { + _addressController.text = address; + } + }); + + reaction((_) => nodeViewModel.port, (String port) { + if (port != _portController.text) { + _portController.text = port; + } + }); + + if (nodeViewModel.hasAuthCredentials) { + reaction((_) => nodeViewModel.login, (String login) { + if (login != _loginController.text) { + _loginController.text = login; + } + }); + + reaction((_) => nodeViewModel.password, (String password) { + if (password != _passwordController.text) { + _passwordController.text = password; + } + }); + } + + _addressController + .addListener(() => nodeViewModel.address = _addressController.text); + _portController + .addListener(() => nodeViewModel.port = _portController.text); + _loginController + .addListener(() => nodeViewModel.login = _loginController.text); + _passwordController + .addListener(() => nodeViewModel.password = _passwordController.text); + } + + final NodeCreateOrEditViewModel nodeViewModel; + final GlobalKey formKey; + + final TextEditingController _addressController; + final TextEditingController _portController; + final TextEditingController _loginController; + final TextEditingController _passwordController; + + @override + Widget build(BuildContext context) { + return Form( + key: formKey, + child: Column( + children: [ + Row( + children: [ + Expanded( + child: BaseTextFormField( + controller: _addressController, + hintText: S.of(context).node_address, + validator: NodeAddressValidator(), + ), + ) + ], + ), + SizedBox(height: 10.0), + Row( + children: [ + Expanded( + child: BaseTextFormField( + controller: _portController, + hintText: S.of(context).node_port, + keyboardType: TextInputType.numberWithOptions( + signed: false, decimal: false), + validator: NodePortValidator(), + )) + ], + ), + SizedBox(height: 10.0), + if (nodeViewModel.hasAuthCredentials) ...[ + Row( + children: [ + Expanded( + child: BaseTextFormField( + controller: _loginController, + hintText: S.of(context).login, + )) + ], + ), + SizedBox(height: 10.0), + Row( + children: [ + Expanded( + child: BaseTextFormField( + controller: _passwordController, + hintText: S.of(context).password, + )) + ], + ), + Padding( + padding: EdgeInsets.only(top: 20), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Observer( + builder: (_) => StandardCheckbox( + value: nodeViewModel.useSSL, + onChanged: (value) => nodeViewModel.useSSL = value, + caption: S.of(context).use_ssl, + ), + ) + ], + ), + ), + Padding( + padding: EdgeInsets.only(top: 20), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Observer( + builder: (_) => StandardCheckbox( + value: nodeViewModel.trusted, + onChanged: (value) => nodeViewModel.trusted = value, + caption: S.of(context).trusted, + ), + ), + ], + ), + ), + ] + ], + ), + ); + } +} diff --git a/lib/view_model/node_list/node_create_or_edit_view_model.dart b/lib/view_model/node_list/node_create_or_edit_view_model.dart index c14bdda5e..be6e3e316 100644 --- a/lib/view_model/node_list/node_create_or_edit_view_model.dart +++ b/lib/view_model/node_list/node_create_or_edit_view_model.dart @@ -1,7 +1,6 @@ import 'package:cake_wallet/core/execution_state.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; -import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/node.dart'; import 'package:cw_core/wallet_type.dart'; @@ -11,7 +10,7 @@ class NodeCreateOrEditViewModel = NodeCreateOrEditViewModelBase with _$NodeCreateOrEditViewModel; abstract class NodeCreateOrEditViewModelBase with Store { - NodeCreateOrEditViewModelBase(this._nodeSource, this._wallet) + NodeCreateOrEditViewModelBase(this._nodeSource, this._walletType) : state = InitialExecutionState(), connectionState = InitialExecutionState(), useSSL = false, @@ -45,8 +44,8 @@ abstract class NodeCreateOrEditViewModelBase with Store { bool get isReady => (address?.isNotEmpty ?? false) && (port?.isNotEmpty ?? false); - bool get hasAuthCredentials => _wallet.type == WalletType.monero || - _wallet.type == WalletType.haven; + bool get hasAuthCredentials => _walletType == WalletType.monero || + _walletType == WalletType.haven; String get uri { var uri = address; @@ -58,7 +57,7 @@ abstract class NodeCreateOrEditViewModelBase with Store { return uri; } - final WalletBase _wallet; + final WalletType _walletType; final Box _nodeSource; @action @@ -76,7 +75,7 @@ abstract class NodeCreateOrEditViewModelBase with Store { try { state = IsExecutingState(); final node = - Node(uri: uri, type: _wallet.type, login: login, password: password, + Node(uri: uri, type: _walletType, login: login, password: password, useSSL: useSSL, trusted: trusted); await _nodeSource.add(node); state = ExecutedSuccessfullyState(); @@ -90,7 +89,7 @@ abstract class NodeCreateOrEditViewModelBase with Store { try { connectionState = IsExecutingState(); final node = - Node(uri: uri, type: _wallet.type, login: login, password: password); + Node(uri: uri, type: _walletType, login: login, password: password); final isAlive = await node.requestNode(); connectionState = ExecutedSuccessfullyState(payload: isAlive); } catch (e) { From 3c04bd9aa5899f3e626876af28adc4c270ab6546 Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Wed, 5 Oct 2022 20:07:16 +0200 Subject: [PATCH 05/47] Pass wallet type when navigating Fix UI padding --- .../screens/new_wallet/advanced_privacy_settings_page.dart | 4 ++-- lib/src/screens/new_wallet/new_wallet_page.dart | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart index e22afeb92..cb3e4e8dc 100644 --- a/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart +++ b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart @@ -50,7 +50,7 @@ class _AdvancedPrivacySettingsBodyState return Container( padding: EdgeInsets.only(top: 24), child: ScrollableWithBottomSection( - contentPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24), + contentPadding: EdgeInsets.only(bottom: 24), content: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ @@ -67,7 +67,7 @@ class _AdvancedPrivacySettingsBodyState builder: (_) { if (privacySettingsViewModel.addCustomNode) { return Padding( - padding: EdgeInsets.only(top: 24), + padding: EdgeInsets.only(left: 24, right: 24, top: 24), child: NodeForm( formKey: _formKey, nodeViewModel: nodeViewModel, diff --git a/lib/src/screens/new_wallet/new_wallet_page.dart b/lib/src/screens/new_wallet/new_wallet_page.dart index 8aef74445..6bbd9e72d 100644 --- a/lib/src/screens/new_wallet/new_wallet_page.dart +++ b/lib/src/screens/new_wallet/new_wallet_page.dart @@ -216,7 +216,8 @@ class _WalletNameFormState extends State { const SizedBox(height: 25), GestureDetector( onTap: () { - Navigator.of(context).pushNamed(Routes.privacySettings); + Navigator.of(context) + .pushNamed(Routes.privacySettings, arguments: _walletNewVM.type); }, child: Text(S.of(context).advanced_privacy_settings), ), From cb9f69074563e0e81199413f54ab9f279dc16033 Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Fri, 7 Oct 2022 15:25:20 +0200 Subject: [PATCH 06/47] Add Native setTrustedDaemon and trustedDaemon functions and integrate them with their wallets --- cw_haven/ios/Classes/haven_api.cpp | 10 ++++++++++ cw_haven/lib/api/signatures.dart | 6 +++++- cw_haven/lib/api/types.dart | 6 +++++- cw_haven/lib/api/wallet.dart | 12 ++++++++++++ cw_haven/lib/haven_wallet.dart | 4 ++++ cw_monero/ios/Classes/monero_api.cpp | 10 ++++++++++ cw_monero/ios/Classes/monero_api.h | 3 +++ cw_monero/lib/api/signatures.dart | 6 +++++- cw_monero/lib/api/types.dart | 6 +++++- cw_monero/lib/api/wallet.dart | 14 +++++++++++++- cw_monero/lib/monero_wallet.dart | 4 ++++ .../node_list/node_create_or_edit_view_model.dart | 7 +++++++ 12 files changed, 83 insertions(+), 5 deletions(-) diff --git a/cw_haven/ios/Classes/haven_api.cpp b/cw_haven/ios/Classes/haven_api.cpp index c1013bf87..aecaf0016 100644 --- a/cw_haven/ios/Classes/haven_api.cpp +++ b/cw_haven/ios/Classes/haven_api.cpp @@ -927,6 +927,16 @@ extern "C" return static_cast(rates.size()); } + void set_trusted_daemon(bool arg) + { + m_wallet->setTrustedDaemon(arg); + } + + bool trusted_daemon() + { + return m_wallet->trustedDaemon(); + } + #ifdef __cplusplus } #endif diff --git a/cw_haven/lib/api/signatures.dart b/cw_haven/lib/api/signatures.dart index 9dd1c8dac..c98926c51 100644 --- a/cw_haven/lib/api/signatures.dart +++ b/cw_haven/lib/api/signatures.dart @@ -137,4 +137,8 @@ typedef get_rate = Pointer Function(); typedef size_of_rate = Int32 Function(); -typedef update_rate = Void Function(); \ No newline at end of file +typedef update_rate = Void Function(); + +typedef set_trusted_daemon = Void Function(Int8 trusted); + +typedef trusted_daemon = Int8 Function(); \ No newline at end of file diff --git a/cw_haven/lib/api/types.dart b/cw_haven/lib/api/types.dart index 878297501..81661afc2 100644 --- a/cw_haven/lib/api/types.dart +++ b/cw_haven/lib/api/types.dart @@ -135,4 +135,8 @@ typedef GetRate = Pointer Function(); typedef SizeOfRate = int Function(); -typedef UpdateRate = void Function(); \ No newline at end of file +typedef UpdateRate = void Function(); + +typedef SetTrustedDaemon = void Function(int); + +typedef TrustedDaemon = int Function(); \ No newline at end of file diff --git a/cw_haven/lib/api/wallet.dart b/cw_haven/lib/api/wallet.dart index 3370fd3e0..96e6e80a6 100644 --- a/cw_haven/lib/api/wallet.dart +++ b/cw_haven/lib/api/wallet.dart @@ -116,6 +116,14 @@ final rescanBlockchainAsyncNative = havenApi .lookup>('rescan_blockchain') .asFunction(); +final setTrustedDaemonNative = havenApi + .lookup>('set_trusted_daemon') + .asFunction(); + +final trustedDaemonNative = havenApi + .lookup>('trusted_daemon') + .asFunction(); + int getSyncingHeight() => getSyncingHeightNative(); bool isNeededToRefresh() => isNeededToRefreshNative() != 0; @@ -346,3 +354,7 @@ Future isConnected() => compute(_isConnected, 0); Future getNodeHeight() => compute(_getNodeHeight, 0); void rescanBlockchainAsync() => rescanBlockchainAsyncNative(); + +Future setTrustedDaemon(bool trusted) async => setTrustedDaemonNative(_boolToInt(trusted)); + +Future trustedDaemon() async => trustedDaemonNative() != 0; diff --git a/cw_haven/lib/haven_wallet.dart b/cw_haven/lib/haven_wallet.dart index c107d2f52..4a08a183a 100644 --- a/cw_haven/lib/haven_wallet.dart +++ b/cw_haven/lib/haven_wallet.dart @@ -390,4 +390,8 @@ abstract class HavenWalletBase extends WalletBase haven_wallet.setTrustedDaemon(arg); + + Future trustedDaemon() async => haven_wallet.trustedDaemon(); } diff --git a/cw_monero/ios/Classes/monero_api.cpp b/cw_monero/ios/Classes/monero_api.cpp index 6bb251dcf..117214295 100644 --- a/cw_monero/ios/Classes/monero_api.cpp +++ b/cw_monero/ios/Classes/monero_api.cpp @@ -783,6 +783,16 @@ extern "C" return strdup(get_current_wallet()->getSubaddressLabel(accountIndex, addressIndex).c_str()); } + void set_trusted_daemon(bool arg) + { + m_wallet->setTrustedDaemon(arg); + } + + bool trusted_daemon() + { + return m_wallet->trustedDaemon(); + } + #ifdef __cplusplus } #endif diff --git a/cw_monero/ios/Classes/monero_api.h b/cw_monero/ios/Classes/monero_api.h index 3e2ebcff2..74258ba4c 100644 --- a/cw_monero/ios/Classes/monero_api.h +++ b/cw_monero/ios/Classes/monero_api.h @@ -30,6 +30,9 @@ void set_refresh_from_block_height(uint64_t height); void set_recovering_from_seed(bool is_recovery); void store(char *path); +void set_trusted_daemon(bool arg); +bool trusted_daemon(); + #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/cw_monero/lib/api/signatures.dart b/cw_monero/lib/api/signatures.dart index 16f983480..3de4fd1a5 100644 --- a/cw_monero/lib/api/signatures.dart +++ b/cw_monero/lib/api/signatures.dart @@ -125,4 +125,8 @@ typedef rescan_blockchain = Void Function(); typedef get_subaddress_label = Pointer Function( Int32 accountIndex, - Int32 addressIndex); \ No newline at end of file + Int32 addressIndex); + +typedef set_trusted_daemon = Void Function(Int8 trusted); + +typedef trusted_daemon = Int8 Function(); \ No newline at end of file diff --git a/cw_monero/lib/api/types.dart b/cw_monero/lib/api/types.dart index 3438b89fc..e328b776a 100644 --- a/cw_monero/lib/api/types.dart +++ b/cw_monero/lib/api/types.dart @@ -123,4 +123,8 @@ typedef RescanBlockchainAsync = void Function(); typedef GetSubaddressLabel = Pointer Function( int accountIndex, - int addressIndex); \ No newline at end of file + int addressIndex); + +typedef SetTrustedDaemon = void Function(int); + +typedef TrustedDaemon = int Function(); \ No newline at end of file diff --git a/cw_monero/lib/api/wallet.dart b/cw_monero/lib/api/wallet.dart index 9e84d7865..aeda971d8 100644 --- a/cw_monero/lib/api/wallet.dart +++ b/cw_monero/lib/api/wallet.dart @@ -120,6 +120,14 @@ final getSubaddressLabelNative = moneroApi .lookup>('get_subaddress_label') .asFunction(); +final setTrustedDaemonNative = moneroApi + .lookup>('set_trusted_daemon') + .asFunction(); + +final trustedDaemonNative = moneroApi + .lookup>('trusted_daemon') + .asFunction(); + int getSyncingHeight() => getSyncingHeightNative(); bool isNeededToRefresh() => isNeededToRefreshNative() != 0; @@ -353,4 +361,8 @@ void rescanBlockchainAsync() => rescanBlockchainAsyncNative(); String getSubaddressLabel(int accountIndex, int addressIndex) { return convertUTF8ToString(pointer: getSubaddressLabelNative(accountIndex, addressIndex)); -} \ No newline at end of file +} + +Future setTrustedDaemon(bool trusted) async => setTrustedDaemonNative(_boolToInt(trusted)); + +Future trustedDaemon() async => trustedDaemonNative() != 0; \ No newline at end of file diff --git a/cw_monero/lib/monero_wallet.dart b/cw_monero/lib/monero_wallet.dart index 175bd96f5..772df420c 100644 --- a/cw_monero/lib/monero_wallet.dart +++ b/cw_monero/lib/monero_wallet.dart @@ -427,4 +427,8 @@ abstract class MoneroWalletBase extends WalletBase monero_wallet.setTrustedDaemon(arg); + + Future trustedDaemon() async => monero_wallet.trustedDaemon(); } diff --git a/lib/view_model/node_list/node_create_or_edit_view_model.dart b/lib/view_model/node_list/node_create_or_edit_view_model.dart index c14bdda5e..4b7e0ddc9 100644 --- a/lib/view_model/node_list/node_create_or_edit_view_model.dart +++ b/lib/view_model/node_list/node_create_or_edit_view_model.dart @@ -1,4 +1,6 @@ import 'package:cake_wallet/core/execution_state.dart'; +import 'package:cw_haven/haven_wallet.dart'; +import 'package:cw_monero/monero_wallet.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; import 'package:cw_core/wallet_base.dart'; @@ -78,6 +80,11 @@ abstract class NodeCreateOrEditViewModelBase with Store { final node = Node(uri: uri, type: _wallet.type, login: login, password: password, useSSL: useSSL, trusted: trusted); + if (_wallet.type == WalletType.monero) { + (_wallet as MoneroWallet).setTrustedDaemon(trusted); + } else if (_wallet.type == WalletType.haven) { + (_wallet as HavenWallet).setTrustedDaemon(trusted); + } await _nodeSource.add(node); state = ExecutedSuccessfullyState(); } catch (e) { From b0e188c0bd154ca9b95658a74d9369b0274bcc31 Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Fri, 7 Oct 2022 20:06:33 +0200 Subject: [PATCH 07/47] Remove unused getter --- cw_core/lib/node.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/cw_core/lib/node.dart b/cw_core/lib/node.dart index dd5969b99..dca429482 100644 --- a/cw_core/lib/node.dart +++ b/cw_core/lib/node.dart @@ -57,8 +57,6 @@ class Node extends HiveObject with Keyable { bool get isSSL => useSSL ?? false; - bool get isTrusted => trusted ?? false; - Uri get uri { switch (type) { case WalletType.monero: From 1eb9e65617e85ef2d70d7c324865c8cde8137565 Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Thu, 20 Oct 2022 20:24:01 +0200 Subject: [PATCH 08/47] Set trusted daemon after node connection --- cw_haven/lib/haven_wallet.dart | 6 ++---- cw_monero/lib/monero_wallet.dart | 6 ++---- .../node_list/node_create_or_edit_view_model.dart | 7 ------- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/cw_haven/lib/haven_wallet.dart b/cw_haven/lib/haven_wallet.dart index 00d37ee08..14ff2f88e 100644 --- a/cw_haven/lib/haven_wallet.dart +++ b/cw_haven/lib/haven_wallet.dart @@ -121,6 +121,8 @@ abstract class HavenWalletBase extends WalletBase haven_wallet.setTrustedDaemon(arg); - - Future trustedDaemon() async => haven_wallet.trustedDaemon(); } diff --git a/cw_monero/lib/monero_wallet.dart b/cw_monero/lib/monero_wallet.dart index ff0104015..86a0358f0 100644 --- a/cw_monero/lib/monero_wallet.dart +++ b/cw_monero/lib/monero_wallet.dart @@ -136,6 +136,8 @@ abstract class MoneroWalletBase extends WalletBase monero_wallet.setTrustedDaemon(arg); - - Future trustedDaemon() async => monero_wallet.trustedDaemon(); } diff --git a/lib/view_model/node_list/node_create_or_edit_view_model.dart b/lib/view_model/node_list/node_create_or_edit_view_model.dart index 7b481f356..e24692059 100644 --- a/lib/view_model/node_list/node_create_or_edit_view_model.dart +++ b/lib/view_model/node_list/node_create_or_edit_view_model.dart @@ -1,6 +1,4 @@ import 'package:cake_wallet/core/execution_state.dart'; -import 'package:cw_haven/haven_wallet.dart'; -import 'package:cw_monero/monero_wallet.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; import 'package:cw_core/wallet_base.dart'; @@ -84,11 +82,6 @@ abstract class NodeCreateOrEditViewModelBase with Store { final node = Node(uri: uri, type: _wallet.type, login: login, password: password, useSSL: useSSL, trusted: trusted); - if (_wallet.type == WalletType.monero) { - (_wallet as MoneroWallet).setTrustedDaemon(trusted); - } else if (_wallet.type == WalletType.haven) { - (_wallet as HavenWallet).setTrustedDaemon(trusted); - } await _nodeSource.add(node); state = ExecutedSuccessfullyState(); } catch (e) { From 2cd748c151488a8378d1e28c25a98588ad163c6e Mon Sep 17 00:00:00 2001 From: Serhii Date: Sat, 5 Nov 2022 20:05:55 +0200 Subject: [PATCH 09/47] filter contacts and wallets by type --- lib/di.dart | 9 ++++--- lib/router.dart | 8 ++++-- .../screens/contact/contact_list_page.dart | 25 +++++++++++-------- .../exchange/widgets/exchange_card.dart | 3 ++- lib/src/screens/send/widgets/send_card.dart | 1 + lib/src/widgets/address_text_field.dart | 7 ++++-- .../contact_list/contact_list_view_model.dart | 17 +++++++++++++ 7 files changed, 51 insertions(+), 19 deletions(-) diff --git a/lib/di.dart b/lib/di.dart index 7ce2ff6d9..01d77b881 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -153,6 +153,7 @@ import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart'; import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart'; import 'package:cake_wallet/src/screens/receive/fullscreen_qr_page.dart'; import 'package:cake_wallet/core/wallet_loading_service.dart'; +import 'package:cw_core/crypto_currency.dart'; final getIt = GetIt.instance; @@ -461,9 +462,11 @@ Future setup( getIt.registerFactory( () => ContactListViewModel(_contactSource, _walletInfoSource)); - getIt.registerFactoryParam( - (bool isEditable, _) => ContactListPage(getIt.get(), - isEditable: isEditable)); + getIt.registerFactoryParam((bool isEditable, CryptoCurrency? cur) + => ContactListPage( + getIt.get(), + isEditable: isEditable, + selectedCurrency: cur)); getIt.registerFactoryParam( (ContactRecord? contact, _) => diff --git a/lib/router.dart b/lib/router.dart index b255ce8b9..8b43fbaf5 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -74,6 +74,7 @@ import 'package:cake_wallet/src/screens/ionia/ionia.dart'; import 'package:cake_wallet/src/screens/ionia/cards/ionia_payment_status_page.dart'; import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart'; import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart'; +import 'package:cw_core/crypto_currency.dart'; late RouteSettings currentRouteSettings; @@ -298,11 +299,14 @@ Route createRoute(RouteSettings settings) { case Routes.addressBook: return MaterialPageRoute( - builder: (_) => getIt.get(param1: true)); + builder: (_) => + getIt.get(param1: true, param2: null)); case Routes.pickerAddressBook: + final selectedCurrency = settings.arguments as CryptoCurrency; return MaterialPageRoute( - builder: (_) => getIt.get(param1: false)); + builder: (_) => getIt.get(param1: false, + param2: selectedCurrency)); case Routes.addressBookAddContact: return CupertinoPageRoute( diff --git a/lib/src/screens/contact/contact_list_page.dart b/lib/src/screens/contact/contact_list_page.dart index 7912472d8..6d23518b8 100644 --- a/lib/src/screens/contact/contact_list_page.dart +++ b/lib/src/screens/contact/contact_list_page.dart @@ -16,10 +16,12 @@ import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart import 'package:cake_wallet/src/widgets/collapsible_standart_list.dart'; class ContactListPage extends BasePage { - ContactListPage(this.contactListViewModel, {this.isEditable = true}); + ContactListPage(this.contactListViewModel, + {this.isEditable = true, required this.selectedCurrency}); final ContactListViewModel contactListViewModel; final bool isEditable; + final CryptoCurrency? selectedCurrency; @override String get title => S.current.address_book; @@ -60,11 +62,13 @@ class ContactListPage extends BasePage { @override Widget body(BuildContext context) { + final contacts = + contactListViewModel.getContacts(isEditable, selectedCurrency); + final walletContacts = + contactListViewModel.getWallets(isEditable, selectedCurrency); return Container( padding: EdgeInsets.only(top: 20.0, bottom: 20.0), - child: Observer( - builder: (_) { - return CollapsibleSectionList( + child: CollapsibleSectionList( context: context, sectionCount: 2, themeColor: Theme.of(context).primaryTextTheme.headline6!.color!, @@ -82,15 +86,15 @@ class ContactListPage extends BasePage { child: Text(title, style: TextStyle(fontSize: 36))); }, itemCounter: (int sectionIndex) => sectionIndex == 0 - ? contactListViewModel.walletContacts.length - : contactListViewModel.contacts.length, + ? walletContacts.length + : contacts.length, itemBuilder: (_, sectionIndex, index) { if (sectionIndex == 0) { - final walletInfo = contactListViewModel.walletContacts[index]; + final walletInfo = walletContacts[index]; return generateRaw(context, walletInfo); } - final contact = contactListViewModel.contacts[index]; + final contact = contacts[index]; final content = generateRaw(context, contact); return !isEditable ? content @@ -100,9 +104,8 @@ class ContactListPage extends BasePage { child: content, ); }, - ); - }, - )); + ) + ); } Widget generateRaw(BuildContext context, ContactBase contact) { diff --git a/lib/src/screens/exchange/widgets/exchange_card.dart b/lib/src/screens/exchange/widgets/exchange_card.dart index 98843b1fb..40aa679a4 100644 --- a/lib/src/screens/exchange/widgets/exchange_card.dart +++ b/lib/src/screens/exchange/widgets/exchange_card.dart @@ -395,7 +395,8 @@ class ExchangeCardState extends State { buttonColor: widget.addressButtonsColor, validator: widget.addressTextFieldValidator, onPushPasteButton: widget.onPushPasteButton, - onPushAddressBookButton: widget.onPushAddressBookButton + onPushAddressBookButton: widget.onPushAddressBookButton, + selectedCurrency: _selectedCurrency ), ) diff --git a/lib/src/screens/send/widgets/send_card.dart b/lib/src/screens/send/widgets/send_card.dart index dc589923f..03e4471fe 100644 --- a/lib/src/screens/send/widgets/send_card.dart +++ b/lib/src/screens/send/widgets/send_card.dart @@ -155,6 +155,7 @@ class SendCardState extends State await output.fetchParsedAddress(context); }, validator: validator, + selectedCurrency: sendViewModel.currency, ); }), if (output.isParsedAddress) Padding( diff --git a/lib/src/widgets/address_text_field.dart b/lib/src/widgets/address_text_field.dart index 35bf3ed85..7e0727312 100644 --- a/lib/src/widgets/address_text_field.dart +++ b/lib/src/widgets/address_text_field.dart @@ -4,6 +4,7 @@ import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/entities/qr_scanner.dart'; import 'package:cake_wallet/entities/contact_base.dart'; +import 'package:cw_core/crypto_currency.dart'; enum AddressTextFieldOption { paste, qrCode, addressBook } @@ -26,7 +27,8 @@ class AddressTextField extends StatelessWidget { this.hintStyle, this.validator, this.onPushPasteButton, - this.onPushAddressBookButton}); + this.onPushAddressBookButton, + this.selectedCurrency}); static const prefixIconWidth = 34.0; static const prefixIconHeight = 34.0; @@ -47,6 +49,7 @@ class AddressTextField extends StatelessWidget { final FocusNode? focusNode; final Function(BuildContext context)? onPushPasteButton; final Function(BuildContext context)? onPushAddressBookButton; + final CryptoCurrency? selectedCurrency; @override Widget build(BuildContext context) { @@ -207,7 +210,7 @@ class AddressTextField extends StatelessWidget { Future _presetAddressBookPicker(BuildContext context) async { final contact = await Navigator.of(context, rootNavigator: true) - .pushNamed(Routes.pickerAddressBook); + .pushNamed(Routes.pickerAddressBook,arguments: selectedCurrency); if (contact is ContactBase && contact.address != null) { controller?.text = contact.address; diff --git a/lib/view_model/contact_list/contact_list_view_model.dart b/lib/view_model/contact_list/contact_list_view_model.dart index ec145ad44..0f67245af 100644 --- a/lib/view_model/contact_list/contact_list_view_model.dart +++ b/lib/view_model/contact_list/contact_list_view_model.dart @@ -7,6 +7,7 @@ import 'package:mobx/mobx.dart'; import 'package:cake_wallet/entities/contact_record.dart'; import 'package:cake_wallet/entities/contact.dart'; import 'package:cake_wallet/utils/mobx.dart'; +import 'package:cw_core/crypto_currency.dart'; part 'contact_list_view_model.g.dart'; @@ -44,4 +45,20 @@ abstract class ContactListViewModelBase with Store { StreamSubscription? _subscription; Future delete(ContactRecord contact) async => contact.original.delete(); + + List getContacts(bool isEditable, CryptoCurrency? cur) { + if (!isEditable) { + return contacts.where((element) => element.type == cur).toList(); + } + + return contacts; + } + + List getWallets(bool isEditable, CryptoCurrency? cur) { + if (!isEditable) { + return walletContacts.where((element) => element.type == cur).toList(); + } + + return walletContacts; + } } From ba783982e43216fea584cc2cea096020adcf491b Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Wed, 9 Nov 2022 17:53:50 +0200 Subject: [PATCH 10/47] Update branch to null safety Fix Conflicts with main --- cw_core/lib/node.dart | 6 ++---- lib/di.dart | 5 +++-- .../advanced_privacy_settings_page.dart | 7 +++---- lib/src/screens/nodes/widgets/node_form.dart | 4 ++-- .../node_create_or_edit_view_model.dart | 13 ++++++------- .../privacy_settings_view_model.dart | 18 +++++++++--------- 6 files changed, 25 insertions(+), 28 deletions(-) diff --git a/cw_core/lib/node.dart b/cw_core/lib/node.dart index 28a54947c..5fce69a8e 100644 --- a/cw_core/lib/node.dart +++ b/cw_core/lib/node.dart @@ -17,7 +17,7 @@ class Node extends HiveObject with Keyable { {this.login, this.password, this.useSSL, - this.trusted, + this.trusted = false, String? uri, WalletType? type,}) { if (uri != null) { @@ -33,7 +33,7 @@ class Node extends HiveObject with Keyable { login = map['login'] as String?, password = map['password'] as String?, useSSL = map['useSSL'] as bool?, - useSSL = map['trusted'] as bool? ?? false; + trusted = map['trusted'] as bool? ?? false; static const typeId = 1; static const boxName = 'Nodes'; @@ -58,8 +58,6 @@ class Node extends HiveObject with Keyable { bool get isSSL => useSSL ?? false; - bool get isTrusted => trusted ?? false; - Uri get uri { switch (type) { case WalletType.monero: diff --git a/lib/di.dart b/lib/di.dart index 73421c989..7a3a8631c 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -478,8 +478,9 @@ Future setup( getIt.registerFactory(() => NodeListPage(getIt.get())); - getIt.registerFactory(() => - NodeCreateOrEditViewModel(_nodeSource, getIt.get().wallet!)); + getIt.registerFactoryParam( + (WalletType? type, _) => + NodeCreateOrEditViewModel(_nodeSource, type ?? getIt.get().wallet!.type)); getIt.registerFactory( () => NodeCreateOrEditPage(getIt.get())); diff --git a/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart index cb3e4e8dc..58adc9d99 100644 --- a/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart +++ b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart @@ -4,7 +4,6 @@ import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model. import 'package:cake_wallet/view_model/privacy_settings_view_model.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/cupertino.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/widgets/primary_button.dart'; @@ -25,7 +24,7 @@ class AdvancedPrivacySettingsPage extends BasePage { } class AdvancedPrivacySettingsBody extends StatefulWidget { - const AdvancedPrivacySettingsBody(this.privacySettingsViewModel, this.nodeViewModel, {Key key}) + const AdvancedPrivacySettingsBody(this.privacySettingsViewModel, this.nodeViewModel, {Key? key}) : super(key: key); final PrivacySettingsViewModel privacySettingsViewModel; @@ -85,7 +84,7 @@ class _AdvancedPrivacySettingsBodyState LoadingPrimaryButton( onPressed: () {}, text: S.of(context).continue_text, - color: Theme.of(context).accentTextTheme.body2.color, + color: Theme.of(context).accentTextTheme.bodyText1!.color!, textColor: Colors.white, ), const SizedBox(height: 25), @@ -96,7 +95,7 @@ class _AdvancedPrivacySettingsBodyState S.of(context).settings_can_be_changed_later, textAlign: TextAlign.center, style: TextStyle( - color: Theme.of(context).accentTextTheme.display3.color, + color: Theme.of(context).accentTextTheme.headline2?.color, ), ), ), diff --git a/lib/src/screens/nodes/widgets/node_form.dart b/lib/src/screens/nodes/widgets/node_form.dart index 757032a2a..52851e063 100644 --- a/lib/src/screens/nodes/widgets/node_form.dart +++ b/lib/src/screens/nodes/widgets/node_form.dart @@ -10,8 +10,8 @@ import 'package:mobx/mobx.dart'; class NodeForm extends StatelessWidget { NodeForm({ - @required this.nodeViewModel, - @required this.formKey, + required this.nodeViewModel, + required this.formKey, }) : _addressController = TextEditingController(), _portController = TextEditingController(), _loginController = TextEditingController(), diff --git a/lib/view_model/node_list/node_create_or_edit_view_model.dart b/lib/view_model/node_list/node_create_or_edit_view_model.dart index 7137cdd2c..34167ae0a 100644 --- a/lib/view_model/node_list/node_create_or_edit_view_model.dart +++ b/lib/view_model/node_list/node_create_or_edit_view_model.dart @@ -1,7 +1,6 @@ import 'package:cake_wallet/core/execution_state.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; -import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/node.dart'; import 'package:cw_core/wallet_type.dart'; @@ -11,7 +10,7 @@ class NodeCreateOrEditViewModel = NodeCreateOrEditViewModelBase with _$NodeCreateOrEditViewModel; abstract class NodeCreateOrEditViewModelBase with Store { - NodeCreateOrEditViewModelBase(this._nodeSource, this._wallet) + NodeCreateOrEditViewModelBase(this._nodeSource, this._walletType) : state = InitialExecutionState(), connectionState = InitialExecutionState(), useSSL = false, @@ -49,8 +48,8 @@ abstract class NodeCreateOrEditViewModelBase with Store { bool get isReady => address.isNotEmpty && port.isNotEmpty; - bool get hasAuthCredentials => _wallet.type == WalletType.monero || - _wallet.type == WalletType.haven; + bool get hasAuthCredentials => _walletType == WalletType.monero || + _walletType == WalletType.haven; String get uri { var uri = address; @@ -62,7 +61,7 @@ abstract class NodeCreateOrEditViewModelBase with Store { return uri; } - final WalletBase _wallet; + final WalletType _walletType; final Box _nodeSource; @action @@ -80,7 +79,7 @@ abstract class NodeCreateOrEditViewModelBase with Store { try { state = IsExecutingState(); final node = - Node(uri: uri, type: _wallet.type, login: login, password: password, + Node(uri: uri, type: _walletType, login: login, password: password, useSSL: useSSL, trusted: trusted); await _nodeSource.add(node); state = ExecutedSuccessfullyState(); @@ -94,7 +93,7 @@ abstract class NodeCreateOrEditViewModelBase with Store { try { connectionState = IsExecutingState(); final node = - Node(uri: uri, type: _wallet.type, login: login, password: password); + Node(uri: uri, type: _walletType, login: login, password: password); final isAlive = await node.requestNode(); connectionState = ExecutedSuccessfullyState(payload: isAlive); } catch (e) { diff --git a/lib/view_model/privacy_settings_view_model.dart b/lib/view_model/privacy_settings_view_model.dart index ce5a3f7a6..760c577ef 100644 --- a/lib/view_model/privacy_settings_view_model.dart +++ b/lib/view_model/privacy_settings_view_model.dart @@ -9,13 +9,13 @@ class PrivacySettingsViewModel = PrivacySettingsViewModelBase with _$PrivacySettingsViewModel; abstract class PrivacySettingsViewModelBase with Store { - PrivacySettingsViewModelBase(this.type) { - _disableFiat = false; - _disableExchange = false; - _addCustomNode = false; - + PrivacySettingsViewModelBase(this.type) + : _disableFiat = false, + _disableExchange = false, + _addCustomNode = false { settings = [ SwitcherListItem( + // TODO: replace when Disable Fiat PR is merged title: "Disable Fiat API", // title: S.current.disable_fiat, value: () => _disableFiat, @@ -36,16 +36,16 @@ abstract class PrivacySettingsViewModelBase with Store { ]; } - List settings; + late List settings; @observable - bool _disableFiat; + bool _disableFiat = false; @observable - bool _disableExchange; + bool _disableExchange = false; @observable - bool _addCustomNode; + bool _addCustomNode = false; final WalletType type; From ec10732eda3296cd4878bd94b02e8df8f2f87c2c Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Wed, 9 Nov 2022 19:40:12 +0200 Subject: [PATCH 11/47] Save node on continue --- .../screens/new_wallet/advanced_privacy_settings_page.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart index 58adc9d99..da67d4511 100644 --- a/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart +++ b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart @@ -82,7 +82,9 @@ class _AdvancedPrivacySettingsBodyState bottomSection: Column( children: [ LoadingPrimaryButton( - onPressed: () {}, + onPressed: () { + nodeViewModel.save(); + }, text: S.of(context).continue_text, color: Theme.of(context).accentTextTheme.bodyText1!.color!, textColor: Colors.white, From 668e9fcf076b9bf5603e9651d31de5828ab0f325 Mon Sep 17 00:00:00 2001 From: Godwin Asuquo Date: Fri, 11 Nov 2022 15:55:21 +0200 Subject: [PATCH 12/47] [CW-73] Fix matching .exchange domain to openAlias --- lib/entities/parse_address_from_domain.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/entities/parse_address_from_domain.dart b/lib/entities/parse_address_from_domain.dart index 7fcaeeaad..775f6e229 100644 --- a/lib/entities/parse_address_from_domain.dart +++ b/lib/entities/parse_address_from_domain.dart @@ -4,7 +4,6 @@ import 'package:cake_wallet/entities/parsed_address.dart'; import 'package:cake_wallet/entities/unstoppable_domain_address.dart'; import 'package:cake_wallet/entities/emoji_string_extension.dart'; import 'package:cw_core/wallet_type.dart'; -import 'package:flutter/foundation.dart'; import 'package:cake_wallet/entities/fio_address_provider.dart'; class AddressResolver { @@ -51,7 +50,7 @@ class AddressResolver { return ParsedAddress(addresses: [text]); } - if (unstoppableDomains.any((domain) => name.contains(domain))) { + if (unstoppableDomains.any((domain) => name.trim() == domain)) { final address = await fetchUnstoppableDomainAddress(text, ticker); return ParsedAddress.fetchUnstoppableDomainAddress(address: address, name: text); } From 69886372660be5e204083e9e05e2dbb789a4c597 Mon Sep 17 00:00:00 2001 From: Serhii Date: Sun, 13 Nov 2022 20:06:45 +0200 Subject: [PATCH 13/47] fix fetching trade state for SideShift --- lib/exchange/sideshift/sideshift_exchange_provider.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/exchange/sideshift/sideshift_exchange_provider.dart b/lib/exchange/sideshift/sideshift_exchange_provider.dart index a732f7ef2..8cd4593c1 100644 --- a/lib/exchange/sideshift/sideshift_exchange_provider.dart +++ b/lib/exchange/sideshift/sideshift_exchange_provider.dart @@ -250,8 +250,10 @@ class SideShiftExchangeProvider extends ExchangeProvider { final deposits = responseJSON['deposits'] as List?; TradeState? state; - if (deposits != null && deposits.isNotEmpty) { - final status = deposits[0]['status'] as String; + if (deposits != null && deposits.isEmpty) { + state = TradeState.deserialize(raw: 'created'); + } else { + final status = deposits?[0]['status'] as String; state = TradeState.deserialize(raw: status); } From 05f1b17a732932ed12b2b93b751acf218160214b Mon Sep 17 00:00:00 2001 From: Serhii Date: Mon, 21 Nov 2022 22:41:09 +0200 Subject: [PATCH 14/47] fix contact list bug --- lib/router.dart | 2 +- lib/src/screens/contact/contact_list_page.dart | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/router.dart b/lib/router.dart index 8b43fbaf5..9fe22e22d 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -300,7 +300,7 @@ Route createRoute(RouteSettings settings) { case Routes.addressBook: return MaterialPageRoute( builder: (_) => - getIt.get(param1: true, param2: null)); + getIt.get(param1: true)); case Routes.pickerAddressBook: final selectedCurrency = settings.arguments as CryptoCurrency; diff --git a/lib/src/screens/contact/contact_list_page.dart b/lib/src/screens/contact/contact_list_page.dart index 6d23518b8..8e9de23fd 100644 --- a/lib/src/screens/contact/contact_list_page.dart +++ b/lib/src/screens/contact/contact_list_page.dart @@ -68,7 +68,9 @@ class ContactListPage extends BasePage { contactListViewModel.getWallets(isEditable, selectedCurrency); return Container( padding: EdgeInsets.only(top: 20.0, bottom: 20.0), - child: CollapsibleSectionList( + child: Observer( + builder: (_) { + return CollapsibleSectionList( context: context, sectionCount: 2, themeColor: Theme.of(context).primaryTextTheme.headline6!.color!, @@ -104,7 +106,7 @@ class ContactListPage extends BasePage { child: content, ); }, - ) + );}) ); } From 2db75344802296ad6fe0d68c4bcedc997e9263af Mon Sep 17 00:00:00 2001 From: Serhii Date: Tue, 22 Nov 2022 00:07:27 +0200 Subject: [PATCH 15/47] small fix --- lib/src/screens/contact/contact_list_page.dart | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/src/screens/contact/contact_list_page.dart b/lib/src/screens/contact/contact_list_page.dart index 8e9de23fd..7895a1df3 100644 --- a/lib/src/screens/contact/contact_list_page.dart +++ b/lib/src/screens/contact/contact_list_page.dart @@ -62,14 +62,15 @@ class ContactListPage extends BasePage { @override Widget body(BuildContext context) { - final contacts = - contactListViewModel.getContacts(isEditable, selectedCurrency); - final walletContacts = - contactListViewModel.getWallets(isEditable, selectedCurrency); + return Container( padding: EdgeInsets.only(top: 20.0, bottom: 20.0), child: Observer( builder: (_) { + final contacts = + contactListViewModel.getContacts(isEditable, selectedCurrency); + final walletContacts = + contactListViewModel.getWallets(isEditable, selectedCurrency); return CollapsibleSectionList( context: context, sectionCount: 2, From 79fb1b91d4b661cba9e1e668f59c9fcf152dc76b Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Sat, 26 Nov 2022 16:13:54 +0200 Subject: [PATCH 16/47] Check for Nodes if exists before adding them in nodes Fix nullability issue due to early access Fix Nodes_list,yml file structure --- assets/node_list.yml | 4 ++-- lib/entities/default_settings_migration.dart | 22 +++++++++++++++---- .../on_authentication_state_change.dart | 4 ++-- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/assets/node_list.yml b/assets/node_list.yml index 09fb72383..7962ea18c 100644 --- a/assets/node_list.yml +++ b/assets/node_list.yml @@ -22,10 +22,10 @@ - uri: node.imonero.org:18081 is_default: false - +- uri: node.c3pool.com:18081 is_default: false - +- uri: xmr.prprpr.icu:18081 is_default: false diff --git a/lib/entities/default_settings_migration.dart b/lib/entities/default_settings_migration.dart index b2036c3f6..fb404cd88 100644 --- a/lib/entities/default_settings_migration.dart +++ b/lib/entities/default_settings_migration.dart @@ -69,6 +69,8 @@ Future defaultSettingsMigration( sharedPreferences: sharedPreferences, nodes: nodes); await changeLitecoinCurrentElectrumServerToDefault( sharedPreferences: sharedPreferences, nodes: nodes); + await changeHavenCurrentNodeToDefault( + sharedPreferences: sharedPreferences, nodes: nodes); break; case 2: @@ -277,17 +279,29 @@ Future updateNodeTypes({required Box nodes}) async { Future addBitcoinElectrumServerList({required Box nodes}) async { final serverList = await loadBitcoinElectrumServerList(); - await nodes.addAll(serverList); + for (var node in serverList) { + if (nodes.values.firstWhereOrNull((element) => element.uriRaw == node.uriRaw) == null) { + await nodes.add(node); + } + } } Future addLitecoinElectrumServerList({required Box nodes}) async { final serverList = await loadLitecoinElectrumServerList(); - await nodes.addAll(serverList); + for (var node in serverList) { + if (nodes.values.firstWhereOrNull((element) => element.uriRaw == node.uriRaw) == null) { + await nodes.add(node); + } + } } Future addHavenNodeList({required Box nodes}) async { final nodeList = await loadDefaultHavenNodes(); - await nodes.addAll(nodeList); + for (var node in nodeList) { + if (nodes.values.firstWhereOrNull((element) => element.uriRaw == node.uriRaw) == null) { + await nodes.add(node); + } + } } Future addAddressesForMoneroWallets( @@ -431,7 +445,7 @@ Future resetBitcoinElectrumServer( final oldElectrumServer = nodeSource.values.firstWhereOrNull( (node) => node.uri.toString().contains('electrumx.cakewallet.com')); var cakeWalletNode = nodeSource.values.firstWhereOrNull( - (node) => node.uri.toString() == cakeWalletBitcoinElectrumUri); + (node) => node.uriRaw.toString() == cakeWalletBitcoinElectrumUri); if (cakeWalletNode == null) { cakeWalletNode = diff --git a/lib/reactions/on_authentication_state_change.dart b/lib/reactions/on_authentication_state_change.dart index c91f5277e..560326cb5 100644 --- a/lib/reactions/on_authentication_state_change.dart +++ b/lib/reactions/on_authentication_state_change.dart @@ -23,12 +23,12 @@ void startAuthenticationStateChange(AuthenticationStore authenticationStore, } if (state == AuthenticationState.allowed) { - await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false); + await navigatorKey.currentState?.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false); return; } if (state == AuthenticationState.denied) { - await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.welcome, (_) => false); + await navigatorKey.currentState?.pushNamedAndRemoveUntil(Routes.welcome, (_) => false); return; } }); From c8a9c1f53f1a60c93e557f7a10462d2f490d298c Mon Sep 17 00:00:00 2001 From: Justin Ehrenhofer Date: Mon, 28 Nov 2022 09:45:18 -0600 Subject: [PATCH 17/47] Update Monero nodes --- assets/node_list.yml | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/assets/node_list.yml b/assets/node_list.yml index 7962ea18c..39b440c9f 100644 --- a/assets/node_list.yml +++ b/assets/node_list.yml @@ -1,31 +1,21 @@ - - uri: xmr-node-uk.cakewallet.com:18081 + uri: xmr-node.cakewallet.com:18081 is_default: true - - uri: xmr-node-eu.cakewallet.com:18081 + uri: node.sethforprivacy.com:18089 is_default: false - - uri: xmr-node-usa-east.cakewallet.com:18081 - is_default: false -- - uri: node.moneroworld.com:18089 - is_default: false -- - uri: node.xmr.pt:18081 - is_default: false -- - uri: node.monero.net:18081 - is_default: false -- - uri: opennode.xmr-tw.org:18089 - is_default: false -- - uri: node.imonero.org:18081 + uri: nodes.hashvault.pro:18081 is_default: false - uri: node.c3pool.com:18081 is_default: false - - uri: xmr.prprpr.icu:18081 + uri: node.supportxmr.com:18081 + is_default: false +- + uri: node.community.rino.io:18081 + is_default: false +- + uri: node.moneroworld.com:18089 is_default: false - From 1dd94c96058cdd153a748b9e6cbad430adc0f75f Mon Sep 17 00:00:00 2001 From: Justin Ehrenhofer Date: Mon, 28 Nov 2022 10:11:52 -0600 Subject: [PATCH 18/47] Add onion node Apologies for forgetting this a few minutes ago, despite me adding this to the guides.cakewallet.com website this morning! Related to CW-252 (no notice is added in this commit) --- assets/node_list.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/assets/node_list.yml b/assets/node_list.yml index 39b440c9f..fccc968cf 100644 --- a/assets/node_list.yml +++ b/assets/node_list.yml @@ -1,6 +1,9 @@ - uri: xmr-node.cakewallet.com:18081 is_default: true +- + uri: cakexmrl7bonq7ovjka5kuwuyd3f7qnkz6z6s6dmsy3uckwra7bvggyd.onion:18081 + is_default: false - uri: node.sethforprivacy.com:18089 is_default: false From 59ee7aa975750ba17071916d4bd71c2a8cb19543 Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Wed, 30 Nov 2022 01:37:56 +0200 Subject: [PATCH 19/47] Add onion node to already existing users --- lib/entities/default_settings_migration.dart | 22 ++++++++++++++------ lib/main.dart | 2 +- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/lib/entities/default_settings_migration.dart b/lib/entities/default_settings_migration.dart index fb404cd88..27ada0b0c 100644 --- a/lib/entities/default_settings_migration.dart +++ b/lib/entities/default_settings_migration.dart @@ -135,19 +135,29 @@ Future defaultSettingsMigration( await changeDefaultHavenNode(nodes); break; + case 18: + await addOnionNode(nodes); + break; + default: break; } await sharedPreferences.setInt( - 'current_default_settings_migration_version', version); + PreferencesKey.currentDefaultSettingsMigrationVersion, version); } catch (e) { print('Migration error: ${e.toString()}'); } }); await sharedPreferences.setInt( - 'current_default_settings_migration_version', version); + PreferencesKey.currentDefaultSettingsMigrationVersion, version); +} + +Future addOnionNode(Box nodes) async { + final onionNodeUri = "cakexmrl7bonq7ovjka5kuwuyd3f7qnkz6z6s6dmsy3uckwra7bvggyd.onion:18081"; + + await nodes.add(Node(uri: onionNodeUri, type: WalletType.monero)); } Future replaceNodesMigration({required Box nodes}) async { @@ -178,7 +188,7 @@ Future changeMoneroCurrentNodeToDefault( final node = getMoneroDefaultNode(nodes: nodes); final nodeId = node?.key as int ?? 0; // 0 - England - await sharedPreferences.setInt('current_node_id', nodeId); + await sharedPreferences.setInt(PreferencesKey.currentNodeIdKey, nodeId); } Node? getBitcoinDefaultElectrumServer({required Box nodes}) { @@ -225,7 +235,7 @@ Future changeBitcoinCurrentElectrumServerToDefault( final server = getBitcoinDefaultElectrumServer(nodes: nodes); final serverId = server?.key as int ?? 0; - await sharedPreferences.setInt('current_node_id_btc', serverId); + await sharedPreferences.setInt(PreferencesKey.currentBitcoinElectrumSererIdKey, serverId); } Future changeLitecoinCurrentElectrumServerToDefault( @@ -234,7 +244,7 @@ Future changeLitecoinCurrentElectrumServerToDefault( final server = getLitecoinDefaultElectrumServer(nodes: nodes); final serverId = server?.key as int ?? 0; - await sharedPreferences.setInt('current_node_id_ltc', serverId); + await sharedPreferences.setInt(PreferencesKey.currentLitecoinElectrumSererIdKey, serverId); } Future changeHavenCurrentNodeToDefault( @@ -254,7 +264,7 @@ Future replaceDefaultNode( 'eu-node.cakewallet.io:18081', 'node.cakewallet.io:18081' ]; - final currentNodeId = sharedPreferences.getInt('current_node_id'); + final currentNodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey); final currentNode = nodes.values.firstWhereOrNull((Node node) => node.key == currentNodeId); final needToReplace = diff --git a/lib/main.dart b/lib/main.dart index 3cd5679b3..e1fade7b4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -128,7 +128,7 @@ Future main() async { exchangeTemplates: exchangeTemplates, transactionDescriptions: transactionDescriptions, secureStorage: secureStorage, - initialMigrationVersion: 17); + initialMigrationVersion: 18); runApp(App()); } catch (e, stacktrace) { runApp(MaterialApp( From ffd0079e1d231180d52f52ec51dba975fcfbbdc3 Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Thu, 1 Dec 2022 14:29:03 +0200 Subject: [PATCH 20/47] Check if user already has onion node before adding it --- lib/entities/default_settings_migration.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/entities/default_settings_migration.dart b/lib/entities/default_settings_migration.dart index 27ada0b0c..9aff05500 100644 --- a/lib/entities/default_settings_migration.dart +++ b/lib/entities/default_settings_migration.dart @@ -157,7 +157,10 @@ Future defaultSettingsMigration( Future addOnionNode(Box nodes) async { final onionNodeUri = "cakexmrl7bonq7ovjka5kuwuyd3f7qnkz6z6s6dmsy3uckwra7bvggyd.onion:18081"; - await nodes.add(Node(uri: onionNodeUri, type: WalletType.monero)); + // check if the user has this node before (added it manually) + if (nodes.values.firstWhereOrNull((element) => element.uriRaw == onionNodeUri) == null) { + await nodes.add(Node(uri: onionNodeUri, type: WalletType.monero)); + } } Future replaceNodesMigration({required Box nodes}) async { From 47764835c36680125e409f54f97646ed83034736 Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Thu, 1 Dec 2022 18:09:21 +0200 Subject: [PATCH 21/47] Fix nullability issue in create trade response --- lib/exchange/changenow/changenow_exchange_provider.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/exchange/changenow/changenow_exchange_provider.dart b/lib/exchange/changenow/changenow_exchange_provider.dart index 20f529733..9910c7b9a 100644 --- a/lib/exchange/changenow/changenow_exchange_provider.dart +++ b/lib/exchange/changenow/changenow_exchange_provider.dart @@ -114,7 +114,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider { final uri = Uri.https(apiAuthority, createTradePath); final response = await post(uri, headers: headers, body: json.encode(body)); - + if (response.statusCode == 400) { final responseJSON = json.decode(response.body) as Map; final error = responseJSON['error'] as String; @@ -128,9 +128,9 @@ class ChangeNowExchangeProvider extends ExchangeProvider { final responseJSON = json.decode(response.body) as Map; final id = responseJSON['id'] as String; - final inputAddress = responseJSON['payinAddress'] as String; - final refundAddress = responseJSON['refundAddress'] as String; - final extraId = responseJSON['payinExtraId'] as String; + final inputAddress = responseJSON['payinAddress'] as String?; + final refundAddress = responseJSON['refundAddress'] as String?; + final extraId = responseJSON['payinExtraId'] as String?; return Trade( id: id, From cbe31aa5aa60c269139f1c3e44be126337a274b2 Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Thu, 1 Dec 2022 18:21:19 +0200 Subject: [PATCH 22/47] Revert allowing nullable values for input and refund addresses --- lib/exchange/changenow/changenow_exchange_provider.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/exchange/changenow/changenow_exchange_provider.dart b/lib/exchange/changenow/changenow_exchange_provider.dart index 9910c7b9a..96b6142e6 100644 --- a/lib/exchange/changenow/changenow_exchange_provider.dart +++ b/lib/exchange/changenow/changenow_exchange_provider.dart @@ -128,8 +128,8 @@ class ChangeNowExchangeProvider extends ExchangeProvider { final responseJSON = json.decode(response.body) as Map; final id = responseJSON['id'] as String; - final inputAddress = responseJSON['payinAddress'] as String?; - final refundAddress = responseJSON['refundAddress'] as String?; + final inputAddress = responseJSON['payinAddress'] as String; + final refundAddress = responseJSON['refundAddress'] as String; final extraId = responseJSON['payinExtraId'] as String?; return Trade( From 8d9c0f2a4670be9f163f4e3d614f786e4bd0cd73 Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Thu, 1 Dec 2022 20:47:13 +0200 Subject: [PATCH 23/47] Add bash script to run all generation commands in one time --- model_generator.sh | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 model_generator.sh diff --git a/model_generator.sh b/model_generator.sh new file mode 100644 index 000000000..f4ef8bdad --- /dev/null +++ b/model_generator.sh @@ -0,0 +1,5 @@ +cd cw_core && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. +cd cw_monero && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. +cd cw_bitcoin && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. +cd cw_haven && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. +flutter packages pub run build_runner build --delete-conflicting-outputs \ No newline at end of file From dd99508d3e3d894987dc2f5d1616f310c1586fb7 Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Thu, 1 Dec 2022 22:11:51 +0200 Subject: [PATCH 24/47] Fix static amount value for determining best rate and replace it with the input the user types --- lib/view_model/exchange/exchange_view_model.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/view_model/exchange/exchange_view_model.dart b/lib/view_model/exchange/exchange_view_model.dart index 725208324..ff3b66f73 100644 --- a/lib/view_model/exchange/exchange_view_model.dart +++ b/lib/view_model/exchange/exchange_view_model.dart @@ -296,12 +296,14 @@ abstract class ExchangeViewModelBase with Store { } Future _calculateBestRate() async { + final amount = double.tryParse(depositAmount) ?? double.tryParse(receiveAmount) ?? 1; + final result = await Future.wait( _tradeAvailableProviders .map((element) => element.calculateAmount( from: depositCurrency, to: receiveCurrency, - amount: 1, + amount: amount, isFixedRateMode: isFixedRateMode, isReceiveAmount: false)) ); @@ -311,7 +313,7 @@ abstract class ExchangeViewModelBase with Store { for (int i=0;i Date: Thu, 1 Dec 2022 22:37:13 +0200 Subject: [PATCH 25/47] allow null minimum amount in limits --- lib/view_model/exchange/exchange_view_model.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/view_model/exchange/exchange_view_model.dart b/lib/view_model/exchange/exchange_view_model.dart index ff3b66f73..fd66a4254 100644 --- a/lib/view_model/exchange/exchange_view_model.dart +++ b/lib/view_model/exchange/exchange_view_model.dart @@ -336,7 +336,7 @@ abstract class ExchangeViewModelBase with Store { ? depositCurrency : receiveCurrency; - double lowestMin = double.maxFinite; + double? lowestMin = double.maxFinite; double? highestMax = 0.0; for (var provider in selectedProviders) { @@ -351,8 +351,8 @@ abstract class ExchangeViewModelBase with Store { to: to, isFixedRateMode: isFixedRateMode); - if (tempLimits.min != null && tempLimits.min! < lowestMin) { - lowestMin = tempLimits.min!; + if (lowestMin != null && (tempLimits.min ?? -1) < lowestMin) { + lowestMin = tempLimits.min; } if (highestMax != null && (tempLimits.max ?? double.maxFinite) > highestMax) { highestMax = tempLimits.max; @@ -362,7 +362,7 @@ abstract class ExchangeViewModelBase with Store { } } - if (lowestMin < double.maxFinite) { + if (lowestMin != double.maxFinite) { limits = Limits(min: lowestMin, max: highestMax); limitsState = LimitsLoadedSuccessfully(limits: limits); From 3bcd31ac44d95235bfb03a46497b71919c3ba28e Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Fri, 2 Dec 2022 20:38:16 +0200 Subject: [PATCH 26/47] calculate best rate based on min/max amount --- lib/view_model/exchange/exchange_view_model.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/view_model/exchange/exchange_view_model.dart b/lib/view_model/exchange/exchange_view_model.dart index fd66a4254..f9d832843 100644 --- a/lib/view_model/exchange/exchange_view_model.dart +++ b/lib/view_model/exchange/exchange_view_model.dart @@ -296,7 +296,7 @@ abstract class ExchangeViewModelBase with Store { } Future _calculateBestRate() async { - final amount = double.tryParse(depositAmount) ?? double.tryParse(receiveAmount) ?? 1; + final amount = limits.min ?? limits.max ?? 1; final result = await Future.wait( _tradeAvailableProviders From 116e468581cf862584a640f41a07d77e0879f4f9 Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Fri, 2 Dec 2022 23:20:06 +0200 Subject: [PATCH 27/47] calculate best rate based on deposit/receive amount --- lib/view_model/exchange/exchange_view_model.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/view_model/exchange/exchange_view_model.dart b/lib/view_model/exchange/exchange_view_model.dart index f9d832843..b03415f4a 100644 --- a/lib/view_model/exchange/exchange_view_model.dart +++ b/lib/view_model/exchange/exchange_view_model.dart @@ -296,7 +296,7 @@ abstract class ExchangeViewModelBase with Store { } Future _calculateBestRate() async { - final amount = limits.min ?? limits.max ?? 1; + final amount = double.tryParse(isFixedRateMode ? receiveAmount : depositAmount) ?? 1; final result = await Future.wait( _tradeAvailableProviders From 5f1e8e9d33fa04bac655e870820620f059ffd4e7 Mon Sep 17 00:00:00 2001 From: Serhii Date: Fri, 2 Dec 2022 23:36:22 +0200 Subject: [PATCH 28/47] remove isEditable parameter --- lib/di.dart | 3 +-- lib/router.dart | 5 ++--- lib/src/screens/contact/contact_list_page.dart | 13 ++++++------- .../contact_list/contact_list_view_model.dart | 8 ++++---- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/lib/di.dart b/lib/di.dart index b84f98ad9..539681036 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -462,10 +462,9 @@ Future setup( getIt.registerFactory( () => ContactListViewModel(_contactSource, _walletInfoSource)); - getIt.registerFactoryParam((bool isEditable, CryptoCurrency? cur) + getIt.registerFactoryParam((CryptoCurrency? cur, _) => ContactListPage( getIt.get(), - isEditable: isEditable, selectedCurrency: cur)); getIt.registerFactoryParam( diff --git a/lib/router.dart b/lib/router.dart index 9fe22e22d..07e500544 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -300,13 +300,12 @@ Route createRoute(RouteSettings settings) { case Routes.addressBook: return MaterialPageRoute( builder: (_) => - getIt.get(param1: true)); + getIt.get()); case Routes.pickerAddressBook: final selectedCurrency = settings.arguments as CryptoCurrency; return MaterialPageRoute( - builder: (_) => getIt.get(param1: false, - param2: selectedCurrency)); + builder: (_) => getIt.get(param1: selectedCurrency)); case Routes.addressBookAddContact: return CupertinoPageRoute( diff --git a/lib/src/screens/contact/contact_list_page.dart b/lib/src/screens/contact/contact_list_page.dart index 7895a1df3..8fcaf31a2 100644 --- a/lib/src/screens/contact/contact_list_page.dart +++ b/lib/src/screens/contact/contact_list_page.dart @@ -17,10 +17,9 @@ import 'package:cake_wallet/src/widgets/collapsible_standart_list.dart'; class ContactListPage extends BasePage { ContactListPage(this.contactListViewModel, - {this.isEditable = true, required this.selectedCurrency}); + {this.selectedCurrency}); final ContactListViewModel contactListViewModel; - final bool isEditable; final CryptoCurrency? selectedCurrency; @override @@ -28,7 +27,7 @@ class ContactListPage extends BasePage { @override Widget? trailing(BuildContext context) { - if (!isEditable) { + if (selectedCurrency != null) { return null; } @@ -68,9 +67,9 @@ class ContactListPage extends BasePage { child: Observer( builder: (_) { final contacts = - contactListViewModel.getContacts(isEditable, selectedCurrency); + contactListViewModel.getContacts(selectedCurrency); final walletContacts = - contactListViewModel.getWallets(isEditable, selectedCurrency); + contactListViewModel.getWallets(selectedCurrency); return CollapsibleSectionList( context: context, sectionCount: 2, @@ -99,7 +98,7 @@ class ContactListPage extends BasePage { final contact = contacts[index]; final content = generateRaw(context, contact); - return !isEditable + return selectedCurrency != null ? content : Slidable( key: Key('${contact.key}'), @@ -116,7 +115,7 @@ class ContactListPage extends BasePage { return GestureDetector( onTap: () async { - if (!isEditable) { + if (selectedCurrency != null) { Navigator.of(context).pop(contact); return; } diff --git a/lib/view_model/contact_list/contact_list_view_model.dart b/lib/view_model/contact_list/contact_list_view_model.dart index 0f67245af..3fa9a73a4 100644 --- a/lib/view_model/contact_list/contact_list_view_model.dart +++ b/lib/view_model/contact_list/contact_list_view_model.dart @@ -46,16 +46,16 @@ abstract class ContactListViewModelBase with Store { Future delete(ContactRecord contact) async => contact.original.delete(); - List getContacts(bool isEditable, CryptoCurrency? cur) { - if (!isEditable) { + List getContacts(CryptoCurrency? cur) { + if (cur != null) { return contacts.where((element) => element.type == cur).toList(); } return contacts; } - List getWallets(bool isEditable, CryptoCurrency? cur) { - if (!isEditable) { + List getWallets(CryptoCurrency? cur) { + if (cur != null) { return walletContacts.where((element) => element.type == cur).toList(); } From 4c7a0a8cb97a4e1af58127bd52e185a3ae60a4e5 Mon Sep 17 00:00:00 2001 From: Serhii Date: Sat, 3 Dec 2022 00:34:34 +0200 Subject: [PATCH 29/47] rework _getCurrencyImage func --- .../screens/contact/contact_list_page.dart | 74 ++----------------- 1 file changed, 6 insertions(+), 68 deletions(-) diff --git a/lib/src/screens/contact/contact_list_page.dart b/lib/src/screens/contact/contact_list_page.dart index 8fcaf31a2..9d0d1ab5a 100644 --- a/lib/src/screens/contact/contact_list_page.dart +++ b/lib/src/screens/contact/contact_list_page.dart @@ -111,7 +111,10 @@ class ContactListPage extends BasePage { } Widget generateRaw(BuildContext context, ContactBase contact) { - final image = _getCurrencyImage(contact.type); + final image = contact.type.iconPath; + final currencyIcon = image != null ? Image.asset(image, height: 24, width: 24) + : const SizedBox(height: 24, width: 24); + return GestureDetector( onTap: () async { @@ -136,12 +139,10 @@ class ContactListPage extends BasePage { mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.start, children: [ - image ?? Offstage(), + currencyIcon, Expanded( child: Padding( - padding: image != null - ? EdgeInsets.only(left: 12) - : EdgeInsets.only(left: 0), + padding: EdgeInsets.only(left: 12), child: Text( contact.name, style: TextStyle( @@ -157,69 +158,6 @@ class ContactListPage extends BasePage { ); } - Image? _getCurrencyImage(CryptoCurrency currency) { - Image? image; - - switch (currency) { - case CryptoCurrency.xmr: - image = - Image.asset('assets/images/monero_logo.png', height: 24, width: 24); - break; - case CryptoCurrency.ada: - image = Image.asset('assets/images/ada.png', height: 24, width: 24); - break; - case CryptoCurrency.bch: - image = Image.asset('assets/images/bch.png', height: 24, width: 24); - break; - case CryptoCurrency.bnb: - image = Image.asset('assets/images/bnb.png', height: 24, width: 24); - break; - case CryptoCurrency.btc: - image = Image.asset('assets/images/bitcoin.png', height: 24, width: 24); - break; - case CryptoCurrency.dai: - image = Image.asset('assets/images/dai.png', height: 24, width: 24); - break; - case CryptoCurrency.dash: - image = Image.asset('assets/images/dash.png', height: 24, width: 24); - break; - case CryptoCurrency.eos: - image = Image.asset('assets/images/eos.png', height: 24, width: 24); - break; - case CryptoCurrency.eth: - image = Image.asset('assets/images/eth.png', height: 24, width: 24); - break; - case CryptoCurrency.ltc: - image = - Image.asset('assets/images/litecoin.png', height: 24, width: 24); - break; - case CryptoCurrency.nano: - image = Image.asset('assets/images/nano.png', height: 24, width: 24); - break; - case CryptoCurrency.trx: - image = Image.asset('assets/images/trx.png', height: 24, width: 24); - break; - case CryptoCurrency.usdt: - image = Image.asset('assets/images/usdt.png', height: 24, width: 24); - break; - case CryptoCurrency.usdterc20: - image = Image.asset('assets/images/usdterc.png', height: 24, width: 24); - break; - case CryptoCurrency.xlm: - image = Image.asset('assets/images/xlm.png', height: 24, width: 24); - break; - case CryptoCurrency.xrp: - image = Image.asset('assets/images/xrp.png', height: 24, width: 24); - break; - case CryptoCurrency.xhv: - image = Image.asset('assets/images/haven_logo.png', height: 24, width: 24); - break; - default: - image = null; - } - return image; - } - Future showAlertDialog(BuildContext context) async { return await showPopUp( context: context, From 11a5e9771197496ac08b72972daf25108c47707b Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Sat, 3 Dec 2022 23:34:23 +0200 Subject: [PATCH 30/47] Fix navigation error when state is changed to denied at app first start [skip_ci] --- lib/main.dart | 2 +- lib/reactions/bootstrap.dart | 6 +++--- lib/reactions/on_authentication_state_change.dart | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index e1fade7b4..11eee146b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -261,7 +261,7 @@ class AppState extends State with SingleTickerProviderStateMixin { final statusBarColor = Colors.transparent; final authenticationStore = getIt.get(); final initialRoute = - authenticationStore.state == AuthenticationState.denied + authenticationStore.state == AuthenticationState.uninitialized ? Routes.disclaimer : Routes.login; final currentTheme = settingsStore.currentTheme; diff --git a/lib/reactions/bootstrap.dart b/lib/reactions/bootstrap.dart index 8d9950e64..a40a17088 100644 --- a/lib/reactions/bootstrap.dart +++ b/lib/reactions/bootstrap.dart @@ -22,9 +22,9 @@ Future bootstrap(GlobalKey navigatorKey) async { final currentWalletName = getIt .get() .getString(PreferencesKey.currentWalletName); - authenticationStore.state = currentWalletName == null - ? AuthenticationState.denied - : AuthenticationState.installed; + if (currentWalletName != null) { + authenticationStore.state = AuthenticationState.installed; + } startAuthenticationStateChange(authenticationStore, navigatorKey); startCurrentWalletChangeReaction( diff --git a/lib/reactions/on_authentication_state_change.dart b/lib/reactions/on_authentication_state_change.dart index 560326cb5..c91f5277e 100644 --- a/lib/reactions/on_authentication_state_change.dart +++ b/lib/reactions/on_authentication_state_change.dart @@ -23,12 +23,12 @@ void startAuthenticationStateChange(AuthenticationStore authenticationStore, } if (state == AuthenticationState.allowed) { - await navigatorKey.currentState?.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false); + await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false); return; } if (state == AuthenticationState.denied) { - await navigatorKey.currentState?.pushNamedAndRemoveUntil(Routes.welcome, (_) => false); + await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.welcome, (_) => false); return; } }); From 98da1c221d2bd5f9162c950406e64b22366d10e6 Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Sat, 3 Dec 2022 23:36:27 +0200 Subject: [PATCH 31/47] revert nullability change with navigation in authentication state change [skip_ci] --- lib/reactions/on_authentication_state_change.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/reactions/on_authentication_state_change.dart b/lib/reactions/on_authentication_state_change.dart index 560326cb5..c91f5277e 100644 --- a/lib/reactions/on_authentication_state_change.dart +++ b/lib/reactions/on_authentication_state_change.dart @@ -23,12 +23,12 @@ void startAuthenticationStateChange(AuthenticationStore authenticationStore, } if (state == AuthenticationState.allowed) { - await navigatorKey.currentState?.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false); + await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false); return; } if (state == AuthenticationState.denied) { - await navigatorKey.currentState?.pushNamedAndRemoveUntil(Routes.welcome, (_) => false); + await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.welcome, (_) => false); return; } }); From 9d64789983dac6b90f3a5a1aa228ebf181fbc0a7 Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Sun, 4 Dec 2022 05:08:42 +0200 Subject: [PATCH 32/47] Fix Conflict with main Rename classes to advanced privacy settings to avoid confusion between settings/privacy-settings --- lib/di.dart | 6 +-- lib/router.dart | 11 ++-- .../advanced_privacy_settings_page.dart | 9 ++-- .../screens/new_wallet/new_wallet_page.dart | 2 +- .../advanced_privacy_settings_view_model.dart | 51 ++++++++++++++++++ .../privacy_settings_view_model.dart | 54 ------------------- res/values/strings_de.arb | 3 +- res/values/strings_en.arb | 3 +- res/values/strings_es.arb | 3 +- res/values/strings_fr.arb | 3 +- res/values/strings_hi.arb | 3 +- res/values/strings_hr.arb | 3 +- res/values/strings_it.arb | 3 +- res/values/strings_ja.arb | 3 +- res/values/strings_ko.arb | 3 +- res/values/strings_nl.arb | 3 +- res/values/strings_pl.arb | 3 +- res/values/strings_pt.arb | 3 +- res/values/strings_ru.arb | 3 +- res/values/strings_uk.arb | 3 +- res/values/strings_zh.arb | 3 +- 21 files changed, 96 insertions(+), 82 deletions(-) create mode 100644 lib/view_model/advanced_privacy_settings_view_model.dart delete mode 100644 lib/view_model/privacy_settings_view_model.dart diff --git a/lib/di.dart b/lib/di.dart index a896bf1e4..7a7621203 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -35,7 +35,7 @@ import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart'; import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart'; import 'package:cake_wallet/view_model/settings/security_settings_view_model.dart'; -import 'package:cake_wallet/view_model/privacy_settings_view_model.dart' +import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart'; import 'package:cw_core/unspent_coins_info.dart'; import 'package:cake_wallet/core/backup_service.dart'; import 'package:cw_core/wallet_service.dart'; @@ -816,8 +816,8 @@ Future setup( (IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo) => IoniaPaymentStatusPage(getIt.get(param1: paymentInfo, param2: committedInfo))); - getIt.registerFactoryParam((type, _) => - PrivacySettingsViewModel(type)) + getIt.registerFactoryParam((type, _) => + AdvancedPrivacySettingsViewModel(type, getIt.get())); _isSetupFinished = true; } diff --git a/lib/router.dart b/lib/router.dart index f22fd3e18..20e4d7632 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -27,7 +27,7 @@ import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart'; import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart'; import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart'; -import 'package:cake_wallet/view_model/privacy_settings_view_model.dart'; +import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:cake_wallet/routes.dart'; @@ -494,13 +494,14 @@ Route createRoute(RouteSettings settings) { case Routes.onramperPage: return CupertinoPageRoute(builder: (_) => getIt.get()); - case Routes.privacySettings: + case Routes.advancedPrivacySettings: final type = settings.arguments as WalletType; - final privacySettingsViewModel = getIt.get(param1: type); - final nodeCreateViewModel = getIt.get(param1: type); return CupertinoPageRoute( - builder: (_) => AdvancedPrivacySettingsPage(privacySettingsViewModel, nodeCreateViewModel)); + builder: (_) => AdvancedPrivacySettingsPage( + getIt.get(param1: type), + getIt.get(param1: type), + )); default: return MaterialPageRoute( diff --git a/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart index da67d4511..33aca0307 100644 --- a/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart +++ b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart @@ -1,7 +1,7 @@ import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart'; import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart'; -import 'package:cake_wallet/view_model/privacy_settings_view_model.dart'; +import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter/material.dart'; import 'package:cake_wallet/generated/i18n.dart'; @@ -12,7 +12,7 @@ import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; class AdvancedPrivacySettingsPage extends BasePage { AdvancedPrivacySettingsPage(this.privacySettingsViewModel, this.nodeViewModel); - final PrivacySettingsViewModel privacySettingsViewModel; + final AdvancedPrivacySettingsViewModel privacySettingsViewModel; final NodeCreateOrEditViewModel nodeViewModel; @override @@ -27,7 +27,7 @@ class AdvancedPrivacySettingsBody extends StatefulWidget { const AdvancedPrivacySettingsBody(this.privacySettingsViewModel, this.nodeViewModel, {Key? key}) : super(key: key); - final PrivacySettingsViewModel privacySettingsViewModel; + final AdvancedPrivacySettingsViewModel privacySettingsViewModel; final NodeCreateOrEditViewModel nodeViewModel; @override @@ -39,7 +39,7 @@ class _AdvancedPrivacySettingsBodyState extends State { _AdvancedPrivacySettingsBodyState(this.privacySettingsViewModel, this.nodeViewModel); - final PrivacySettingsViewModel privacySettingsViewModel; + final AdvancedPrivacySettingsViewModel privacySettingsViewModel; final NodeCreateOrEditViewModel nodeViewModel; final _formKey = GlobalKey(); @@ -84,6 +84,7 @@ class _AdvancedPrivacySettingsBodyState LoadingPrimaryButton( onPressed: () { nodeViewModel.save(); + Navigator.pop(context); }, text: S.of(context).continue_text, color: Theme.of(context).accentTextTheme.bodyText1!.color!, diff --git a/lib/src/screens/new_wallet/new_wallet_page.dart b/lib/src/screens/new_wallet/new_wallet_page.dart index 0abeaede2..9e0cd898c 100644 --- a/lib/src/screens/new_wallet/new_wallet_page.dart +++ b/lib/src/screens/new_wallet/new_wallet_page.dart @@ -219,7 +219,7 @@ class _WalletNameFormState extends State { GestureDetector( onTap: () { Navigator.of(context) - .pushNamed(Routes.privacySettings, arguments: _walletNewVM.type); + .pushNamed(Routes.advancedPrivacySettings, arguments: _walletNewVM.type); }, child: Text(S.of(context).advanced_privacy_settings), ), diff --git a/lib/view_model/advanced_privacy_settings_view_model.dart b/lib/view_model/advanced_privacy_settings_view_model.dart new file mode 100644 index 000000000..ef9ab878f --- /dev/null +++ b/lib/view_model/advanced_privacy_settings_view_model.dart @@ -0,0 +1,51 @@ +import 'package:cake_wallet/store/settings_store.dart'; +import 'package:cake_wallet/view_model/settings/switcher_list_item.dart'; +import 'package:cw_core/wallet_type.dart'; +import 'package:mobx/mobx.dart'; +import 'package:cake_wallet/generated/i18n.dart'; + +part 'advanced_privacy_settings_view_model.g.dart'; + +class AdvancedPrivacySettingsViewModel = AdvancedPrivacySettingsViewModelBase + with _$AdvancedPrivacySettingsViewModel; + +abstract class AdvancedPrivacySettingsViewModelBase with Store { + AdvancedPrivacySettingsViewModelBase(this.type, this._settingsStore) + : _disableFiat = false, + _addCustomNode = false { + settings = [ + // TODO: uncomment when Disable Fiat PR is merged + // SwitcherListItem( + // title: S.current.disable_fiat, + // value: () => _disableFiat, + // onValueChange: (_, bool value) => _disableFiat = value, + // ), + SwitcherListItem( + title: S.current.disable_exchange, + value: () => _settingsStore.disableExchange, + onValueChange: (_, bool value) { + _settingsStore.disableExchange = value; + }, + ), + SwitcherListItem( + title: S.current.add_custom_node, + value: () => _addCustomNode, + onValueChange: (_, bool value) => _addCustomNode = value, + ), + ]; + } + + late List settings; + + @observable + bool _disableFiat = false; + + @observable + bool _addCustomNode = false; + + final WalletType type; + final SettingsStore _settingsStore; + + @computed + bool get addCustomNode => _addCustomNode; +} diff --git a/lib/view_model/privacy_settings_view_model.dart b/lib/view_model/privacy_settings_view_model.dart deleted file mode 100644 index 760c577ef..000000000 --- a/lib/view_model/privacy_settings_view_model.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'package:cake_wallet/view_model/settings/switcher_list_item.dart'; -import 'package:cw_core/wallet_type.dart'; -import 'package:mobx/mobx.dart'; -import 'package:cake_wallet/generated/i18n.dart'; - -part 'privacy_settings_view_model.g.dart'; - -class PrivacySettingsViewModel = PrivacySettingsViewModelBase - with _$PrivacySettingsViewModel; - -abstract class PrivacySettingsViewModelBase with Store { - PrivacySettingsViewModelBase(this.type) - : _disableFiat = false, - _disableExchange = false, - _addCustomNode = false { - settings = [ - SwitcherListItem( - // TODO: replace when Disable Fiat PR is merged - title: "Disable Fiat API", - // title: S.current.disable_fiat, - value: () => _disableFiat, - onValueChange: (_, bool value) => _disableFiat = value, - ), - SwitcherListItem( - title: "Disable Exchange", - // title: S.current.disable_exchange, - value: () => _disableExchange, - onValueChange: (_, bool value) => _disableExchange = value, - ), - SwitcherListItem( - title: "Add New Custom Node", - // title: S.current.add_custom_node, - value: () => _addCustomNode, - onValueChange: (_, bool value) => _addCustomNode = value, - ), - ]; - } - - late List settings; - - @observable - bool _disableFiat = false; - - @observable - bool _disableExchange = false; - - @observable - bool _addCustomNode = false; - - final WalletType type; - - @computed - bool get addCustomNode => _addCustomNode; -} diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index 8f339d090..d9eb8d78a 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -663,5 +663,6 @@ "other_settings": "Andere Einstellungen", "disable_exchange": "Exchange deaktivieren", "advanced_privacy_settings": "Erweiterte Datenschutzeinstellungen", - "settings_can_be_changed_later": "Diese Einstellungen können später in den App-Einstellungen geändert werden" + "settings_can_be_changed_later": "Diese Einstellungen können später in den App-Einstellungen geändert werden", + "add_custom_node": "Neuen benutzerdefinierten Knoten hinzufügen" } diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index b50ba6c83..baf955fcd 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -663,5 +663,6 @@ "other_settings": "Other settings", "disable_exchange": "Disable exchange", "advanced_privacy_settings": "Advanced Privacy Settings", - "settings_can_be_changed_later": "These settings can be changed later in the app settings" + "settings_can_be_changed_later": "These settings can be changed later in the app settings", + "add_custom_node": "Add New Custom Node" } diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index 738e64849..54b3fae18 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -663,5 +663,6 @@ "other_settings": "Otras configuraciones", "disable_exchange": "Deshabilitar intercambio", "advanced_privacy_settings": "Configuración avanzada de privacidad", - "settings_can_be_changed_later": "Estas configuraciones se pueden cambiar más tarde en la configuración de la aplicación" + "settings_can_be_changed_later": "Estas configuraciones se pueden cambiar más tarde en la configuración de la aplicación", + "add_custom_node": "Agregar nuevo nodo personalizado" } diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb index f04a6181c..b6836ab18 100644 --- a/res/values/strings_fr.arb +++ b/res/values/strings_fr.arb @@ -661,5 +661,6 @@ "other_settings": "Autres paramètres", "disable_exchange": "Désactiver l'échange", "advanced_privacy_settings": "Paramètres de confidentialité avancés", - "settings_can_be_changed_later": "Ces paramètres peuvent être modifiés ultérieurement dans les paramètres de l'application" + "settings_can_be_changed_later": "Ces paramètres peuvent être modifiés ultérieurement dans les paramètres de l'application", + "add_custom_node": "Ajouter un nouveau nœud personnalisé" } diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index fdf565a7b..72a21f333 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -663,5 +663,6 @@ "other_settings": "अन्य सेटिंग्स", "disable_exchange": "एक्सचेंज अक्षम करें", "advanced_privacy_settings": "उन्नत गोपनीयता सेटिंग्स", - "settings_can_be_changed_later": "इन सेटिंग्स को बाद में ऐप सेटिंग में बदला जा सकता है" + "settings_can_be_changed_later": "इन सेटिंग्स को बाद में ऐप सेटिंग में बदला जा सकता है", + "add_custom_node": "नया कस्टम नोड जोड़ें" } diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index ece52e656..16b388a05 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -663,5 +663,6 @@ "other_settings": "Ostale postavke", "disable_exchange": "Onemogući exchange", "advanced_privacy_settings": "Napredne postavke privatnosti", - "settings_can_be_changed_later": "Te se postavke mogu promijeniti kasnije u postavkama aplikacije" + "settings_can_be_changed_later": "Te se postavke mogu promijeniti kasnije u postavkama aplikacije", + "add_custom_node": "Dodaj novi prilagođeni čvor" } diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb index d5f591c64..28ad40d47 100644 --- a/res/values/strings_it.arb +++ b/res/values/strings_it.arb @@ -663,5 +663,6 @@ "other_settings": "Altre impostazioni", "disable_exchange": "Disabilita scambio", "advanced_privacy_settings": "Impostazioni avanzate sulla privacy", - "settings_can_be_changed_later": "Queste impostazioni possono essere modificate in seguito nelle impostazioni dell'app" + "settings_can_be_changed_later": "Queste impostazioni possono essere modificate in seguito nelle impostazioni dell'app", + "add_custom_node": "Aggiungi nuovo nodo personalizzato" } diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index 21c21c7a8..d79f58e7a 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -663,5 +663,6 @@ "other_settings": "その他の設定", "disable_exchange": "交換を無効にする", "advanced_privacy_settings": "高度なプライバシー設定", - "settings_can_be_changed_later": "これらの設定は、後でアプリの設定で変更できます" + "settings_can_be_changed_later": "これらの設定は、後でアプリの設定で変更できます", + "add_custom_node": "新しいカスタム ノードを追加" } diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index 0d2bc31bc..0652ffc54 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -663,5 +663,6 @@ "other_settings": "기타 설정", "disable_exchange": "교환 비활성화", "advanced_privacy_settings": "고급 개인 정보 설정", - "settings_can_be_changed_later": "이 설정은 나중에 앱 설정에서 변경할 수 있습니다." + "settings_can_be_changed_later": "이 설정은 나중에 앱 설정에서 변경할 수 있습니다.", + "add_custom_node": "새 사용자 정의 노드 추가" } diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index b7bb86d9c..2c6e528ca 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -663,5 +663,6 @@ "other_settings": "Andere instellingen", "disable_exchange": "Uitwisseling uitschakelen", "advanced_privacy_settings": "Geavanceerde privacy-instellingen", - "settings_can_be_changed_later": "Deze instellingen kunnen later worden gewijzigd in de app-instellingen" + "settings_can_be_changed_later": "Deze instellingen kunnen later worden gewijzigd in de app-instellingen", + "add_custom_node": "Voeg een nieuw aangepast knooppunt toe" } diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index 20a0b2f98..179f7267b 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -663,5 +663,6 @@ "other_settings": "Inne ustawienia", "disable_exchange": "Wyłącz wymianę", "advanced_privacy_settings": "Zaawansowane ustawienia prywatności", - "settings_can_be_changed_later": "Te ustawienia można później zmienić w ustawieniach aplikacji" + "settings_can_be_changed_later": "Te ustawienia można później zmienić w ustawieniach aplikacji", + "add_custom_node": "Dodaj nowy węzeł niestandardowy" } diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index 65438a26c..cf0669585 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -662,5 +662,6 @@ "other_settings": "Outras configurações", "disable_exchange": "Desativar troca", "advanced_privacy_settings": "Configurações de privacidade avançadas", - "settings_can_be_changed_later": "Essas configurações podem ser alteradas posteriormente nas configurações do aplicativo" + "settings_can_be_changed_later": "Essas configurações podem ser alteradas posteriormente nas configurações do aplicativo", + "add_custom_node": "Adicionar novo nó personalizado" } diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index 4dcda3007..f73ad4564 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -663,5 +663,6 @@ "other_settings": "Другие настройки", "disable_exchange": "Отключить обмен", "advanced_privacy_settings": "Расширенные настройки конфиденциальности", - "settings_can_be_changed_later": "Эти настройки можно изменить позже в настройках приложения." + "settings_can_be_changed_later": "Эти настройки можно изменить позже в настройках приложения.", + "add_custom_node": "Добавить новый пользовательский узел" } diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index 61f6cfb0d..c52359d64 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -662,5 +662,6 @@ "other_settings": "Інші налаштування", "disable_exchange": "Вимкнути exchange", "advanced_privacy_settings": "Розширені налаштування конфіденційності", - "settings_can_be_changed_later": "Ці параметри можна змінити пізніше в налаштуваннях програми" + "settings_can_be_changed_later": "Ці параметри можна змінити пізніше в налаштуваннях програми", + "add_custom_node": "Додати новий спеціальний вузол" } diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index 750b4e605..a8f9119da 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -661,5 +661,6 @@ "other_settings": "其他设置", "disable_exchange": "禁用交换", "advanced_privacy_settings": "高级隐私设置", - "settings_can_be_changed_later": "稍后可以在应用设置中更改这些设置" + "settings_can_be_changed_later": "稍后可以在应用设置中更改这些设置", + "add_custom_node": "添加新的自定义节点" } From 7e6439947645fc197d74127d0c593161dcfffe8d Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Sun, 4 Dec 2022 05:27:49 +0200 Subject: [PATCH 33/47] remove un-necessary attributes passing --- .../advanced_privacy_settings_page.dart | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart index 33aca0307..e0dd1a729 100644 --- a/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart +++ b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart @@ -31,16 +31,11 @@ class AdvancedPrivacySettingsBody extends StatefulWidget { final NodeCreateOrEditViewModel nodeViewModel; @override - _AdvancedPrivacySettingsBodyState createState() => - _AdvancedPrivacySettingsBodyState(privacySettingsViewModel, nodeViewModel); + _AdvancedPrivacySettingsBodyState createState() => _AdvancedPrivacySettingsBodyState(); } -class _AdvancedPrivacySettingsBodyState - extends State { - _AdvancedPrivacySettingsBodyState(this.privacySettingsViewModel, this.nodeViewModel); - - final AdvancedPrivacySettingsViewModel privacySettingsViewModel; - final NodeCreateOrEditViewModel nodeViewModel; +class _AdvancedPrivacySettingsBodyState extends State { + _AdvancedPrivacySettingsBodyState(); final _formKey = GlobalKey(); @@ -53,7 +48,7 @@ class _AdvancedPrivacySettingsBodyState content: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ - ...privacySettingsViewModel.settings.map( + ...widget.privacySettingsViewModel.settings.map( (item) => Observer( builder: (_) => SettingsSwitcherCell( title: item.title, @@ -64,12 +59,12 @@ class _AdvancedPrivacySettingsBodyState ), Observer( builder: (_) { - if (privacySettingsViewModel.addCustomNode) { + if (widget.privacySettingsViewModel.addCustomNode) { return Padding( padding: EdgeInsets.only(left: 24, right: 24, top: 24), child: NodeForm( formKey: _formKey, - nodeViewModel: nodeViewModel, + nodeViewModel: widget.nodeViewModel, ), ); } @@ -83,7 +78,7 @@ class _AdvancedPrivacySettingsBodyState children: [ LoadingPrimaryButton( onPressed: () { - nodeViewModel.save(); + widget.nodeViewModel.save(); Navigator.pop(context); }, text: S.of(context).continue_text, @@ -92,8 +87,7 @@ class _AdvancedPrivacySettingsBodyState ), const SizedBox(height: 25), Padding( - padding: EdgeInsets.symmetric( - horizontal: MediaQuery.of(context).size.width * 0.15), + padding: EdgeInsets.symmetric(horizontal: MediaQuery.of(context).size.width * 0.15), child: Text( S.of(context).settings_can_be_changed_later, textAlign: TextAlign.center, From 9eb8a442d813ece2f9f73b11142afc30faf96721 Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Sun, 4 Dec 2022 17:30:09 +0200 Subject: [PATCH 34/47] Allow setting the new added node as the current selected node --- lib/di.dart | 7 +++++-- .../new_wallet/advanced_privacy_settings_page.dart | 8 ++++---- .../node_list/node_create_or_edit_view_model.dart | 11 +++++++++-- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/di.dart b/lib/di.dart index 7a7621203..a5c7702d8 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -500,8 +500,11 @@ Future setup( getIt.registerFactory(() => OtherSettingsPage(getIt.get())); getIt.registerFactoryParam( - (WalletType? type, _) => - NodeCreateOrEditViewModel(_nodeSource, type ?? getIt.get().wallet!.type)); + (WalletType? type, _) => NodeCreateOrEditViewModel( + _nodeSource, + type ?? getIt.get().wallet!.type, + getIt.get(), + )); getIt.registerFactory( () => NodeCreateOrEditPage(getIt.get())); diff --git a/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart index e0dd1a729..ff1c83f90 100644 --- a/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart +++ b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart @@ -10,9 +10,9 @@ import 'package:cake_wallet/src/widgets/primary_button.dart'; import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; class AdvancedPrivacySettingsPage extends BasePage { - AdvancedPrivacySettingsPage(this.privacySettingsViewModel, this.nodeViewModel); + AdvancedPrivacySettingsPage(this.advancedPrivacySettingsViewModel, this.nodeViewModel); - final AdvancedPrivacySettingsViewModel privacySettingsViewModel; + final AdvancedPrivacySettingsViewModel advancedPrivacySettingsViewModel; final NodeCreateOrEditViewModel nodeViewModel; @override @@ -20,7 +20,7 @@ class AdvancedPrivacySettingsPage extends BasePage { @override Widget body(BuildContext context) => - AdvancedPrivacySettingsBody(privacySettingsViewModel, nodeViewModel); + AdvancedPrivacySettingsBody(advancedPrivacySettingsViewModel, nodeViewModel); } class AdvancedPrivacySettingsBody extends StatefulWidget { @@ -78,7 +78,7 @@ class _AdvancedPrivacySettingsBodyState extends State _nodeSource; + final SettingsStore _settingsStore; @action void reset() { @@ -75,13 +77,18 @@ abstract class NodeCreateOrEditViewModelBase with Store { } @action - Future save() async { + Future save({bool saveAsCurrent = false}) async { try { state = IsExecutingState(); final node = Node(uri: uri, type: _walletType, login: login, password: password, useSSL: useSSL, trusted: trusted); await _nodeSource.add(node); + + if (saveAsCurrent) { + _settingsStore.nodes[_walletType] = node; + } + state = ExecutedSuccessfullyState(); } catch (e) { state = FailureState(e.toString()); From 3aa0e626ff2e1936bed9d9bbdb248d867d68e035 Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Mon, 5 Dec 2022 18:37:35 +0200 Subject: [PATCH 35/47] Pass selected currency to the view model instead of the UI --- lib/di.dart | 8 ++-- .../screens/contact/contact_list_page.dart | 23 +++++------ .../contact_list/contact_list_view_model.dart | 39 ++++++++----------- 3 files changed, 28 insertions(+), 42 deletions(-) diff --git a/lib/di.dart b/lib/di.dart index 539681036..c37f4eeac 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -459,13 +459,11 @@ Future setup( (ContactRecord? contact, _) => ContactViewModel(_contactSource, contact: contact)); - getIt.registerFactory( - () => ContactListViewModel(_contactSource, _walletInfoSource)); + getIt.registerFactoryParam( + (CryptoCurrency? cur, _) => ContactListViewModel(_contactSource, _walletInfoSource, cur)); getIt.registerFactoryParam((CryptoCurrency? cur, _) - => ContactListPage( - getIt.get(), - selectedCurrency: cur)); + => ContactListPage(getIt.get(param1: cur))); getIt.registerFactoryParam( (ContactRecord? contact, _) => diff --git a/lib/src/screens/contact/contact_list_page.dart b/lib/src/screens/contact/contact_list_page.dart index 9d0d1ab5a..7cd7a0157 100644 --- a/lib/src/screens/contact/contact_list_page.dart +++ b/lib/src/screens/contact/contact_list_page.dart @@ -9,25 +9,22 @@ import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cw_core/crypto_currency.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart'; import 'package:cake_wallet/src/widgets/collapsible_standart_list.dart'; class ContactListPage extends BasePage { - ContactListPage(this.contactListViewModel, - {this.selectedCurrency}); + ContactListPage(this.contactListViewModel); final ContactListViewModel contactListViewModel; - final CryptoCurrency? selectedCurrency; @override String get title => S.current.address_book; @override Widget? trailing(BuildContext context) { - if (selectedCurrency != null) { + if (!contactListViewModel.isEditable) { return null; } @@ -66,10 +63,8 @@ class ContactListPage extends BasePage { padding: EdgeInsets.only(top: 20.0, bottom: 20.0), child: Observer( builder: (_) { - final contacts = - contactListViewModel.getContacts(selectedCurrency); - final walletContacts = - contactListViewModel.getWallets(selectedCurrency); + final contacts = contactListViewModel.contactsToShow; + final walletContacts = contactListViewModel.walletContactsToShow; return CollapsibleSectionList( context: context, sectionCount: 2, @@ -98,13 +93,13 @@ class ContactListPage extends BasePage { final contact = contacts[index]; final content = generateRaw(context, contact); - return selectedCurrency != null - ? content - : Slidable( + return contactListViewModel.isEditable + ? Slidable( key: Key('${contact.key}'), endActionPane: _actionPane(context, contact), child: content, - ); + ) + : content; }, );}) ); @@ -118,7 +113,7 @@ class ContactListPage extends BasePage { return GestureDetector( onTap: () async { - if (selectedCurrency != null) { + if (!contactListViewModel.isEditable) { Navigator.of(context).pop(contact); return; } diff --git a/lib/view_model/contact_list/contact_list_view_model.dart b/lib/view_model/contact_list/contact_list_view_model.dart index 3fa9a73a4..5b0187fc8 100644 --- a/lib/view_model/contact_list/contact_list_view_model.dart +++ b/lib/view_model/contact_list/contact_list_view_model.dart @@ -11,24 +11,22 @@ import 'package:cw_core/crypto_currency.dart'; part 'contact_list_view_model.g.dart'; -class ContactListViewModel = ContactListViewModelBase - with _$ContactListViewModel; +class ContactListViewModel = ContactListViewModelBase with _$ContactListViewModel; abstract class ContactListViewModelBase with Store { - ContactListViewModelBase(this.contactSource, this.walletInfoSource) + ContactListViewModelBase(this.contactSource, this.walletInfoSource, this._currency) : contacts = ObservableList(), walletContacts = [] { walletInfoSource.values.forEach((info) { if (info.addresses?.isNotEmpty ?? false) { info.addresses?.forEach((address, label) { - final name = label.isNotEmpty - ? info.name + ' ($label)' - : info.name; + final name = label.isNotEmpty ? info.name + ' ($label)' : info.name; walletContacts.add(WalletContact( - address, - name, - walletTypeToCryptoCurrency(info.type))); + address, + name, + walletTypeToCryptoCurrency(info.type), + )); }); } }); @@ -42,23 +40,18 @@ abstract class ContactListViewModelBase with Store { final Box walletInfoSource; final ObservableList contacts; final List walletContacts; + final CryptoCurrency? _currency; StreamSubscription? _subscription; + bool get isEditable => _currency == null; + Future delete(ContactRecord contact) async => contact.original.delete(); - List getContacts(CryptoCurrency? cur) { - if (cur != null) { - return contacts.where((element) => element.type == cur).toList(); - } + @computed + List get contactsToShow => + contacts.where((element) => _currency == null || element.type == _currency).toList(); - return contacts; - } - - List getWallets(CryptoCurrency? cur) { - if (cur != null) { - return walletContacts.where((element) => element.type == cur).toList(); - } - - return walletContacts; - } + @computed + List get walletContactsToShow => + walletContacts.where((element) => _currency == null || element.type == _currency).toList(); } From d19f7b6d3896e39cd906c08bd7eb4358df661f70 Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Mon, 5 Dec 2022 18:40:53 +0200 Subject: [PATCH 36/47] Remove unused state 'denied' from authentication state [skip ci] --- lib/reactions/on_authentication_state_change.dart | 5 ----- lib/store/authentication_store.dart | 5 +---- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/lib/reactions/on_authentication_state_change.dart b/lib/reactions/on_authentication_state_change.dart index c91f5277e..edadf33b0 100644 --- a/lib/reactions/on_authentication_state_change.dart +++ b/lib/reactions/on_authentication_state_change.dart @@ -26,10 +26,5 @@ void startAuthenticationStateChange(AuthenticationStore authenticationStore, await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false); return; } - - if (state == AuthenticationState.denied) { - await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.welcome, (_) => false); - return; - } }); } diff --git a/lib/store/authentication_store.dart b/lib/store/authentication_store.dart index 626ca2a91..b734d7acb 100644 --- a/lib/store/authentication_store.dart +++ b/lib/store/authentication_store.dart @@ -4,7 +4,7 @@ part 'authentication_store.g.dart'; class AuthenticationStore = AuthenticationStoreBase with _$AuthenticationStore; -enum AuthenticationState { uninitialized, installed, allowed, denied } +enum AuthenticationState { uninitialized, installed, allowed } abstract class AuthenticationStoreBase with Store { AuthenticationStoreBase() : state = AuthenticationState.uninitialized; @@ -17,7 +17,4 @@ abstract class AuthenticationStoreBase with Store { @action void allowed() => state = AuthenticationState.allowed; - - @action - void denied() => state = AuthenticationState.denied; } From 35b7c05bc1650d41b25c3cc67385cd7b5a8caf95 Mon Sep 17 00:00:00 2001 From: Serhii Date: Tue, 6 Dec 2022 11:41:25 +0200 Subject: [PATCH 37/47] fix null check --- .../sideshift/sideshift_exchange_provider.dart | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/exchange/sideshift/sideshift_exchange_provider.dart b/lib/exchange/sideshift/sideshift_exchange_provider.dart index 8cd4593c1..23e506858 100644 --- a/lib/exchange/sideshift/sideshift_exchange_provider.dart +++ b/lib/exchange/sideshift/sideshift_exchange_provider.dart @@ -249,12 +249,14 @@ class SideShiftExchangeProvider extends ExchangeProvider { final expectedSendAmount = responseJSON['depositAmount'].toString(); final deposits = responseJSON['deposits'] as List?; TradeState? state; - - if (deposits != null && deposits.isEmpty) { - state = TradeState.deserialize(raw: 'created'); - } else { - final status = deposits?[0]['status'] as String; - state = TradeState.deserialize(raw: status); + + if (deposits != null) { + if (deposits.isEmpty) { + state = TradeState.deserialize(raw: 'created'); + } else { + final status = deposits[0]['status'] as String; + state = TradeState.deserialize(raw: status); + } } final expiredAtRaw = responseJSON['expiresAtISO'] as String; From 36c27026881c4bbbd957fd65cfbfb64a9c76d301 Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Tue, 6 Dec 2022 13:30:11 +0200 Subject: [PATCH 38/47] - Recalculate best rate if isFixedRate changed - check limits against the receive amount if isFixedRate --- .../exchange/exchange_view_model.dart | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/lib/view_model/exchange/exchange_view_model.dart b/lib/view_model/exchange/exchange_view_model.dart index b19434166..cda65527a 100644 --- a/lib/view_model/exchange/exchange_view_model.dart +++ b/lib/view_model/exchange/exchange_view_model.dart @@ -44,7 +44,6 @@ abstract class ExchangeViewModelBase with Store { ExchangeViewModelBase(this.wallet, this.trades, this._exchangeTemplateStore, this.tradesStore, this._settingsStore, this.sharedPreferences) : _cryptoNumberFormat = NumberFormat(), - isReverse = false, isFixedRateMode = false, isReceiveAmountEntered = false, depositAmount = '', @@ -112,7 +111,11 @@ abstract class ExchangeViewModelBase with Store { loadLimits(); reaction( (_) => isFixedRateMode, - (Object _) => loadLimits()); + (Object _) { + loadLimits(); + _bestRate = 0; + _calculateBestRate(); + }); } final WalletBase wallet; @@ -227,8 +230,6 @@ abstract class ExchangeViewModelBase with Store { Limits limits; - bool isReverse; - NumberFormat _cryptoNumberFormat; final SettingsStore _settingsStore; @@ -258,7 +259,6 @@ abstract class ExchangeViewModelBase with Store { @action Future changeReceiveAmount({required String amount}) async { receiveAmount = amount; - isReverse = true; if (amount.isEmpty) { depositAmount = ''; @@ -283,7 +283,6 @@ abstract class ExchangeViewModelBase with Store { @action Future changeDepositAmount({required String amount}) async { depositAmount = amount; - isReverse = false; if (amount.isEmpty) { depositAmount = ''; @@ -307,7 +306,7 @@ abstract class ExchangeViewModelBase with Store { } Future _calculateBestRate() async { - final amount = double.tryParse(isFixedRateMode ? receiveAmount : depositAmount) ?? 1; + final amount = double.tryParse(depositAmount) ?? 1; final result = await Future.wait( _tradeAvailableProviders @@ -401,7 +400,7 @@ abstract class ExchangeViewModelBase with Store { settleAddress: receiveAddress, refundAddress: depositAddress, ); - amount = depositAmount; + amount = isFixedRateMode ? receiveAmount : depositAmount; } if (provider is SimpleSwapExchangeProvider) { @@ -412,7 +411,7 @@ abstract class ExchangeViewModelBase with Store { address: receiveAddress, refundAddress: depositAddress, ); - amount = depositAmount; + amount = isFixedRateMode ? receiveAmount : depositAmount; } if (provider is XMRTOExchangeProvider) { @@ -424,7 +423,7 @@ abstract class ExchangeViewModelBase with Store { address: receiveAddress, refundAddress: depositAddress, isBTCRequest: isReceiveAmountEntered); - amount = depositAmount; + amount = isFixedRateMode ? receiveAmount : depositAmount; } if (provider is ChangeNowExchangeProvider) { @@ -435,8 +434,8 @@ abstract class ExchangeViewModelBase with Store { toAmount: receiveAmount.replaceAll(',', '.'), refundAddress: depositAddress, address: receiveAddress, - isReverse: isReverse); - amount = isReverse ? receiveAmount : depositAmount; + isReverse: isFixedRateMode); + amount = isFixedRateMode ? receiveAmount : depositAmount; } if (provider is MorphTokenExchangeProvider) { @@ -446,13 +445,13 @@ abstract class ExchangeViewModelBase with Store { amount: depositAmount.replaceAll(',', '.'), refundAddress: depositAddress, address: receiveAddress); - amount = depositAmount; + amount = isFixedRateMode ? receiveAmount : depositAmount; } amount = amount.replaceAll(',', '.'); if (limitsState is LimitsLoadedSuccessfully) { - if (double.parse(amount) < limits.min!) { + if (limits.max != null && double.parse(amount) < limits.min!) { continue; } else if (limits.max != null && double.parse(amount) > limits.max!) { continue; From 8514887da6f48262b8f5ab6aed254167bf43502b Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Tue, 6 Dec 2022 15:40:40 +0200 Subject: [PATCH 39/47] Negate is Fixed rate mode in simpleswap --- .../simpleswap/simpleswap_exchange_provider.dart | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/exchange/simpleswap/simpleswap_exchange_provider.dart b/lib/exchange/simpleswap/simpleswap_exchange_provider.dart index c6e1baeea..0fb799cec 100644 --- a/lib/exchange/simpleswap/simpleswap_exchange_provider.dart +++ b/lib/exchange/simpleswap/simpleswap_exchange_provider.dart @@ -20,8 +20,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider { .where((i) => i != CryptoCurrency.zaddr) .map((i) => CryptoCurrency.all .where((i) => i != CryptoCurrency.zaddr) - .map((k) => ExchangePair(from: i, to: k, reverse: true)) - .where((c) => c != null)) + .map((k) => ExchangePair(from: i, to: k, reverse: true))) .expand((i) => i) .toList()); @@ -54,12 +53,12 @@ class SimpleSwapExchangeProvider extends ExchangeProvider { 'currency_from': fromCurrency, 'currency_to': toCurrency, 'amount': amount.toString(), - 'fixed': isFixedRateMode.toString() + 'fixed': (!isFixedRateMode).toString() }; final uri = Uri.https(apiAuthority, getEstimatePath, params); final response = await get(uri); - if (response.body == null || response.body == "null") return 0.00; + if (response.body == "null") return 0.00; final data = json.decode(response.body) as String; return double.parse(data); } catch (_) { @@ -87,7 +86,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider { "currency_from": _normalizeCryptoCurrency(_request.from), "currency_to": _normalizeCryptoCurrency(_request.to), "amount": _request.amount, - "fixed": isFixedRateMode, + "fixed": !isFixedRateMode, "user_refund_address": _request.refundAddress, "address_to": _request.address }; From f29f17476c0faf16dfc169067841c9b937511d66 Mon Sep 17 00:00:00 2001 From: Serhii Date: Tue, 6 Dec 2022 17:14:07 +0200 Subject: [PATCH 40/47] add null check [skip ci] --- .../sideshift/sideshift_exchange_provider.dart | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/exchange/sideshift/sideshift_exchange_provider.dart b/lib/exchange/sideshift/sideshift_exchange_provider.dart index 23e506858..0cd74061f 100644 --- a/lib/exchange/sideshift/sideshift_exchange_provider.dart +++ b/lib/exchange/sideshift/sideshift_exchange_provider.dart @@ -249,15 +249,12 @@ class SideShiftExchangeProvider extends ExchangeProvider { final expectedSendAmount = responseJSON['depositAmount'].toString(); final deposits = responseJSON['deposits'] as List?; TradeState? state; - - if (deposits != null) { - if (deposits.isEmpty) { - state = TradeState.deserialize(raw: 'created'); - } else { - final status = deposits[0]['status'] as String; - state = TradeState.deserialize(raw: status); - } + String? status; + + if (deposits?.isNotEmpty ?? false) { + status = deposits![0]['status'] as String; } + state = TradeState.deserialize(raw: status ?? 'created'); final expiredAtRaw = responseJSON['expiresAtISO'] as String; final expiredAt = From fa5c705bc888abea53703ca06589e344a63d7ee8 Mon Sep 17 00:00:00 2001 From: Omar Hatem Date: Tue, 6 Dec 2022 17:29:44 +0200 Subject: [PATCH 41/47] Add nullability to `status` String [skip ci] --- lib/exchange/sideshift/sideshift_exchange_provider.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/exchange/sideshift/sideshift_exchange_provider.dart b/lib/exchange/sideshift/sideshift_exchange_provider.dart index 0cd74061f..920dc9907 100644 --- a/lib/exchange/sideshift/sideshift_exchange_provider.dart +++ b/lib/exchange/sideshift/sideshift_exchange_provider.dart @@ -252,7 +252,7 @@ class SideShiftExchangeProvider extends ExchangeProvider { String? status; if (deposits?.isNotEmpty ?? false) { - status = deposits![0]['status'] as String; + status = deposits![0]['status'] as String?; } state = TradeState.deserialize(raw: status ?? 'created'); From f14c01303fa08dd0a8d80571bf61e16ac990da39 Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Tue, 6 Dec 2022 19:23:46 +0200 Subject: [PATCH 42/47] - Add whether this provide supports fixed rate or not - Fix Change now fixed rate exchange due to wrong rate id --- .../changenow_exchange_provider.dart | 20 +++++++++++++------ lib/exchange/exchange_provider.dart | 2 +- .../morphtoken_exchange_provider.dart | 3 +++ .../sideshift_exchange_provider.dart | 10 +++++----- .../simpleswap_exchange_provider.dart | 3 +++ .../xmrto/xmrto_exchange_provider.dart | 3 +++ .../exchange/exchange_view_model.dart | 3 ++- 7 files changed, 31 insertions(+), 13 deletions(-) diff --git a/lib/exchange/changenow/changenow_exchange_provider.dart b/lib/exchange/changenow/changenow_exchange_provider.dart index 96b6142e6..8ef376370 100644 --- a/lib/exchange/changenow/changenow_exchange_provider.dart +++ b/lib/exchange/changenow/changenow_exchange_provider.dart @@ -11,7 +11,6 @@ import 'package:cake_wallet/exchange/trade_request.dart'; import 'package:cake_wallet/exchange/trade_state.dart'; import 'package:cake_wallet/exchange/changenow/changenow_request.dart'; import 'package:cake_wallet/exchange/exchange_provider_description.dart'; -import 'package:cake_wallet/exchange/trade_not_created_exeption.dart'; class ChangeNowExchangeProvider extends ExchangeProvider { ChangeNowExchangeProvider() @@ -21,8 +20,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider { .where((i) => i != CryptoCurrency.xhv) .map((i) => CryptoCurrency.all .where((i) => i != CryptoCurrency.xhv) - .map((k) => ExchangePair(from: i, to: k, reverse: true)) - .where((c) => c != null)) + .map((k) => ExchangePair(from: i, to: k, reverse: true))) .expand((i) => i) .toList()); @@ -43,6 +41,9 @@ class ChangeNowExchangeProvider extends ExchangeProvider { @override bool get isEnabled => true; + @override + bool get supportsFixedRate => true; + @override ExchangeProviderDescription get description => ExchangeProviderDescription.changeNow; @@ -109,6 +110,15 @@ class ChangeNowExchangeProvider extends ExchangeProvider { }; if (isFixedRateMode) { + // since we schedule to calculate the rate every 5 seconds we need to ensure that + // we have the latest rate id with the given inputs before creating the trade + await calculateAmount( + from: _request.to, + to: _request.from, + amount: double.tryParse(_request.toAmount) ?? 0, + isFixedRateMode: true, + isReceiveAmount: true, + ); body['rateId'] = _lastUsedRateId; } @@ -180,9 +190,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider { final extraId = responseJSON['payinExtraId'] as String; final outputTransaction = responseJSON['payoutHash'] as String; final expiredAtRaw = responseJSON['validUntil'] as String; - final expiredAt = expiredAtRaw != null - ? DateTime.parse(expiredAtRaw).toLocal() - : null; + final expiredAt = DateTime.tryParse(expiredAtRaw)?.toLocal(); return Trade( id: id, diff --git a/lib/exchange/exchange_provider.dart b/lib/exchange/exchange_provider.dart index 14fba803f..108256015 100644 --- a/lib/exchange/exchange_provider.dart +++ b/lib/exchange/exchange_provider.dart @@ -1,4 +1,3 @@ -import 'package:flutter/foundation.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:cake_wallet/exchange/trade_request.dart'; import 'package:cake_wallet/exchange/exchange_pair.dart'; @@ -14,6 +13,7 @@ abstract class ExchangeProvider { ExchangeProviderDescription get description; bool get isAvailable; bool get isEnabled; + bool get supportsFixedRate; @override String toString() => title; diff --git a/lib/exchange/morphtoken/morphtoken_exchange_provider.dart b/lib/exchange/morphtoken/morphtoken_exchange_provider.dart index 1df4fef87..6650d4f3a 100644 --- a/lib/exchange/morphtoken/morphtoken_exchange_provider.dart +++ b/lib/exchange/morphtoken/morphtoken_exchange_provider.dart @@ -66,6 +66,9 @@ class MorphTokenExchangeProvider extends ExchangeProvider { @override bool get isEnabled => true; + @override + bool get supportsFixedRate => false; + @override ExchangeProviderDescription get description => ExchangeProviderDescription.morphToken; diff --git a/lib/exchange/sideshift/sideshift_exchange_provider.dart b/lib/exchange/sideshift/sideshift_exchange_provider.dart index 920dc9907..b93f0a80f 100644 --- a/lib/exchange/sideshift/sideshift_exchange_provider.dart +++ b/lib/exchange/sideshift/sideshift_exchange_provider.dart @@ -12,7 +12,6 @@ import 'package:cw_core/crypto_currency.dart'; import 'package:cake_wallet/exchange/trade_request.dart'; import 'package:cake_wallet/exchange/trade.dart'; import 'package:cake_wallet/exchange/limits.dart'; -import 'package:flutter/foundation.dart'; import 'package:http/http.dart'; class SideShiftExchangeProvider extends ExchangeProvider { @@ -48,8 +47,7 @@ class SideShiftExchangeProvider extends ExchangeProvider { return supportedCurrencies .map((i) => supportedCurrencies - .map((k) => ExchangePair(from: i, to: k, reverse: true)) - .where((c) => c != null)) + .map((k) => ExchangePair(from: i, to: k, reverse: true))) .expand((i) => i) .toList(); } @@ -257,8 +255,7 @@ class SideShiftExchangeProvider extends ExchangeProvider { state = TradeState.deserialize(raw: status ?? 'created'); final expiredAtRaw = responseJSON['expiresAtISO'] as String; - final expiredAt = - expiredAtRaw != null ? DateTime.parse(expiredAtRaw).toLocal() : null; + final expiredAt = DateTime.tryParse(expiredAtRaw)?.toLocal(); return Trade( id: id, @@ -278,6 +275,9 @@ class SideShiftExchangeProvider extends ExchangeProvider { @override bool get isEnabled => true; + @override + bool get supportsFixedRate => true; + @override String get title => 'SideShift'; diff --git a/lib/exchange/simpleswap/simpleswap_exchange_provider.dart b/lib/exchange/simpleswap/simpleswap_exchange_provider.dart index 0fb799cec..97681f0aa 100644 --- a/lib/exchange/simpleswap/simpleswap_exchange_provider.dart +++ b/lib/exchange/simpleswap/simpleswap_exchange_provider.dart @@ -209,6 +209,9 @@ class SimpleSwapExchangeProvider extends ExchangeProvider { @override bool get isEnabled => true; + @override + bool get supportsFixedRate => false; + @override String get title => 'SimpleSwap'; diff --git a/lib/exchange/xmrto/xmrto_exchange_provider.dart b/lib/exchange/xmrto/xmrto_exchange_provider.dart index d5f79361e..da367e4d4 100644 --- a/lib/exchange/xmrto/xmrto_exchange_provider.dart +++ b/lib/exchange/xmrto/xmrto_exchange_provider.dart @@ -48,6 +48,9 @@ class XMRTOExchangeProvider extends ExchangeProvider { @override bool get isEnabled => true; + @override + bool get supportsFixedRate => false; + @override ExchangeProviderDescription get description => ExchangeProviderDescription.xmrto; diff --git a/lib/view_model/exchange/exchange_view_model.dart b/lib/view_model/exchange/exchange_view_model.dart index cda65527a..49ee9ea95 100644 --- a/lib/view_model/exchange/exchange_view_model.dart +++ b/lib/view_model/exchange/exchange_view_model.dart @@ -306,10 +306,11 @@ abstract class ExchangeViewModelBase with Store { } Future _calculateBestRate() async { - final amount = double.tryParse(depositAmount) ?? 1; + final amount = double.tryParse(isFixedRateMode ? receiveAmount : depositAmount) ?? 1; final result = await Future.wait( _tradeAvailableProviders + .where((element) => element.supportsFixedRate) .map((element) => element.calculateAmount( from: depositCurrency, to: receiveCurrency, From a9f0466825247f6e2a877aac3799851adb1bd142 Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Tue, 6 Dec 2022 20:10:26 +0200 Subject: [PATCH 43/47] Revert SimpleSwap changes since we disabled it for fixed rate --- lib/exchange/simpleswap/simpleswap_exchange_provider.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/exchange/simpleswap/simpleswap_exchange_provider.dart b/lib/exchange/simpleswap/simpleswap_exchange_provider.dart index 97681f0aa..4c42835ed 100644 --- a/lib/exchange/simpleswap/simpleswap_exchange_provider.dart +++ b/lib/exchange/simpleswap/simpleswap_exchange_provider.dart @@ -53,7 +53,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider { 'currency_from': fromCurrency, 'currency_to': toCurrency, 'amount': amount.toString(), - 'fixed': (!isFixedRateMode).toString() + 'fixed': isFixedRateMode.toString() }; final uri = Uri.https(apiAuthority, getEstimatePath, params); final response = await get(uri); @@ -86,7 +86,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider { "currency_from": _normalizeCryptoCurrency(_request.from), "currency_to": _normalizeCryptoCurrency(_request.to), "amount": _request.amount, - "fixed": !isFixedRateMode, + "fixed": isFixedRateMode, "user_refund_address": _request.refundAddress, "address_to": _request.address }; From 8ff8cf38b87a577df232b231a4b84ea7f7cd2cb0 Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Wed, 7 Dec 2022 18:15:30 +0200 Subject: [PATCH 44/47] Check if the provider supportsFixedRate only if fixed rate is applied [skip ci] --- lib/view_model/exchange/exchange_view_model.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/view_model/exchange/exchange_view_model.dart b/lib/view_model/exchange/exchange_view_model.dart index 49ee9ea95..510e0ac3a 100644 --- a/lib/view_model/exchange/exchange_view_model.dart +++ b/lib/view_model/exchange/exchange_view_model.dart @@ -310,7 +310,7 @@ abstract class ExchangeViewModelBase with Store { final result = await Future.wait( _tradeAvailableProviders - .where((element) => element.supportsFixedRate) + .where((element) => !isFixedRateMode || element.supportsFixedRate) .map((element) => element.calculateAmount( from: depositCurrency, to: receiveCurrency, From 0da48f66fef74b94270ef77767c64182dbb4f08e Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Wed, 7 Dec 2022 21:09:15 +0200 Subject: [PATCH 45/47] Delegate returning rate to each provider to handle its logic internally --- .../changenow/changenow_exchange_provider.dart | 14 +++++++------- .../sideshift/sideshift_exchange_provider.dart | 4 +--- .../simpleswap/simpleswap_exchange_provider.dart | 2 +- lib/view_model/exchange/exchange_view_model.dart | 4 ++-- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/lib/exchange/changenow/changenow_exchange_provider.dart b/lib/exchange/changenow/changenow_exchange_provider.dart index 8ef376370..ca245923f 100644 --- a/lib/exchange/changenow/changenow_exchange_provider.dart +++ b/lib/exchange/changenow/changenow_exchange_provider.dart @@ -113,8 +113,8 @@ class ChangeNowExchangeProvider extends ExchangeProvider { // since we schedule to calculate the rate every 5 seconds we need to ensure that // we have the latest rate id with the given inputs before creating the trade await calculateAmount( - from: _request.to, - to: _request.from, + from: _request.from, + to: _request.to, amount: double.tryParse(_request.toAmount) ?? 0, isFixedRateMode: true, isReceiveAmount: true, @@ -222,10 +222,10 @@ class ChangeNowExchangeProvider extends ExchangeProvider { final type = isReverse ? 'reverse' : 'direct'; final flow = getFlow(isFixedRateMode); final params = { - 'fromCurrency': isReverse ? normalizeCryptoCurrency(to) : normalizeCryptoCurrency(from), - 'toCurrency': isReverse ? normalizeCryptoCurrency(from) : normalizeCryptoCurrency(to), - 'fromNetwork': isReverse ? networkFor(to) : networkFor(from), - 'toNetwork': isReverse ? networkFor(from) : networkFor(to), + 'fromCurrency': normalizeCryptoCurrency(from), + 'toCurrency': normalizeCryptoCurrency(to), + 'fromNetwork': networkFor(from), + 'toNetwork': networkFor(to), 'type': type, 'flow': flow}; @@ -246,7 +246,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider { _lastUsedRateId = rateId; } - return isReverse ? fromAmount : toAmount; + return isReverse ? (amount / fromAmount) : (toAmount / amount); } catch(e) { print(e.toString()); return 0.0; diff --git a/lib/exchange/sideshift/sideshift_exchange_provider.dart b/lib/exchange/sideshift/sideshift_exchange_provider.dart index b93f0a80f..912ad89c5 100644 --- a/lib/exchange/sideshift/sideshift_exchange_provider.dart +++ b/lib/exchange/sideshift/sideshift_exchange_provider.dart @@ -79,9 +79,7 @@ class SideShiftExchangeProvider extends ExchangeProvider { if (amount > max) return 0.00; - final estimatedAmount = rate * amount; - - return estimatedAmount; + return rate; } catch (_) { return 0.00; } diff --git a/lib/exchange/simpleswap/simpleswap_exchange_provider.dart b/lib/exchange/simpleswap/simpleswap_exchange_provider.dart index 4c42835ed..0c1027000 100644 --- a/lib/exchange/simpleswap/simpleswap_exchange_provider.dart +++ b/lib/exchange/simpleswap/simpleswap_exchange_provider.dart @@ -60,7 +60,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider { if (response.body == "null") return 0.00; final data = json.decode(response.body) as String; - return double.parse(data); + return double.parse(data) / amount; } catch (_) { return 0.00; } diff --git a/lib/view_model/exchange/exchange_view_model.dart b/lib/view_model/exchange/exchange_view_model.dart index 510e0ac3a..80551304f 100644 --- a/lib/view_model/exchange/exchange_view_model.dart +++ b/lib/view_model/exchange/exchange_view_model.dart @@ -316,7 +316,7 @@ abstract class ExchangeViewModelBase with Store { to: receiveCurrency, amount: amount, isFixedRateMode: isFixedRateMode, - isReceiveAmount: false)) + isReceiveAmount: isFixedRateMode)) ); _sortedAvailableProviders.clear(); @@ -324,7 +324,7 @@ abstract class ExchangeViewModelBase with Store { for (int i=0;i Date: Thu, 8 Dec 2022 01:21:45 +0200 Subject: [PATCH 46/47] - Fix Change now request missing type - Only send either to or from amount depending on fixed rate - take the trade amount from the response --- lib/exchange/changenow/changenow_exchange_provider.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/exchange/changenow/changenow_exchange_provider.dart b/lib/exchange/changenow/changenow_exchange_provider.dart index ca245923f..ee49855e4 100644 --- a/lib/exchange/changenow/changenow_exchange_provider.dart +++ b/lib/exchange/changenow/changenow_exchange_provider.dart @@ -97,15 +97,17 @@ class ChangeNowExchangeProvider extends ExchangeProvider { apiHeaderKey: apiKey, 'Content-Type': 'application/json'}; final flow = getFlow(isFixedRateMode); + final type = isFixedRateMode ? 'reverse' : 'direct'; final body = { 'fromCurrency': normalizeCryptoCurrency(_request.from), 'toCurrency': normalizeCryptoCurrency(_request.to), 'fromNetwork': networkFor(_request.from), 'toNetwork': networkFor(_request.to), - 'fromAmount': _request.fromAmount, - 'toAmount': _request.toAmount, + if (!isFixedRateMode) 'fromAmount': _request.fromAmount, + if (isFixedRateMode) 'toAmount': _request.toAmount, 'address': _request.address, 'flow': flow, + 'type': type, 'refundAddress': _request.refundAddress }; @@ -151,7 +153,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider { refundAddress: refundAddress, extraId: extraId, createdAt: DateTime.now(), - amount: _request.fromAmount, + amount: responseJSON['fromAmount']?.toString() ?? _request.fromAmount, state: TradeState.created); } From 4b1e9a10ebd84daff704f27c88bf4f8a88cafd45 Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Thu, 8 Dec 2022 21:14:42 +0200 Subject: [PATCH 47/47] - Rename calculateAmount to fetchRate to be more descriptive - Add Disable Exchange change reaction to save in shared prefs [skip ci] --- lib/exchange/changenow/changenow_exchange_provider.dart | 4 ++-- lib/exchange/exchange_provider.dart | 2 +- lib/exchange/morphtoken/morphtoken_exchange_provider.dart | 2 +- lib/exchange/sideshift/sideshift_exchange_provider.dart | 2 +- lib/exchange/simpleswap/simpleswap_exchange_provider.dart | 2 +- lib/exchange/xmrto/xmrto_exchange_provider.dart | 2 +- lib/store/settings_store.dart | 5 +++++ lib/view_model/exchange/exchange_view_model.dart | 2 +- 8 files changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/exchange/changenow/changenow_exchange_provider.dart b/lib/exchange/changenow/changenow_exchange_provider.dart index ee49855e4..a9fb7c9ca 100644 --- a/lib/exchange/changenow/changenow_exchange_provider.dart +++ b/lib/exchange/changenow/changenow_exchange_provider.dart @@ -114,7 +114,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider { if (isFixedRateMode) { // since we schedule to calculate the rate every 5 seconds we need to ensure that // we have the latest rate id with the given inputs before creating the trade - await calculateAmount( + await fetchRate( from: _request.from, to: _request.to, amount: double.tryParse(_request.toAmount) ?? 0, @@ -208,7 +208,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider { } @override - Future calculateAmount( + Future fetchRate( {required CryptoCurrency from, required CryptoCurrency to, required double amount, diff --git a/lib/exchange/exchange_provider.dart b/lib/exchange/exchange_provider.dart index 108256015..763350c94 100644 --- a/lib/exchange/exchange_provider.dart +++ b/lib/exchange/exchange_provider.dart @@ -26,7 +26,7 @@ abstract class ExchangeProvider { required TradeRequest request, required bool isFixedRateMode}); Future findTradeById({required String id}); - Future calculateAmount({ + Future fetchRate({ required CryptoCurrency from, required CryptoCurrency to, required double amount, diff --git a/lib/exchange/morphtoken/morphtoken_exchange_provider.dart b/lib/exchange/morphtoken/morphtoken_exchange_provider.dart index 6650d4f3a..a2a72b24f 100644 --- a/lib/exchange/morphtoken/morphtoken_exchange_provider.dart +++ b/lib/exchange/morphtoken/morphtoken_exchange_provider.dart @@ -203,7 +203,7 @@ class MorphTokenExchangeProvider extends ExchangeProvider { } @override - Future calculateAmount( + Future fetchRate( {required CryptoCurrency from, required CryptoCurrency to, required double amount, diff --git a/lib/exchange/sideshift/sideshift_exchange_provider.dart b/lib/exchange/sideshift/sideshift_exchange_provider.dart index 912ad89c5..98f18f058 100644 --- a/lib/exchange/sideshift/sideshift_exchange_provider.dart +++ b/lib/exchange/sideshift/sideshift_exchange_provider.dart @@ -57,7 +57,7 @@ class SideShiftExchangeProvider extends ExchangeProvider { ExchangeProviderDescription.sideShift; @override - Future calculateAmount( + Future fetchRate( {required CryptoCurrency from, required CryptoCurrency to, required double amount, diff --git a/lib/exchange/simpleswap/simpleswap_exchange_provider.dart b/lib/exchange/simpleswap/simpleswap_exchange_provider.dart index 0c1027000..2521c1486 100644 --- a/lib/exchange/simpleswap/simpleswap_exchange_provider.dart +++ b/lib/exchange/simpleswap/simpleswap_exchange_provider.dart @@ -36,7 +36,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider { ExchangeProviderDescription.simpleSwap; @override - Future calculateAmount( + Future fetchRate( {required CryptoCurrency from, required CryptoCurrency to, required double amount, diff --git a/lib/exchange/xmrto/xmrto_exchange_provider.dart b/lib/exchange/xmrto/xmrto_exchange_provider.dart index da367e4d4..536754e18 100644 --- a/lib/exchange/xmrto/xmrto_exchange_provider.dart +++ b/lib/exchange/xmrto/xmrto_exchange_provider.dart @@ -194,7 +194,7 @@ class XMRTOExchangeProvider extends ExchangeProvider { } @override - Future calculateAmount( + Future fetchRate( {required CryptoCurrency from, required CryptoCurrency to, required double amount, diff --git a/lib/store/settings_store.dart b/lib/store/settings_store.dart index 534ea67e9..e1ff316f4 100644 --- a/lib/store/settings_store.dart +++ b/lib/store/settings_store.dart @@ -115,6 +115,11 @@ abstract class SettingsStoreBase with Store { (BalanceDisplayMode mode) => sharedPreferences.setInt( PreferencesKey.currentBalanceDisplayModeKey, mode.serialize())); + reaction( + (_) => disableExchange, + (bool disableExchange) => sharedPreferences.setBool( + PreferencesKey.disableExchangeKey, disableExchange)); + this .nodes .observe((change) { diff --git a/lib/view_model/exchange/exchange_view_model.dart b/lib/view_model/exchange/exchange_view_model.dart index 80551304f..5c1f696b8 100644 --- a/lib/view_model/exchange/exchange_view_model.dart +++ b/lib/view_model/exchange/exchange_view_model.dart @@ -311,7 +311,7 @@ abstract class ExchangeViewModelBase with Store { final result = await Future.wait( _tradeAvailableProviders .where((element) => !isFixedRateMode || element.supportsFixedRate) - .map((element) => element.calculateAmount( + .map((element) => element.fetchRate( from: depositCurrency, to: receiveCurrency, amount: amount,