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) {