fix pow node edits (#3078)
malik1004x committed
Mar 13, 2026 at 23:20 UTC
9a6fd46e041a969b4805ff91f9c1d47b235d1e4f
3 files changed
+112
-128
lib/router.dart
+3
-2
@@ -629,9 +629,10 @@ Route<dynamic> createRoute(RouteSettings settings) {
629
630
case Routes.newPowNode:
631
final args = settings.arguments as Map<String, dynamic>?;
632
+ final page = getIt.get<PowNodeCreateOrEditPage>(
633
+ param1: args?['editingNode'] as Node?, param2: args?['isSelected'] as bool?);
634
return CupertinoPageRoute<void>(
633
- builder: (_) => getIt.get<PowNodeCreateOrEditPage>(
634
- param1: args?['editingNode'] as Node?, param2: args?['isSelected'] as bool?));
635
+ builder: (_) => page);
636
637
case Routes.accountCreation:
638
return CupertinoPageRoute<String>(
lib/src/screens/nodes/pow_node_create_or_edit_page.dart
+105
-123
@@ -1,7 +1,10 @@
1
import 'package:cake_wallet/core/execution_state.dart';
2
+import 'package:cake_wallet/new-ui/widgets/keyboard_hide_overlay.dart';
3
+import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
4
import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart';
5
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
6
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
7
+import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
8
import 'package:cake_wallet/utils/show_pop_up.dart';
9
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
10
import 'package:cw_core/node.dart';
@@ -13,76 +16,30 @@ import 'package:cake_wallet/src/widgets/primary_button.dart';
16
import 'package:cake_wallet/src/screens/base_page.dart';
17
import 'package:cake_wallet/src/widgets/scrollable_with_bottom_section.dart';
18
16
-class PowNodeCreateOrEditPage extends BasePage {
19
+class PowNodeCreateOrEditPage extends StatefulWidget {
20
PowNodeCreateOrEditPage(
21
{required this.nodeCreateOrEditViewModel, this.editingNode, this.isSelected})
19
- : _addressController = TextEditingController(),
20
- _portController = TextEditingController(),
21
- _loginController = TextEditingController(),
22
- _passwordController = TextEditingController() {
23
- reaction((_) => nodeCreateOrEditViewModel.address, (String address) {
24
- if (address != _addressController.text) {
25
- _addressController.text = address;
26
- }
27
- });
28
-
29
- reaction((_) => nodeCreateOrEditViewModel.port, (String port) {
30
- if (port != _portController.text) {
31
- _portController.text = port;
32
- }
33
- });
34
-
35
- if (nodeCreateOrEditViewModel.hasAuthCredentials) {
36
- reaction((_) => nodeCreateOrEditViewModel.login, (String login) {
37
- if (login != _loginController.text) {
38
- _loginController.text = login;
39
- }
40
- });
22
+ ;
23
42
- reaction((_) => nodeCreateOrEditViewModel.password, (String password) {
43
- if (password != _passwordController.text) {
44
- _passwordController.text = password;
45
- }
46
- });
47
- }
24
49
- _addressController
50
- .addListener(() => nodeCreateOrEditViewModel.address = _addressController.text);
51
- _portController.addListener(() => nodeCreateOrEditViewModel.port = _portController.text);
52
- _loginController.addListener(() => nodeCreateOrEditViewModel.login = _loginController.text);
53
- _passwordController
54
- .addListener(() => nodeCreateOrEditViewModel.password = _passwordController.text);
55
- }
56
-
57
- final TextEditingController _addressController;
58
- final TextEditingController _portController;
59
- final TextEditingController _loginController;
60
- final TextEditingController _passwordController;
61
-
62
- @override
63
- String get title => editingNode != null ? S.current.edit_node : S.current.node_new;
25
65
- @override
66
- Widget trailing(BuildContext context) => IconButton(
67
- onPressed: () async {
68
- await nodeCreateOrEditViewModel.scanQRCodeForNewNode(context);
69
- },
70
- splashColor: Colors.transparent,
71
- highlightColor: Colors.transparent,
72
- hoverColor: Colors.transparent,
73
- icon: Image.asset(
74
- 'assets/images/qr_code_icon.png',
75
- ),
76
- );
26
27
final NodeCreateOrEditViewModel nodeCreateOrEditViewModel;
28
final Node? editingNode;
29
final bool? isSelected;
30
+
31
+ @override
32
+ State<PowNodeCreateOrEditPage> createState() => _PowNodeCreateOrEditPageState();
33
+}
34
+
35
+class _PowNodeCreateOrEditPageState extends State<PowNodeCreateOrEditPage> {
36
final _formKey = GlobalKey<NodeFormState>();
37
38
+
39
@override
84
- Widget body(BuildContext context) {
85
- reaction((_) => nodeCreateOrEditViewModel.connectionState, (ExecutionState state) {
40
+ void initState() {
41
+ super.initState();
42
+ reaction((_) => widget.nodeCreateOrEditViewModel.connectionState, (ExecutionState state) {
43
if (state is ExecutedSuccessfullyState) {
44
WidgetsBinding.instance.addPostFrameCallback((_) {
45
showPopUp<void>(
@@ -111,73 +68,98 @@ class PowNodeCreateOrEditPage extends BasePage {
68
});
69
}
70
});
71
+ }
72
115
- return Container(
116
- padding: EdgeInsets.only(left: 24, right: 24),
117
- child: ScrollableWithBottomSection(
118
- contentPadding: EdgeInsets.only(bottom: 24.0, top: 8),
119
- content: NodeForm(
120
- key: _formKey,
121
- nodeViewModel: nodeCreateOrEditViewModel,
122
- ),
123
- bottomSectionPadding: EdgeInsets.only(bottom: 24),
124
- bottomSection: Observer(
125
- builder: (_) => Row(
126
- mainAxisAlignment: MainAxisAlignment.center,
127
- children: <Widget>[
128
- Flexible(
129
- child: Container(
130
- padding: EdgeInsets.only(right: 8.0),
131
- child: LoadingPrimaryButton(
132
- onPressed: () async {
133
- final confirmed = await showPopUp<bool>(
134
- context: context,
135
- builder: (BuildContext context) {
136
- return AlertWithTwoActions(
137
- alertTitle: S.of(context).remove_node,
138
- alertContent: S.of(context).remove_node_message,
139
- rightButtonText: S.of(context).remove,
140
- leftButtonText: S.of(context).cancel,
141
- actionRightButton: () => Navigator.pop(context, true),
142
- actionLeftButton: () => Navigator.pop(context, false));
143
- }) ??
144
- false;
145
-
146
- if (confirmed) {
147
- await editingNode!.delete();
148
- Navigator.of(context).pop();
149
- }
150
- },
151
- text: S.of(context).delete,
152
- isDisabled: !nodeCreateOrEditViewModel.isReady || (isSelected ?? false),
153
- color: Theme.of(context).colorScheme.errorContainer,
154
- textColor: Theme.of(context).colorScheme.onPrimary,
155
- ),
156
- ),
157
- ),
158
- Flexible(
159
- child: Container(
160
- padding: EdgeInsets.only(left: 8.0),
161
- child: PrimaryButton(
162
- onPressed: () async {
163
- if (_formKey.currentState != null &&
164
- !_formKey.currentState!.validate()) {
165
- return;
166
- }
73
+ @override
74
+ Widget build(BuildContext context) {
75
168
- await nodeCreateOrEditViewModel.save(
169
- editingNode: editingNode, saveAsCurrent: isSelected ?? false);
170
- Navigator.of(context).pop();
171
- },
172
- text: S.of(context).save,
173
- color: Theme.of(context).colorScheme.primary,
174
- textColor: Theme.of(context).colorScheme.onPrimary,
175
- isDisabled: (!nodeCreateOrEditViewModel.isReady) ||
176
- (nodeCreateOrEditViewModel.connectionState is IsExecutingState),
177
- ),
178
- )),
179
- ],
76
+ return Container(
77
+ color: Theme.of(context).colorScheme.surface,
78
+ child: KeyboardHideOverlay(
79
+ child: Column(
80
+ children: [
81
+ ModalTopBar(
82
+ title: widget.editingNode != null ? S.current.edit_node : S.current.node_new,
83
+ leadingIcon: Icon(Icons.arrow_back_ios_new),
84
+ onLeadingPressed: Navigator.of(context).pop,
85
+ trailingIcon: CakeImageWidget(imageUrl:
86
+ "assets/new-ui/scan.svg",width:24,height:24,
87
+ colorFilter: ColorFilter.mode(Theme.of(context).colorScheme.primary, BlendMode.srcIn),
88
+ ),
89
+ onTrailingPressed: () => widget.nodeCreateOrEditViewModel.scanQRCodeForNewNode(context),
90
+ ),
91
+ Expanded(
92
+ child: Container(
93
+ padding: EdgeInsets.only(left: 24, right: 24),
94
+ child: ScrollableWithBottomSection(
95
+ contentPadding: EdgeInsets.only(bottom: 24.0, top: 8),
96
+ content: NodeForm(
97
+ key: _formKey,
98
+ nodeViewModel: widget.nodeCreateOrEditViewModel,
99
+ ),
100
+ bottomSectionPadding: EdgeInsets.only(bottom: 24),
101
+ bottomSection: Observer(
102
+ builder: (_) => Row(
103
+ mainAxisAlignment: MainAxisAlignment.center,
104
+ children: <Widget>[
105
+ Flexible(
106
+ child: Container(
107
+ padding: EdgeInsets.only(right: 8.0),
108
+ child: LoadingPrimaryButton(
109
+ onPressed: () async {
110
+ final confirmed = await showPopUp<bool>(
111
+ context: context,
112
+ builder: (BuildContext context) {
113
+ return AlertWithTwoActions(
114
+ alertTitle: S.of(context).remove_node,
115
+ alertContent: S.of(context).remove_node_message,
116
+ rightButtonText: S.of(context).remove,
117
+ leftButtonText: S.of(context).cancel,
118
+ actionRightButton: () => Navigator.pop(context, true),
119
+ actionLeftButton: () => Navigator.pop(context, false));
120
+ }) ??
121
+ false;
122
+
123
+ if (confirmed) {
124
+ await widget.editingNode!.delete();
125
+ Navigator.of(context).pop();
126
+ }
127
+ },
128
+ text: S.of(context).delete,
129
+ isDisabled: !widget.nodeCreateOrEditViewModel.isReady || (widget.isSelected ?? false),
130
+ color: Theme.of(context).colorScheme.errorContainer,
131
+ textColor: Theme.of(context).colorScheme.onPrimary,
132
+ ),
133
+ ),
134
+ ),
135
+ Flexible(
136
+ child: Container(
137
+ padding: EdgeInsets.only(left: 8.0),
138
+ child: PrimaryButton(
139
+ onPressed: () async {
140
+ if (_formKey.currentState != null &&
141
+ !_formKey.currentState!.validate()) {
142
+ return;
143
+ }
144
+
145
+ await widget.nodeCreateOrEditViewModel.save(
146
+ editingNode: widget.editingNode, saveAsCurrent: widget.isSelected ?? false);
147
+ Navigator.of(context).pop();
148
+ },
149
+ text: S.of(context).save,
150
+ color: Theme.of(context).colorScheme.primary,
151
+ textColor: Theme.of(context).colorScheme.onPrimary,
152
+ isDisabled: (!widget.nodeCreateOrEditViewModel.isReady) ||
153
+ (widget.nodeCreateOrEditViewModel.connectionState is IsExecutingState),
154
+ ),
155
+ )),
156
+ ],
157
+ )),
158
)),
181
- ));
159
+ ),
160
+ ],
161
+ ),
162
+ ),
163
+ );
164
}
165
}
lib/src/screens/settings/manage_nodes_page.dart
+4
-3
@@ -15,7 +15,8 @@ import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
15
16
class ManageNodesPage extends BasePage {
17
ManageNodesPage(this.isPow, {this.nodeListViewModel, this.powNodeListViewModel})
18
- : assert((isPow && powNodeListViewModel != null) || (!isPow && nodeListViewModel != null));
18
+ : assert((isPow && powNodeListViewModel != null) || (!isPow && nodeListViewModel != null)),
19
+ assert(powNodeListViewModel == null || nodeListViewModel == null);
20
21
final NodeListViewModel? nodeListViewModel;
22
final PowNodeListViewModel? powNodeListViewModel;
@@ -34,7 +35,7 @@ class ManageNodesPage extends BasePage {
35
button: true,
36
child: NodeHeaderListRow(
37
title: S.of(context).add_new_node,
37
- onTap: (_) async => await Navigator.of(context).pushNamed(Routes.newNode),
38
+ onTap: (_) async => await Navigator.of(context).pushNamed(isPow ? Routes.newPowNode : Routes.newNode),
39
),
40
),
41
if (FeatureFlag.isAutomaticNodeSwitchingEnabled)
@@ -80,7 +81,7 @@ class ManageNodesPage extends BasePage {
81
title: node.uriRaw,
82
node: node,
83
isSelected: isSelected,
83
- isPow: false,
84
+ isPow: isPow,
85
onTap: (_) async {
86
if (isSelected) {
87
return;