Separate node form to be more reusable Add node form to privacy settings

Separate node form to be more reusable Add node form to privacy settings

OmarHatem committed Oct 5, 2022 at 19:28 UTC 299df3c087ace7f188d204db8c1623222cbd2f20
6 files changed +191 -187
lib/di.dart
+13 -12
@@ -343,7 +343,7 @@ Future setup(
343 onAuthenticationFinished: onAuthFinished,
344 closable: closable ?? false));
345
346 - getIt.registerFactory(() =>
346 + getIt.registerFactory(() =>
347 BalancePage(dashboardViewModel: getIt.get<DashboardViewModel>(), settingsStore: getIt.get<SettingsStore>()));
348
349 getIt.registerFactory<DashboardPage>(() => DashboardPage( balancePage: getIt.get<BalancePage>(), walletViewModel: getIt.get<DashboardViewModel>(), addressListViewModel: getIt.get<WalletAddressListViewModel>()));
@@ -478,8 +478,9 @@ Future setup(
478
479 getIt.registerFactory(() => NodeListPage(getIt.get<NodeListViewModel>()));
480
481 - getIt.registerFactory(() =>
482 - NodeCreateOrEditViewModel(_nodeSource, getIt.get<AppStore>().wallet));
481 + getIt.registerFactoryParam<NodeCreateOrEditViewModel, WalletType, void>(
482 + (WalletType type, _) =>
483 + NodeCreateOrEditViewModel(_nodeSource, type ?? getIt.get<AppStore>().wallet.type));
484
485 getIt.registerFactory(
486 () => NodeCreateOrEditPage(getIt.get<NodeCreateOrEditViewModel>()));
@@ -672,7 +673,7 @@ Future setup(
673
674 getIt.registerFactoryParam<FullscreenQRPage, String, bool>(
675 (String qrData, bool isLight) => FullscreenQRPage(qrData: qrData, isLight: isLight,));
675 -
676 +
677 getIt.registerFactory(() => IoniaApi());
678
679 getIt.registerFactory(() => AnyPayApi());
@@ -692,7 +693,7 @@ Future setup(
693
694 getIt.registerFactoryParam<IoniaMerchPurchaseViewModel, double, IoniaMerchant>((double amount, merchant) {
695 return IoniaMerchPurchaseViewModel(
695 - ioniaAnyPayService: getIt.get<IoniaAnyPay>(),
696 + ioniaAnyPayService: getIt.get<IoniaAnyPay>(),
697 amount: amount,
698 ioniaMerchant: merchant,
699 );
@@ -734,31 +735,31 @@ Future setup(
735 ioniaService: getIt.get<IoniaService>(),
736 giftCard: giftCard);
737 });
737 -
738 +
739 getIt.registerFactoryParam<IoniaCustomTipViewModel, List, void>((List args, _) {
740 final amount = args[0] as double;
741 final merchant = args[1] as IoniaMerchant;
742 final tip = args[2] as IoniaTip;
742 -
743 +
744 return IoniaCustomTipViewModel(amount: amount, tip: tip, ioniaMerchant: merchant);
745 });
745 -
746 +
747 getIt.registerFactoryParam<IoniaGiftCardDetailPage, IoniaGiftCard, void>((IoniaGiftCard giftCard, _) {
748 return IoniaGiftCardDetailPage(getIt.get<IoniaGiftCardDetailsViewModel>(param1: giftCard));
749 });
750
751 getIt.registerFactoryParam<IoniaMoreOptionsPage, List, void>((List args, _){
752 final giftCard = args.first as IoniaGiftCard;
752 -
753 - return IoniaMoreOptionsPage(giftCard);
753 +
754 + return IoniaMoreOptionsPage(giftCard);
755 });
756
757 getIt.registerFactoryParam<IoniaCustomRedeemViewModel, IoniaGiftCard, void>((IoniaGiftCard giftCard, _) => IoniaCustomRedeemViewModel(giftCard));
758
759 getIt.registerFactoryParam<IoniaCustomRedeemPage, List, void>((List args, _){
760 final giftCard = args.first as IoniaGiftCard;
760 -
761 - return IoniaCustomRedeemPage(getIt.get<IoniaCustomRedeemViewModel>(param1: giftCard) );
761 +
762 + return IoniaCustomRedeemPage(getIt.get<IoniaCustomRedeemViewModel>(param1: giftCard) );
763 });
764
765
lib/router.dart
+3 -1
@@ -20,6 +20,7 @@ import 'package:cake_wallet/src/screens/support/support_page.dart';
20 import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart';
21 import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart';
22 import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
23 +import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
24 import 'package:cake_wallet/view_model/privacy_settings_view_model.dart';
25 import 'package:flutter/cupertino.dart';
26 import 'package:flutter/material.dart';
@@ -476,9 +477,10 @@ Route<dynamic> createRoute(RouteSettings settings) {
477 case Routes.privacySettings:
478 final type = settings.arguments as WalletType;
479 final privacySettingsViewModel = getIt.get<PrivacySettingsViewModel>(param1: type);
480 + final nodeCreateViewModel = getIt.get<NodeCreateOrEditViewModel>(param1: type);
481
482 return CupertinoPageRoute<void>(
481 - builder: (_) => AdvancedPrivacySettingsPage(privacySettingsViewModel));
483 + builder: (_) => AdvancedPrivacySettingsPage(privacySettingsViewModel, nodeCreateViewModel));
484
485 default:
486 return MaterialPageRoute<void>(
lib/src/screens/new_wallet/advanced_privacy_settings_page.dart
+13 -78
@@ -1,49 +1,50 @@
1 -import 'package:cake_wallet/entities/generate_name.dart';
1 +import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart';
2 import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
3 +import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
4 import 'package:cake_wallet/view_model/privacy_settings_view_model.dart';
5 import 'package:flutter_mobx/flutter_mobx.dart';
6 import 'package:flutter/material.dart';
7 import 'package:flutter/cupertino.dart';
8 import 'package:cake_wallet/generated/i18n.dart';
8 -import 'package:cake_wallet/core/wallet_name_validator.dart';
9 import 'package:cake_wallet/src/screens/base_page.dart';
10 import 'package:cake_wallet/src/widgets/primary_button.dart';
11 import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
12
13 class AdvancedPrivacySettingsPage extends BasePage {
14 - AdvancedPrivacySettingsPage(this.privacySettingsViewModel);
14 + AdvancedPrivacySettingsPage(this.privacySettingsViewModel, this.nodeViewModel);
15
16 final PrivacySettingsViewModel privacySettingsViewModel;
17 + final NodeCreateOrEditViewModel nodeViewModel;
18
19 @override
20 String get title => S.current.privacy_settings;
21
22 @override
23 Widget body(BuildContext context) =>
23 - AdvancedPrivacySettingsBody(privacySettingsViewModel);
24 + AdvancedPrivacySettingsBody(privacySettingsViewModel, nodeViewModel);
25 }
26
27 class AdvancedPrivacySettingsBody extends StatefulWidget {
27 - const AdvancedPrivacySettingsBody(this.privacySettingsViewModel, {Key key})
28 + const AdvancedPrivacySettingsBody(this.privacySettingsViewModel, this.nodeViewModel, {Key key})
29 : super(key: key);
30
31 final PrivacySettingsViewModel privacySettingsViewModel;
32 + final NodeCreateOrEditViewModel nodeViewModel;
33
34 @override
35 _AdvancedPrivacySettingsBodyState createState() =>
34 - _AdvancedPrivacySettingsBodyState(privacySettingsViewModel);
36 + _AdvancedPrivacySettingsBodyState(privacySettingsViewModel, nodeViewModel);
37 }
38
39 class _AdvancedPrivacySettingsBodyState
40 extends State<AdvancedPrivacySettingsBody> {
39 - _AdvancedPrivacySettingsBodyState(this.privacySettingsViewModel);
41 + _AdvancedPrivacySettingsBodyState(this.privacySettingsViewModel, this.nodeViewModel);
42
43 final PrivacySettingsViewModel privacySettingsViewModel;
44 + final NodeCreateOrEditViewModel nodeViewModel;
45
46 final _formKey = GlobalKey<FormState>();
47
45 - final TextEditingController _controller = TextEditingController();
46 -
48 @override
49 Widget build(BuildContext context) {
50 return Container(
@@ -67,75 +68,9 @@ class _AdvancedPrivacySettingsBodyState
68 if (privacySettingsViewModel.addCustomNode) {
69 return Padding(
70 padding: EdgeInsets.only(top: 24),
70 - child: Form(
71 - key: _formKey,
72 - child: TextFormField(
73 - onChanged: (value) {},
74 - controller: _controller,
75 - textAlign: TextAlign.center,
76 - style: TextStyle(
77 - fontSize: 20.0,
78 - fontWeight: FontWeight.w600,
79 - color:
80 - Theme.of(context).primaryTextTheme.title.color),
81 - decoration: InputDecoration(
82 - hintStyle: TextStyle(
83 - fontSize: 18.0,
84 - fontWeight: FontWeight.w500,
85 - color: Theme.of(context)
86 - .accentTextTheme
87 - .display3
88 - .color),
89 - hintText: S.of(context).wallet_name,
90 - focusedBorder: UnderlineInputBorder(
91 - borderSide: BorderSide(
92 - color: Theme.of(context)
93 - .accentTextTheme
94 - .display3
95 - .decorationColor,
96 - width: 1.0),
97 - ),
98 - enabledBorder: UnderlineInputBorder(
99 - borderSide: BorderSide(
100 - color: Theme.of(context)
101 - .accentTextTheme
102 - .display3
103 - .decorationColor,
104 - width: 1.0),
105 - ),
106 - suffixIcon: IconButton(
107 - onPressed: () async {
108 - final rName = await generateName();
109 - FocusManager.instance.primaryFocus?.unfocus();
110 -
111 - setState(() {
112 - _controller.text = rName;
113 - _controller.selection =
114 - TextSelection.fromPosition(
115 - TextPosition(offset: _controller.text.length),
116 - );
117 - });
118 - },
119 - icon: Container(
120 - padding: const EdgeInsets.all(8),
121 - decoration: BoxDecoration(
122 - borderRadius: BorderRadius.circular(6.0),
123 - color: Theme.of(context).hintColor,
124 - ),
125 - width: 34,
126 - height: 34,
127 - child: Image.asset(
128 - 'assets/images/refresh_icon.png',
129 - color: Theme.of(context)
130 - .primaryTextTheme
131 - .display1
132 - .decorationColor,
133 - ),
134 - ),
135 - ),
136 - ),
137 - validator: WalletNameValidator(),
138 - ),
71 + child: NodeForm(
72 + formKey: _formKey,
73 + nodeViewModel: nodeViewModel,
74 ),
75 );
76 }
lib/src/screens/nodes/node_create_or_edit_page.dart
+5 -89
@@ -1,16 +1,13 @@
1 import 'package:cake_wallet/core/execution_state.dart';
2 +import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart';
3 import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
3 -import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
4 import 'package:cake_wallet/utils/show_pop_up.dart';
5 import 'package:flutter/material.dart';
6 import 'package:flutter/cupertino.dart';
7 import 'package:flutter_mobx/flutter_mobx.dart';
8 import 'package:mobx/mobx.dart';
9 import 'package:cake_wallet/generated/i18n.dart';
10 -import 'package:cake_wallet/core/node_address_validator.dart';
11 -import 'package:cake_wallet/core/node_port_validator.dart';
10 import 'package:cake_wallet/src/widgets/primary_button.dart';
13 -import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
11 import 'package:cake_wallet/src/screens/base_page.dart';
12 import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
13 import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
@@ -108,91 +105,10 @@ class NodeCreateOrEditPage extends BasePage {
105 padding: EdgeInsets.only(left: 24, right: 24),
106 child: ScrollableWithBottomSection(
107 contentPadding: EdgeInsets.only(bottom: 24.0),
111 - content: Form(
112 - key: _formKey,
113 - child: Column(
114 - children: <Widget>[
115 - Row(
116 - children: <Widget>[
117 - Expanded(
118 - child: BaseTextFormField(
119 - controller: _addressController,
120 - hintText: S.of(context).node_address,
121 - validator: NodeAddressValidator(),
122 - )
123 - )
124 - ],
125 - ),
126 - SizedBox(height: 10.0),
127 - Row(
128 - children: <Widget>[
129 - Expanded(
130 - child: BaseTextFormField(
131 - controller: _portController,
132 - hintText: S.of(context).node_port,
133 - keyboardType: TextInputType.numberWithOptions(
134 - signed: false, decimal: false),
135 - validator: NodePortValidator(),
136 - )
137 - )
138 - ],
139 - ),
140 - SizedBox(height: 10.0),
141 - if (nodeCreateOrEditViewModel.hasAuthCredentials) ...[
142 - Row(
143 - children: <Widget>[
144 - Expanded(
145 - child: BaseTextFormField(
146 - controller: _loginController,
147 - hintText: S.of(context).login,
148 - )
149 - )
150 - ],
151 - ),
152 - SizedBox(height: 10.0),
153 - Row(
154 - children: <Widget>[
155 - Expanded(
156 - child: BaseTextFormField(
157 - controller: _passwordController,
158 - hintText: S.of(context).password,
159 - )
160 - )
161 - ],
162 - ),
163 - Padding(
164 - padding: EdgeInsets.only(top: 20),
165 - child: Row(
166 - mainAxisAlignment: MainAxisAlignment.start,
167 - mainAxisSize: MainAxisSize.max,
168 - children: [
169 - Observer(
170 - builder: (_) => StandardCheckbox(
171 - value: nodeCreateOrEditViewModel.useSSL,
172 - onChanged: (value) =>
173 - nodeCreateOrEditViewModel.useSSL = value,
174 - caption: S.of(context).use_ssl,
175 - ))
176 - ],
177 - )),
178 - Padding(
179 - padding: EdgeInsets.only(top: 20),
180 - child: Row(
181 - mainAxisAlignment: MainAxisAlignment.start,
182 - mainAxisSize: MainAxisSize.max,
183 - children: [
184 - Observer(
185 - builder: (_) => StandardCheckbox(
186 - value: nodeCreateOrEditViewModel.trusted,
187 - onChanged: (value) =>
188 - nodeCreateOrEditViewModel.trusted = value,
189 - caption: S.of(context).trusted,
190 - ))
191 - ],
192 - )),
193 - ]
194 - ],
195 - )),
108 + content: NodeForm(
109 + formKey: _formKey,
110 + nodeViewModel: nodeCreateOrEditViewModel,
111 + ),
112 bottomSectionPadding: EdgeInsets.only(bottom: 24),
113 bottomSection: Observer(
114 builder: (_) => Row(
lib/src/screens/nodes/widgets/node_form.dart new
+151
@@ -0,0 +1,151 @@
1 +import 'package:cake_wallet/core/node_address_validator.dart';
2 +import 'package:cake_wallet/core/node_port_validator.dart';
3 +import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
4 +import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
5 +import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
6 +import 'package:flutter/material.dart';
7 +import 'package:flutter_mobx/flutter_mobx.dart';
8 +import 'package:cake_wallet/generated/i18n.dart';
9 +import 'package:mobx/mobx.dart';
10 +
11 +class NodeForm extends StatelessWidget {
12 + NodeForm({
13 + @required this.nodeViewModel,
14 + @required this.formKey,
15 + }) : _addressController = TextEditingController(),
16 + _portController = TextEditingController(),
17 + _loginController = TextEditingController(),
18 + _passwordController = TextEditingController() {
19 + reaction((_) => nodeViewModel.address, (String address) {
20 + if (address != _addressController.text) {
21 + _addressController.text = address;
22 + }
23 + });
24 +
25 + reaction((_) => nodeViewModel.port, (String port) {
26 + if (port != _portController.text) {
27 + _portController.text = port;
28 + }
29 + });
30 +
31 + if (nodeViewModel.hasAuthCredentials) {
32 + reaction((_) => nodeViewModel.login, (String login) {
33 + if (login != _loginController.text) {
34 + _loginController.text = login;
35 + }
36 + });
37 +
38 + reaction((_) => nodeViewModel.password, (String password) {
39 + if (password != _passwordController.text) {
40 + _passwordController.text = password;
41 + }
42 + });
43 + }
44 +
45 + _addressController
46 + .addListener(() => nodeViewModel.address = _addressController.text);
47 + _portController
48 + .addListener(() => nodeViewModel.port = _portController.text);
49 + _loginController
50 + .addListener(() => nodeViewModel.login = _loginController.text);
51 + _passwordController
52 + .addListener(() => nodeViewModel.password = _passwordController.text);
53 + }
54 +
55 + final NodeCreateOrEditViewModel nodeViewModel;
56 + final GlobalKey<FormState> formKey;
57 +
58 + final TextEditingController _addressController;
59 + final TextEditingController _portController;
60 + final TextEditingController _loginController;
61 + final TextEditingController _passwordController;
62 +
63 + @override
64 + Widget build(BuildContext context) {
65 + return Form(
66 + key: formKey,
67 + child: Column(
68 + children: <Widget>[
69 + Row(
70 + children: <Widget>[
71 + Expanded(
72 + child: BaseTextFormField(
73 + controller: _addressController,
74 + hintText: S.of(context).node_address,
75 + validator: NodeAddressValidator(),
76 + ),
77 + )
78 + ],
79 + ),
80 + SizedBox(height: 10.0),
81 + Row(
82 + children: <Widget>[
83 + Expanded(
84 + child: BaseTextFormField(
85 + controller: _portController,
86 + hintText: S.of(context).node_port,
87 + keyboardType: TextInputType.numberWithOptions(
88 + signed: false, decimal: false),
89 + validator: NodePortValidator(),
90 + ))
91 + ],
92 + ),
93 + SizedBox(height: 10.0),
94 + if (nodeViewModel.hasAuthCredentials) ...[
95 + Row(
96 + children: <Widget>[
97 + Expanded(
98 + child: BaseTextFormField(
99 + controller: _loginController,
100 + hintText: S.of(context).login,
101 + ))
102 + ],
103 + ),
104 + SizedBox(height: 10.0),
105 + Row(
106 + children: <Widget>[
107 + Expanded(
108 + child: BaseTextFormField(
109 + controller: _passwordController,
110 + hintText: S.of(context).password,
111 + ))
112 + ],
113 + ),
114 + Padding(
115 + padding: EdgeInsets.only(top: 20),
116 + child: Row(
117 + mainAxisAlignment: MainAxisAlignment.start,
118 + mainAxisSize: MainAxisSize.max,
119 + children: [
120 + Observer(
121 + builder: (_) => StandardCheckbox(
122 + value: nodeViewModel.useSSL,
123 + onChanged: (value) => nodeViewModel.useSSL = value,
124 + caption: S.of(context).use_ssl,
125 + ),
126 + )
127 + ],
128 + ),
129 + ),
130 + Padding(
131 + padding: EdgeInsets.only(top: 20),
132 + child: Row(
133 + mainAxisAlignment: MainAxisAlignment.start,
134 + mainAxisSize: MainAxisSize.max,
135 + children: [
136 + Observer(
137 + builder: (_) => StandardCheckbox(
138 + value: nodeViewModel.trusted,
139 + onChanged: (value) => nodeViewModel.trusted = value,
140 + caption: S.of(context).trusted,
141 + ),
142 + ),
143 + ],
144 + ),
145 + ),
146 + ]
147 + ],
148 + ),
149 + );
150 + }
151 +}
lib/view_model/node_list/node_create_or_edit_view_model.dart
+6 -7
@@ -1,7 +1,6 @@
1 import 'package:cake_wallet/core/execution_state.dart';
2 import 'package:hive/hive.dart';
3 import 'package:mobx/mobx.dart';
4 -import 'package:cw_core/wallet_base.dart';
4 import 'package:cw_core/node.dart';
5 import 'package:cw_core/wallet_type.dart';
6
@@ -11,7 +10,7 @@ class NodeCreateOrEditViewModel = NodeCreateOrEditViewModelBase
10 with _$NodeCreateOrEditViewModel;
11
12 abstract class NodeCreateOrEditViewModelBase with Store {
14 - NodeCreateOrEditViewModelBase(this._nodeSource, this._wallet)
13 + NodeCreateOrEditViewModelBase(this._nodeSource, this._walletType)
14 : state = InitialExecutionState(),
15 connectionState = InitialExecutionState(),
16 useSSL = false,
@@ -45,8 +44,8 @@ abstract class NodeCreateOrEditViewModelBase with Store {
44 bool get isReady =>
45 (address?.isNotEmpty ?? false) && (port?.isNotEmpty ?? false);
46
48 - bool get hasAuthCredentials => _wallet.type == WalletType.monero ||
49 - _wallet.type == WalletType.haven;
47 + bool get hasAuthCredentials => _walletType == WalletType.monero ||
48 + _walletType == WalletType.haven;
49
50 String get uri {
51 var uri = address;
@@ -58,7 +57,7 @@ abstract class NodeCreateOrEditViewModelBase with Store {
57 return uri;
58 }
59
61 - final WalletBase _wallet;
60 + final WalletType _walletType;
61 final Box<Node> _nodeSource;
62
63 @action
@@ -76,7 +75,7 @@ abstract class NodeCreateOrEditViewModelBase with Store {
75 try {
76 state = IsExecutingState();
77 final node =
79 - Node(uri: uri, type: _wallet.type, login: login, password: password,
78 + Node(uri: uri, type: _walletType, login: login, password: password,
79 useSSL: useSSL, trusted: trusted);
80 await _nodeSource.add(node);
81 state = ExecutedSuccessfullyState();
@@ -90,7 +89,7 @@ abstract class NodeCreateOrEditViewModelBase with Store {
89 try {
90 connectionState = IsExecutingState();
91 final node =
93 - Node(uri: uri, type: _wallet.type, login: login, password: password);
92 + Node(uri: uri, type: _walletType, login: login, password: password);
93 final isAlive = await node.requestNode();
94 connectionState = ExecutedSuccessfullyState(payload: isAlive);
95 } catch (e) {