Cw 268 contact address validation (#905)
* feat: Proper Bitcoin address validation in exchange screen * fix: use custom validation in addition to RegEx to make sure all address cases are validated - for cases like P2SH addresses starting with a 3, which are not validated by bitcoin_flutter functions * feat: add bitcoin_flutter to root project * refactor: improve conditional isValid return chain * feat: enhance contact page address validation - only shows address box when a currency is selected, to prevent the selected value from being null - changes TextValidator() for the new AddressValidator() * fix: use -1 for initial selectedAtIndex, since there is no currency yet selected
Rafael Saes committed
May 15, 2023 at 09:43 UTC
40f3ccbe42da8de3623b5913ef77f4e308eee5c7
1 file changed
+87
-80
lib/src/screens/contact/contact_page.dart
+87
-80
@@ -1,13 +1,11 @@
1
-import 'package:cake_wallet/core/validator.dart';
1
+import 'package:cake_wallet/core/address_validator.dart';
2
import 'package:cake_wallet/palette.dart';
3
import 'package:cake_wallet/utils/show_pop_up.dart';
4
import 'package:cw_core/currency.dart';
5
import 'package:flutter/material.dart';
6
-import 'package:flutter/cupertino.dart';
6
import 'package:flutter_mobx/flutter_mobx.dart';
7
import 'package:mobx/mobx.dart';
8
import 'package:cake_wallet/generated/i18n.dart';
10
-import 'package:cake_wallet/core/address_validator.dart';
9
import 'package:cake_wallet/core/contact_name_validator.dart';
10
import 'package:cake_wallet/core/execution_state.dart';
11
import 'package:cake_wallet/view_model/contact_list/contact_view_model.dart';
@@ -33,8 +31,8 @@ class ContactPage extends BasePage {
31
_addressController
32
.addListener(() => contactViewModel.address = _addressController.text);
33
36
- autorun((_) =>
37
- _currencyTypeController.text = contactViewModel.currency?.toString()??'');
34
+ autorun((_) => _currencyTypeController.text =
35
+ contactViewModel.currency?.toString() ?? '');
36
}
37
38
@override
@@ -61,96 +59,105 @@ class ContactPage extends BasePage {
59
}
60
});
61
64
- return ScrollableWithBottomSection(
65
- contentPadding: EdgeInsets.all(24),
66
- content: Form(
67
- key: _formKey,
68
- child: Column(
69
- mainAxisSize: MainAxisSize.min,
70
- children: <Widget>[
71
- BaseTextFormField(
72
- controller: _nameController,
73
- hintText: S.of(context).contact_name,
74
- validator: ContactNameValidator()),
75
- Padding(
76
- padding: EdgeInsets.only(top: 20),
77
- child: Container(
78
- child: InkWell(
79
- onTap: () => _presentCurrencyPicker(context),
80
- child: IgnorePointer(
81
- child: BaseTextFormField(
82
- controller: _currencyTypeController,
83
- hintText: S.of(context).settings_currency,
84
- suffixIcon: Row(
85
- mainAxisSize: MainAxisSize.min,
86
- mainAxisAlignment: MainAxisAlignment.end,
87
- children: <Widget>[downArrow],
88
- ),
89
- )),
62
+ return Observer(
63
+ builder: (_) => ScrollableWithBottomSection(
64
+ contentPadding: EdgeInsets.all(24),
65
+ content: Form(
66
+ key: _formKey,
67
+ child: Column(
68
+ mainAxisSize: MainAxisSize.min,
69
+ children: <Widget>[
70
+ BaseTextFormField(
71
+ controller: _nameController,
72
+ hintText: S.of(context).contact_name,
73
+ validator: ContactNameValidator()),
74
+ Padding(
75
+ padding: EdgeInsets.only(top: 20),
76
+ child: Container(
77
+ child: InkWell(
78
+ onTap: () => _presentCurrencyPicker(context),
79
+ child: IgnorePointer(
80
+ child: BaseTextFormField(
81
+ controller: _currencyTypeController,
82
+ hintText: S.of(context).settings_currency,
83
+ suffixIcon: Row(
84
+ mainAxisSize: MainAxisSize.min,
85
+ mainAxisAlignment: MainAxisAlignment.end,
86
+ children: <Widget>[downArrow],
87
+ ),
88
+ )),
89
+ ),
90
),
91
),
92
- ),
93
- Padding(
94
- padding: EdgeInsets.only(top: 20),
95
- child: Observer(
96
- builder: (_) => AddressTextField(
92
+ if (contactViewModel.currency != null)
93
+ Padding(
94
+ padding: EdgeInsets.only(top: 20),
95
+ child: AddressTextField(
96
controller: _addressController,
97
options: [
98
AddressTextFieldOption.paste,
99
AddressTextFieldOption.qrCode,
100
],
102
- buttonColor: Theme.of(context).accentTextTheme!.headline3!.color!,
101
+ buttonColor:
102
+ Theme.of(context).accentTextTheme!.headline3!.color!,
103
iconColor: PaletteDark.gray,
104
- borderColor: Theme.of(context).primaryTextTheme!.headline6!.backgroundColor!,
105
- validator: TextValidator()
106
- // AddressValidator(
107
- // type: contactViewModel.currency),
108
- )),
109
- )
110
- ],
111
- ),
112
- ),
113
- bottomSectionPadding:
114
- EdgeInsets.only(left: 24, right: 24, bottom: 24),
115
- bottomSection: Row(
116
- children: <Widget>[
117
- Expanded(
118
- child: PrimaryButton(
119
- onPressed: () {
120
- contactViewModel.reset();
121
- _nameController.text = '';
122
- _addressController.text = '';
123
- },
124
- text: S.of(context).reset,
125
- color: Colors.orange,
126
- textColor: Colors.white),
104
+ borderColor: Theme.of(context)
105
+ .primaryTextTheme!
106
+ .headline6!
107
+ .backgroundColor!,
108
+ validator:
109
+ AddressValidator(type: contactViewModel.currency!),
110
+ ),
111
+ )
112
+ ],
113
),
128
- SizedBox(width: 20),
129
- Expanded(
130
- child: Observer(
131
- builder: (_) => PrimaryButton(
132
- onPressed: () async {
133
- if (_formKey.currentState != null && !_formKey.currentState!.validate()) {
134
- return;
135
- }
114
+ ),
115
+ bottomSectionPadding:
116
+ EdgeInsets.only(left: 24, right: 24, bottom: 24),
117
+ bottomSection: Row(
118
+ children: <Widget>[
119
+ Expanded(
120
+ child: PrimaryButton(
121
+ onPressed: () {
122
+ contactViewModel.reset();
123
+ _nameController.text = '';
124
+ _addressController.text = '';
125
+ },
126
+ text: S.of(context).reset,
127
+ color: Colors.orange,
128
+ textColor: Colors.white),
129
+ ),
130
+ SizedBox(width: 20),
131
+ Expanded(
132
+ child: Observer(
133
+ builder: (_) => PrimaryButton(
134
+ onPressed: () async {
135
+ if (_formKey.currentState != null &&
136
+ !_formKey.currentState!.validate()) {
137
+ return;
138
+ }
139
137
- await contactViewModel.save();
138
- },
139
- text: S.of(context).save,
140
- color: Theme.of(context).accentTextTheme!.bodyText1!.color!,
141
- textColor: Colors.white,
142
- isDisabled: !contactViewModel.isReady)))
143
- ],
144
- ));
140
+ await contactViewModel.save();
141
+ },
142
+ text: S.of(context).save,
143
+ color: Theme.of(context)
144
+ .accentTextTheme!
145
+ .bodyText1!
146
+ .color!,
147
+ textColor: Colors.white,
148
+ isDisabled: !contactViewModel.isReady)))
149
+ ],
150
+ )),
151
+ );
152
}
153
154
void _presentCurrencyPicker(BuildContext context) {
155
showPopUp<void>(
156
builder: (_) => CurrencyPicker(
150
- selectedAtIndex:
151
- contactViewModel.currency != null
152
- ? contactViewModel.currencies.indexOf(contactViewModel.currency!)
153
- : 0,
157
+ selectedAtIndex: contactViewModel.currency != null
158
+ ? contactViewModel.currencies
159
+ .indexOf(contactViewModel.currency!)
160
+ : -1,
161
items: contactViewModel.currencies,
162
title: S.of(context).please_select,
163
hintText: S.of(context).search_currency,