TMP
M committed
Oct 9, 2020 at 21:34 UTC
f9cc21478adc3706a62dc3011156f28606139bad
16 files changed
+793
-300
cw_monero/ios/Classes/monero_api.cpp
+9
-4
@@ -219,6 +219,8 @@ extern "C"
219
220
bool create_wallet(char *path, char *password, char *language, int32_t networkType, char *error)
221
{
222
+ Monero::WalletManagerFactory::setLogLevel(4);
223
+
224
Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
225
Monero::WalletManager *walletManager = Monero::WalletManagerFactory::getWalletManager();
226
Monero::Wallet *wallet = walletManager->createWallet(path, password, language, _networkType);
@@ -228,9 +230,9 @@ extern "C"
230
231
wallet->statusWithErrorString(status, errorString);
232
231
- if (status != Monero::Wallet::Status_Ok)
233
+ if (wallet->status() != Monero::Wallet::Status_Ok)
234
{
233
- error = strdup(errorString.c_str());
235
+ error = strdup(wallet->errorString().c_str());
236
return false;
237
}
238
@@ -254,7 +256,7 @@ extern "C"
256
257
wallet->statusWithErrorString(status, errorString);
258
257
- if (status != Monero::Wallet::Status_Ok)
259
+ if (status != Monero::Wallet::Status_Ok || !errorString.empty())
260
{
261
error = strdup(errorString.c_str());
262
return false;
@@ -282,7 +284,7 @@ extern "C"
284
285
wallet->statusWithErrorString(status, errorString);
286
285
- if (status != Monero::Wallet::Status_Ok)
287
+ if (status != Monero::Wallet::Status_Ok || !errorString.empty())
288
{
289
error = strdup(errorString.c_str());
290
return false;
@@ -349,11 +351,13 @@ extern "C"
351
352
uint64_t get_full_balance(uint32_t account_index)
353
{
354
+// return 0;
355
return get_current_wallet()->balance(account_index);
356
}
357
358
uint64_t get_unlocked_balance(uint32_t account_index)
359
{
360
+// return 0;
361
return get_current_wallet()->unlockedBalance(account_index);
362
}
363
@@ -681,6 +685,7 @@ extern "C"
685
void on_startup()
686
{
687
Monero::Utils::onStartup();
688
+ Monero::WalletManagerFactory::setLogLevel(4);
689
}
690
691
void rescan_blockchain()
cw_monero/lib/exceptions/wallet_creation_exception.dart
+3
@@ -2,4 +2,7 @@ class WalletCreationException implements Exception {
2
WalletCreationException({this.message});
3
4
final String message;
5
+
6
+ @override
7
+ String toString() => message;
8
}
\ No newline at end of file
cw_monero/lib/wallet_manager.dart
+3
@@ -1,4 +1,5 @@
1
import 'dart:ffi';
2
+import 'package:cw_monero/wallet.dart';
3
import 'package:ffi/ffi.dart';
4
import 'package:flutter/foundation.dart';
5
import 'package:cw_monero/convert_utf8_to_string.dart';
@@ -49,6 +50,8 @@ void createWalletSync(
50
throw WalletCreationException(
51
message: convertUTF8ToString(pointer: errorMessagePointer));
52
}
53
+
54
+ // setupNodeSync(address: "node.moneroworld.com:18089");
55
}
56
57
bool isWalletExistSync({String path}) {
ios/Runner.xcodeproj/project.pbxproj
+3
-3
@@ -354,7 +354,7 @@
354
buildSettings = {
355
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
356
CLANG_ENABLE_MODULES = YES;
357
- CURRENT_PROJECT_VERSION = 4;
357
+ CURRENT_PROJECT_VERSION = 5;
358
DEVELOPMENT_TEAM = 32J6BB6VUS;
359
ENABLE_BITCODE = NO;
360
FRAMEWORK_SEARCH_PATHS = (
@@ -493,7 +493,7 @@
493
buildSettings = {
494
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
495
CLANG_ENABLE_MODULES = YES;
496
- CURRENT_PROJECT_VERSION = 4;
496
+ CURRENT_PROJECT_VERSION = 5;
497
DEVELOPMENT_TEAM = 32J6BB6VUS;
498
ENABLE_BITCODE = NO;
499
FRAMEWORK_SEARCH_PATHS = (
@@ -526,7 +526,7 @@
526
buildSettings = {
527
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
528
CLANG_ENABLE_MODULES = YES;
529
- CURRENT_PROJECT_VERSION = 4;
529
+ CURRENT_PROJECT_VERSION = 5;
530
DEVELOPMENT_TEAM = 32J6BB6VUS;
531
ENABLE_BITCODE = NO;
532
FRAMEWORK_SEARCH_PATHS = (
lib/entities/fs_migration.dart
+5
@@ -137,6 +137,11 @@ Future<void> ios_migrate_wallet_passwords() async {
137
final walletsDir = Directory('${appDocDir.path}/wallets');
138
final moneroWalletsDir = Directory('${walletsDir.path}/monero');
139
140
+ if (!moneroWalletsDir.existsSync() || moneroWalletsDir.listSync().isEmpty) {
141
+ await prefs.setBool('ios_migration_wallet_passwords_completed', true);
142
+ return;
143
+ }
144
+
145
moneroWalletsDir.listSync().forEach((item) async {
146
try {
147
if (item is Directory) {
lib/main.dart
+1
-1
@@ -95,7 +95,7 @@ Future<void> initialSetup(
95
tradesSource: tradesSource,
96
templates: templates,
97
exchangeTemplates: exchangeTemplates);
98
- await bootstrap(navigatorKey);
98
+ bootstrap(navigatorKey);
99
monero_wallet.onStartup();
100
}
101
lib/monero/monero_wallet_service.dart
+1
-1
@@ -67,7 +67,7 @@ class MoneroWalletService extends WalletService<
67
return wallet;
68
} catch (e) {
69
// TODO: Implement Exception for wallet list service.
70
- print('MoneroWalletsManager Error: $e');
70
+ print('MoneroWalletsManager Error: ${e.toString()}');
71
rethrow;
72
}
73
}
lib/reactions/on_authentication_state_change.dart
+4
-1
@@ -8,22 +8,25 @@ import 'package:cake_wallet/store/authentication_store.dart';
8
ReactionDisposer _onAuthenticationStateChange;
9
10
void startAuthenticationStateChange(AuthenticationStore authenticationStore,
11
- GlobalKey<NavigatorState> navigatorKey) {
11
+ @required GlobalKey<NavigatorState> navigatorKey) {
12
_onAuthenticationStateChange ??= autorun((_) async {
13
final state = authenticationStore.state;
14
15
if (state == AuthenticationState.installed) {
16
await loadCurrentWallet();
17
+ return;
18
}
19
20
if (state == AuthenticationState.allowed) {
21
await navigatorKey.currentState
22
.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false);
23
+ return;
24
}
25
26
if (state == AuthenticationState.denied) {
27
await navigatorKey.currentState
28
.pushNamedAndRemoveUntil(Routes.welcome, (_) => false);
29
+ return;
30
}
31
});
32
}
lib/router.dart
+8
-8
@@ -58,7 +58,7 @@ class Router {
58
return CupertinoPageRoute<void>(
59
builder: (_) => getIt.get<SetupPinCodePage>(
60
param1: (BuildContext context, dynamic _) =>
61
- Navigator.pushNamed(context, Routes.newWalletType)),
61
+ Navigator.pushNamed(context, Routes.newWallet)),
62
fullscreenDialog: true);
63
64
case Routes.newWalletType:
@@ -128,7 +128,7 @@ class Router {
128
return CupertinoPageRoute<void>(
129
builder: (_) => getIt.get<SetupPinCodePage>(
130
param1: (BuildContext context, dynamic _) =>
131
- Navigator.pushNamed(context, Routes.restoreWalletType)),
131
+ Navigator.pushNamed(context, Routes.restoreWalletFromSeed)),
132
fullscreenDialog: true);
133
134
case Routes.seed:
@@ -137,15 +137,15 @@ class Router {
137
getIt.get<WalletSeedPage>(param1: settings.arguments as bool));
138
139
case Routes.restoreWalletFromSeed:
140
- final args = settings.arguments as List<dynamic>;
141
- final type = args.first as WalletType;
142
- final language = type == WalletType.monero
143
- ? args[1] as String
144
- : LanguageList.english;
140
+ // final args = settings.arguments as List<dynamic>;
141
+ final type = WalletType.monero; //args.first as WalletType;
142
+ // final language = type == WalletType.monero
143
+ // ? args[1] as String
144
+ // : LanguageList.english;
145
146
return CupertinoPageRoute<void>(
147
builder: (_) =>
148
- RestoreWalletFromSeedPage(type: type, language: language));
148
+ RestoreWalletFromSeedPage(type: type));
149
150
case Routes.restoreWalletFromKeys:
151
final args = settings.arguments as List<dynamic>;
lib/src/screens/restore/restore_from_keys.dart
new
+83
@@ -0,0 +1,83 @@
1
+import 'package:flutter/services.dart';
2
+import 'package:flutter/cupertino.dart';
3
+import 'package:flutter/material.dart';
4
+import 'package:cake_wallet/generated/i18n.dart';
5
+import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
6
+import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
7
+
8
+class RestoreFromKeysFrom extends StatefulWidget {
9
+ @override
10
+ _RestoreFromKeysFromState createState() => _RestoreFromKeysFromState();
11
+}
12
+
13
+class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
14
+ final _formKey = GlobalKey<FormState>();
15
+ final _blockchainHeightKey = GlobalKey<BlockchainHeightState>();
16
+ final _nameController = TextEditingController();
17
+ final _addressController = TextEditingController();
18
+ final _viewKeyController = TextEditingController();
19
+ final _spendKeyController = TextEditingController();
20
+ final _wifController = TextEditingController();
21
+
22
+ @override
23
+ void initState() {
24
+ // _nameController.addListener(() =>
25
+ // widget.walletRestorationFromKeysVM.name = _nameController.text);
26
+ // _addressController.addListener(() =>
27
+ // widget.walletRestorationFromKeysVM.address = _addressController.text);
28
+ // _viewKeyController.addListener(() =>
29
+ // widget.walletRestorationFromKeysVM.viewKey = _viewKeyController.text);
30
+ // _spendKeyController.addListener(() =>
31
+ // widget.walletRestorationFromKeysVM.spendKey = _spendKeyController.text);
32
+ // _wifController.addListener(() =>
33
+ // widget.walletRestorationFromKeysVM.wif = _wifController.text);
34
+
35
+ super.initState();
36
+ }
37
+
38
+ @override
39
+ void dispose() {
40
+ _nameController.dispose();
41
+ _addressController.dispose();
42
+ _viewKeyController.dispose();
43
+ _spendKeyController.dispose();
44
+ _wifController.dispose();
45
+ super.dispose();
46
+ }
47
+
48
+ @override
49
+ Widget build(BuildContext context) {
50
+ return Container(
51
+ padding: EdgeInsets.only(left: 24, right: 24),
52
+ child: Form(
53
+ key: _formKey,
54
+ child: Column(children: <Widget>[
55
+ BaseTextFormField(
56
+ controller: _addressController,
57
+ keyboardType: TextInputType.multiline,
58
+ maxLines: null,
59
+ hintText: S.of(context).restore_address,
60
+ ),
61
+ Container(
62
+ padding: EdgeInsets.only(top: 20.0),
63
+ child: BaseTextFormField(
64
+ controller: _viewKeyController,
65
+ hintText: S.of(context).restore_view_key_private,
66
+ )),
67
+ Container(
68
+ padding: EdgeInsets.only(top: 20.0),
69
+ child: BaseTextFormField(
70
+ controller: _spendKeyController,
71
+ hintText: S.of(context).restore_spend_key_private,
72
+ )),
73
+ BlockchainHeightWidget(
74
+ key: _blockchainHeightKey,
75
+ onHeightChange: (height) {
76
+ // widget.walletRestorationFromKeysVM.height = height;
77
+ print(height);
78
+ }),
79
+ ]),
80
+ ),
81
+ );
82
+ }
83
+}
lib/src/screens/restore/restore_wallet_from_seed_page.dart
+179
-38
@@ -1,3 +1,11 @@
1
+import 'package:cake_wallet/src/screens/restore/restore_from_keys.dart';
2
+import 'package:cake_wallet/src/screens/seed_language/widgets/seed_language_picker.dart';
3
+import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
4
+import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
5
+import 'package:cake_wallet/src/widgets/primary_button.dart';
6
+import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
7
+import 'package:cake_wallet/utils/show_pop_up.dart';
8
+import 'package:flutter/cupertino.dart';
9
import 'package:flutter/material.dart';
10
import 'package:flutter/services.dart';
11
import 'package:cake_wallet/routes.dart';
@@ -7,48 +15,162 @@ import 'package:cake_wallet/src/widgets/seed_widget.dart';
15
import 'package:cake_wallet/entities/wallet_type.dart';
16
import 'package:cake_wallet/core/seed_validator.dart';
17
import 'package:cake_wallet/core/mnemonic_length.dart';
18
+import 'package:smooth_page_indicator/smooth_page_indicator.dart';
19
20
class RestoreWalletFromSeedPage extends BasePage {
12
- RestoreWalletFromSeedPage({@required this.type, @required this.language});
21
+ RestoreWalletFromSeedPage({@required this.type});
22
23
final WalletType type;
15
- final String language;
16
- final formKey = GlobalKey<_RestoreFromSeedFormState>();
24
+ final String language = 'en';
25
+
26
+ // final formKey = GlobalKey<_RestoreFromSeedFormState>();
27
+ // final formKey = GlobalKey<_RestoreFromSeedFormState>();
28
29
@override
30
String get title => S.current.restore_title_from_seed;
31
21
- @override
22
- Color get titleColor => Colors.white;
32
+ final controller = PageController(initialPage: 0);
33
24
- @override
25
- Color get backgroundLightColor => Colors.transparent;
34
+ Widget _page(BuildContext context, int index) {
35
+ if (_pages == null || _pages.isEmpty) {
36
+ _setPages(context);
37
+ }
38
27
- @override
28
- Color get backgroundDarkColor => Colors.transparent;
39
+ return _pages[index];
40
+ }
41
30
- @override
31
- bool get resizeToAvoidBottomPadding => false;
42
+ int _pageLength(BuildContext context) {
43
+ if (_pages == null || _pages.isEmpty) {
44
+ _setPages(context);
45
+ }
46
33
- @override
34
- Widget body(BuildContext context) =>
35
- RestoreFromSeedForm(key: formKey, type: type, language: language,
36
- leading: leading(context), middle: middle(context));
47
+ return _pages.length;
48
+ }
49
+
50
+ void _setPages(BuildContext context) {
51
+ _pages = <Widget>[
52
+ Container(
53
+ padding: EdgeInsets.only(left: 25, right: 25),
54
+ child: Column(children: [
55
+ SeedWidget(
56
+ maxLength: mnemonicLength(WalletType.monero),
57
+ onMnemonicChange: (seed) => null,
58
+ onFinish: () => null,
59
+ // Navigator.of(context).pushNamed(
60
+ // Routes.restoreWalletFromSeedDetails,
61
+ // arguments: [WalletType.monero, '', '']),
62
+ validator: SeedValidator(type: WalletType.monero, language: ''),
63
+ ),
64
+ GestureDetector(
65
+ onTap: () async {
66
+ final selected = await showPopUp<String>(
67
+ context: context,
68
+ builder: (BuildContext context) =>
69
+ SeedLanguagePicker(selected: 'English')); //key: _pickerKey
70
+ print('Seletec $selected');
71
+ },
72
+ child: Container(
73
+ color: Colors.transparent,
74
+ padding: EdgeInsets.only(top: 20.0),
75
+ child: IgnorePointer(child: BaseTextFormField(
76
+ enableInteractiveSelection: false,
77
+ readOnly: true,
78
+ hintText: 'Language',
79
+ initialValue: 'English (Seed language)')))),
80
+ BlockchainHeightWidget(
81
+ // key: _blockchainHeightKey,
82
+ onHeightChange: (height) {
83
+ // widget.walletRestorationFromKeysVM.height = height;
84
+ print(height);
85
+ })
86
+ ])),
87
+ RestoreFromKeysFrom(),
88
+ // Container(color: Colors.yellow)
89
+ ];
90
+ }
91
+
92
+ List<Widget> _pages;
93
94
@override
39
- Widget build(BuildContext context) {
40
- return Scaffold(
41
- resizeToAvoidBottomPadding: resizeToAvoidBottomPadding,
42
- body: Container(
43
- color: Theme.of(context).backgroundColor,
44
- child: body(context)
45
- )
46
- );
95
+ Widget body(BuildContext context) {
96
+ return Column(mainAxisAlignment: MainAxisAlignment.center, children: [
97
+ Expanded(
98
+ child: PageView.builder(
99
+ onPageChanged: (page) {
100
+ print('Page index $page');
101
+ },
102
+ controller: controller,
103
+ itemCount: _pageLength(context),
104
+ itemBuilder: (context, index) => _page(context, index))),
105
+ Padding(
106
+ padding: EdgeInsets.only(top: 10),
107
+ child: SmoothPageIndicator(
108
+ controller: controller,
109
+ count: _pageLength(context),
110
+ effect: ColorTransitionEffect(
111
+ spacing: 6.0,
112
+ radius: 6.0,
113
+ dotWidth: 6.0,
114
+ dotHeight: 6.0,
115
+ dotColor: Theme.of(context).hintColor.withOpacity(0.5),
116
+ activeDotColor: Theme.of(context).hintColor),
117
+ )),
118
+ Padding(
119
+ padding: EdgeInsets.only(top: 20, bottom: 40, left: 25, right: 25),
120
+ child: PrimaryButton(
121
+ text: S.of(context).restore_recover,
122
+ isDisabled: false,
123
+ onPressed: () => null,
124
+ color: Theme.of(context).accentTextTheme.body2.color,
125
+ textColor: Colors.white)),
126
+ ]);
127
+
128
+ // return GestureDetector(
129
+ // onTap: () =>
130
+ // SystemChannels.textInput.invokeMethod<void>('TextInput.hide'),
131
+ // child: ScrollableWithBottomSection(
132
+ // bottomSection: Column(children: [
133
+ // GestureDetector(
134
+ // onTap: () {},
135
+ // child: Text('Switch to restore from keys',
136
+ // style: TextStyle(fontSize: 15, color: Theme.of(context).hintColor))),
137
+ // SizedBox(height: 30),
138
+ // PrimaryButton(
139
+ // text: S.of(context).restore_next,
140
+ // isDisabled: false,
141
+ // onPressed: () => null,
142
+ // color: Theme.of(context).accentTextTheme.body2.color,
143
+ // textColor: Colors.white)
144
+ // ]),
145
+ // contentPadding: EdgeInsets.only(bottom: 24),
146
+ // content: Container(
147
+ // padding: EdgeInsets.only(left: 25, right: 25),
148
+ // child: Column(children: [
149
+ // SeedWidget(
150
+ // maxLength: mnemonicLength(type),
151
+ // onMnemonicChange: (seed) => null,
152
+ // onFinish: () => Navigator.of(context).pushNamed(
153
+ // Routes.restoreWalletFromSeedDetails,
154
+ // arguments: [type, language, '']),
155
+ // validator: SeedValidator(type: type, language: language),
156
+ // ),
157
+ // // SizedBox(height: 15),
158
+ // // BaseTextFormField(hintText: 'Language', initialValue: 'English'),
159
+ // BlockchainHeightWidget(
160
+ // // key: _blockchainHeightKey,
161
+ // onHeightChange: (height) {
162
+ // // widget.walletRestorationFromKeysVM.height = height;
163
+ // print(height);
164
+ // })
165
+ // ]))),
166
+ // );
167
}
168
}
169
170
class RestoreFromSeedForm extends StatefulWidget {
51
- RestoreFromSeedForm({Key key, this.type, this.language, this.leading, this.middle}) : super(key: key);
171
+ RestoreFromSeedForm(
172
+ {Key key, this.type, this.language, this.leading, this.middle})
173
+ : super(key: key);
174
final WalletType type;
175
final String language;
176
final Widget leading;
@@ -59,27 +181,46 @@ class RestoreFromSeedForm extends StatefulWidget {
181
}
182
183
class _RestoreFromSeedFormState extends State<RestoreFromSeedForm> {
62
- final _seedKey = GlobalKey<SeedWidgetState>();
184
+ // final _seedKey = GlobalKey<SeedWidgetState>();
185
64
- String mnemonic() => _seedKey.currentState.items.map((e) => e.text).join(' ');
186
+ String mnemonic() =>
187
+ ''; // _seedKey.currentState.items.map((e) => e.text).join(' ');
188
189
@override
190
Widget build(BuildContext context) {
191
return GestureDetector(
192
onTap: () =>
193
SystemChannels.textInput.invokeMethod<void>('TextInput.hide'),
71
- child: SeedWidget(
72
- key: _seedKey,
73
- maxLength: mnemonicLength(widget.type),
74
- onMnemonicChange: (seed) => null,
75
- onFinish: () => Navigator.of(context).pushNamed(
76
- Routes.restoreWalletFromSeedDetails,
77
- arguments: [widget.type, widget.language, mnemonic()]),
78
- leading: widget.leading,
79
- middle: widget.middle,
80
- validator:
81
- SeedValidator(type: widget.type, language: widget.language),
82
- ),
194
+ child: Container(
195
+ padding: EdgeInsets.only(left: 25, right: 25),
196
+ // color: Colors.blue,
197
+ // height: 300,
198
+ child: Column(children: [
199
+ SeedWidget(
200
+ // key: _seedKey,
201
+ maxLength: mnemonicLength(widget.type),
202
+ onMnemonicChange: (seed) => null,
203
+ onFinish: () => Navigator.of(context).pushNamed(
204
+ Routes.restoreWalletFromSeedDetails,
205
+ arguments: [widget.type, widget.language, mnemonic()]),
206
+ leading: widget.leading,
207
+ middle: widget.middle,
208
+ validator:
209
+ SeedValidator(type: widget.type, language: widget.language),
210
+ ),
211
+ BlockchainHeightWidget(
212
+ // key: _blockchainHeightKey,
213
+ onHeightChange: (height) {
214
+ // widget.walletRestorationFromKeysVM.height = height;
215
+ print(height);
216
+ }),
217
+ Container(
218
+ color: Colors.green,
219
+ width: 100,
220
+ height: 56,
221
+ child: BaseTextFormField(
222
+ hintText: 'Language', initialValue: 'English')),
223
+ ])),
224
);
225
}
226
}
lib/src/screens/seed_language/seed_language_page.dart
+6
-4
@@ -35,13 +35,15 @@ class SeedLanguageFormState extends State<SeedLanguageForm> {
35
static const aspectRatioImage = 1.22;
36
37
final walletNameImage = Image.asset('assets/images/wallet_name.png');
38
- final walletNameLightImage = Image.asset('assets/images/wallet_name_light.png');
38
+ final walletNameLightImage =
39
+ Image.asset('assets/images/wallet_name_light.png');
40
final _languageSelectorKey = GlobalKey<SeedLanguageSelectorState>();
41
42
@override
43
Widget build(BuildContext context) {
44
final walletImage = getIt.get<SettingsStore>().isDarkTheme
44
- ? walletNameImage : walletNameLightImage;
45
+ ? walletNameImage
46
+ : walletNameLightImage;
47
48
return Container(
49
padding: EdgeInsets.only(top: 24),
@@ -78,8 +80,8 @@ class SeedLanguageFormState extends State<SeedLanguageForm> {
80
bottomSection: Observer(
81
builder: (context) {
82
return PrimaryButton(
81
- onPressed: () => widget
82
- .onConfirm(context, _languageSelectorKey.currentState.selected),
83
+ onPressed: () => widget.onConfirm(
84
+ context, _languageSelectorKey.currentState.selected),
85
text: S.of(context).seed_language_next,
86
color: Colors.green,
87
textColor: Colors.white);
lib/src/screens/wallet_list/wallet_list_page.dart
+1
-1
@@ -175,7 +175,7 @@ class WalletListBodyState extends State<WalletListBody> {
175
SizedBox(height: 10.0),
176
PrimaryImageButton(
177
onPressed: () =>
178
- Navigator.of(context).pushNamed(Routes.restoreWalletType),
178
+ Navigator.of(context).pushNamed(Routes.restoreWalletFromSeed),
179
image: restoreWalletImage,
180
text: S.of(context).wallet_list_restore_wallet,
181
color: Theme.of(context).accentTextTheme.caption.color,
lib/src/screens/welcome/welcome_page.dart
+2
-2
@@ -103,7 +103,7 @@ class WelcomePage extends BasePage {
103
Padding(
104
padding: EdgeInsets.only(top: 24),
105
child: PrimaryImageButton(
106
- onPressed: () => Navigator.pushNamed(context, Routes.newWallet),
106
+ onPressed: () => Navigator.pushNamed(context, Routes.newWalletFromWelcome),
107
image: newWalletImage,
108
text: S.of(context).create_new,
109
color: Theme.of(context).accentTextTheme.subtitle.decorationColor,
@@ -113,7 +113,7 @@ class WelcomePage extends BasePage {
113
Padding(
114
padding: EdgeInsets.only(top: 10),
115
child: PrimaryImageButton(
116
- onPressed: () => Navigator.pushNamed(context, Routes.restoreWalletOptions),
116
+ onPressed: () => Navigator.pushNamed(context, Routes.restoreWalletOptionsFromWelcome),
117
image: restoreWalletImage,
118
text: S.of(context).restore_wallet,
119
color: Theme.of(context).accentTextTheme.caption.color,
lib/src/widgets/base_text_form_field.dart
+21
-7
@@ -19,11 +19,14 @@ class BaseTextFormField extends StatelessWidget {
19
this.suffix,
20
this.suffixIcon,
21
this.enabled = true,
22
+ this.readOnly = false,
23
+ this.enableInteractiveSelection = true,
24
this.validator,
25
this.textStyle,
26
this.placeholderTextStyle,
27
this.maxLength,
26
- this.focusNode});
28
+ this.focusNode,
29
+ this.initialValue});
30
31
final TextEditingController controller;
32
final TextInputType keyboardType;
@@ -46,10 +49,16 @@ class BaseTextFormField extends StatelessWidget {
49
final TextStyle textStyle;
50
final int maxLength;
51
final FocusNode focusNode;
52
+ final bool readOnly;
53
+ final bool enableInteractiveSelection;
54
+ String initialValue;
55
56
@override
57
Widget build(BuildContext context) {
58
return TextFormField(
59
+ enableInteractiveSelection: enableInteractiveSelection,
60
+ readOnly: readOnly,
61
+ initialValue: initialValue,
62
focusNode: focusNode,
63
controller: controller,
64
keyboardType: keyboardType,
@@ -60,9 +69,11 @@ class BaseTextFormField extends StatelessWidget {
69
inputFormatters: inputFormatters,
70
enabled: enabled,
71
maxLength: maxLength,
63
- style: textStyle ?? TextStyle(
64
- fontSize: 16.0,
65
- color: textColor ?? Theme.of(context).primaryTextTheme.title.color),
72
+ style: textStyle ??
73
+ TextStyle(
74
+ fontSize: 16.0,
75
+ color:
76
+ textColor ?? Theme.of(context).primaryTextTheme.title.color),
77
decoration: InputDecoration(
78
prefix: prefix,
79
prefixIcon: prefixIcon,
@@ -75,15 +86,18 @@ class BaseTextFormField extends StatelessWidget {
86
hintText: hintText,
87
focusedBorder: UnderlineInputBorder(
88
borderSide: BorderSide(
78
- color: borderColor ?? Theme.of(context).primaryTextTheme.title.backgroundColor,
89
+ color: borderColor ??
90
+ Theme.of(context).primaryTextTheme.title.backgroundColor,
91
width: 1.0)),
92
disabledBorder: UnderlineInputBorder(
93
borderSide: BorderSide(
82
- color: borderColor ?? Theme.of(context).primaryTextTheme.title.backgroundColor,
94
+ color: borderColor ??
95
+ Theme.of(context).primaryTextTheme.title.backgroundColor,
96
width: 1.0)),
97
enabledBorder: UnderlineInputBorder(
98
borderSide: BorderSide(
86
- color: borderColor ?? Theme.of(context).primaryTextTheme.title.backgroundColor,
99
+ color: borderColor ??
100
+ Theme.of(context).primaryTextTheme.title.backgroundColor,
101
width: 1.0))),
102
validator: validator,
103
);
lib/src/widgets/seed_widget.dart
+464
-230
@@ -1,3 +1,5 @@
1
+import 'package:cake_wallet/entities/wallet_type.dart';
2
+import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
3
import 'package:flutter/cupertino.dart';
4
import 'package:flutter/material.dart';
5
import 'package:flutter/services.dart';
@@ -8,6 +10,166 @@ import 'package:cake_wallet/entities/mnemonic_item.dart';
10
import 'package:cake_wallet/generated/i18n.dart';
11
import 'package:flutter/widgets.dart';
12
13
+class Annotation extends Comparable<Annotation> {
14
+ Annotation({@required this.range, this.style});
15
+
16
+ final TextRange range;
17
+ final TextStyle style;
18
+
19
+ @override
20
+ int compareTo(Annotation other) => range.start.compareTo(other.range.start);
21
+}
22
+
23
+class TextAnnotation extends Comparable<TextAnnotation> {
24
+ TextAnnotation({@required this.text, this.style});
25
+
26
+ final TextStyle style;
27
+ final String text;
28
+
29
+ @override
30
+ int compareTo(TextAnnotation other) => text.compareTo(other.text);
31
+}
32
+
33
+class AnnotatedEditableText extends EditableText {
34
+ AnnotatedEditableText({
35
+ Key key,
36
+ FocusNode focusNode,
37
+ TextEditingController controller,
38
+ TextStyle style,
39
+ ValueChanged<String> onChanged,
40
+ ValueChanged<String> onSubmitted,
41
+ Color cursorColor,
42
+ Color selectionColor,
43
+ Color backgroundCursorColor,
44
+ TextSelectionControls selectionControls,
45
+ @required this.words,
46
+ }) : textAnnotations = words
47
+ .map((word) => TextAnnotation(
48
+ text: word,
49
+ style: TextStyle(
50
+ color: Colors.black,
51
+ backgroundColor: Colors.transparent,
52
+ fontWeight: FontWeight.normal,
53
+ fontSize: 20)))
54
+ .toList(),
55
+ super(
56
+ maxLines: null,
57
+ key: key,
58
+ focusNode: focusNode,
59
+ controller: controller,
60
+ cursorColor: cursorColor,
61
+ style: style,
62
+ keyboardType: TextInputType.text,
63
+ autocorrect: false,
64
+ autofocus: false,
65
+ selectionColor: selectionColor,
66
+ selectionControls: selectionControls,
67
+ backgroundCursorColor: backgroundCursorColor,
68
+ onChanged: onChanged,
69
+ onSubmitted: onSubmitted,
70
+ toolbarOptions: const ToolbarOptions(
71
+ copy: true,
72
+ cut: true,
73
+ paste: true,
74
+ selectAll: true,
75
+ ),
76
+ enableSuggestions: false,
77
+ enableInteractiveSelection: true,
78
+ showSelectionHandles: true,
79
+ showCursor: true,
80
+ ) {
81
+ textAnnotations.add(TextAnnotation(
82
+ text: ' ', style: TextStyle(backgroundColor: Colors.transparent)));
83
+ }
84
+
85
+ final List<String> words;
86
+ final List<TextAnnotation> textAnnotations;
87
+
88
+ @override
89
+ AnnotatedEditableTextState createState() => AnnotatedEditableTextState();
90
+}
91
+
92
+class AnnotatedEditableTextState extends EditableTextState {
93
+ @override
94
+ AnnotatedEditableText get widget => super.widget as AnnotatedEditableText;
95
+
96
+ List<Annotation> getRanges() {
97
+ final source = widget.textAnnotations
98
+ .map((item) => range(item.text, textEditingValue.text)
99
+ .map((range) => Annotation(style: item.style, range: range)))
100
+ .expand((e) => e)
101
+ .toList();
102
+ final result = List<Annotation>();
103
+ final text = textEditingValue.text;
104
+ source.sort();
105
+ Annotation prev;
106
+
107
+ for (var item in source) {
108
+ if (prev == null) {
109
+ if (item.range.start > 0) {
110
+ result.add(Annotation(
111
+ range: TextRange(start: 0, end: item.range.start),
112
+ style: TextStyle(
113
+ color: Colors.black, backgroundColor: Colors.transparent)));
114
+ }
115
+ result.add(item);
116
+ prev = item;
117
+ continue;
118
+ } else {
119
+ if (prev.range.end > item.range.start) {
120
+ // throw StateError('Invalid (intersecting) ranges for annotated field');
121
+ } else if (prev.range.end < item.range.start) {
122
+ result.add(Annotation(
123
+ range: TextRange(start: prev.range.end, end: item.range.start),
124
+ style: TextStyle(
125
+ color: Colors.red, backgroundColor: Colors.transparent)));
126
+ }
127
+
128
+ result.add(item);
129
+ prev = item;
130
+ }
131
+ }
132
+
133
+ if (result.length > 0 && result.last.range.end < text.length) {
134
+ result.add(Annotation(
135
+ range: TextRange(start: result.last.range.end, end: text.length),
136
+ style: TextStyle( backgroundColor: Colors.transparent)));
137
+ }
138
+ return result;
139
+ }
140
+
141
+ List<TextRange> range(String pattern, String source) {
142
+ final result = List<TextRange>();
143
+
144
+ for (int index = source.indexOf(pattern);
145
+ index >= 0;
146
+ index = source.indexOf(pattern, index + 1)) {
147
+ final start = index;
148
+ final end = start + pattern.length;
149
+ result.add(TextRange(start: start, end: end));
150
+ }
151
+
152
+ return result;
153
+ }
154
+
155
+ @override
156
+ TextSpan buildTextSpan() {
157
+ final text = textEditingValue.text;
158
+ final ranges = getRanges();
159
+
160
+ if (ranges.isNotEmpty) {
161
+ return TextSpan(
162
+ style: widget.style,
163
+ children: ranges
164
+ .map((item) => TextSpan(
165
+ style: item.style, text: item.range.textInside(text)))
166
+ .toList());
167
+ }
168
+
169
+ return TextSpan(style: widget.style, text: text);
170
+ }
171
+}
172
+
173
class SeedWidget extends StatefulWidget {
174
SeedWidget(
175
{Key key,
@@ -48,10 +210,13 @@ class SeedWidgetState extends State<SeedWidget> {
210
@override
211
void initState() {
212
super.initState();
213
+ showPlaceholder = true;
214
isValid = false;
215
isCurrentMnemonicValid = false;
216
_seedController
217
.addListener(() => changeCurrentMnemonic(_seedController.text));
218
+ focusNode.addListener(() => setState(() =>
219
+ showPlaceholder = !focusNode.hasFocus && controller.text.isEmpty));
220
}
221
222
void addMnemonic(String text) {
@@ -198,239 +363,308 @@ class SeedWidgetState extends State<SeedWidget> {
363
return isValid;
364
}
365
366
+ final controller = TextEditingController();
367
+ final focusNode = FocusNode();
368
+
369
+ bool showPlaceholder;
370
+
371
+ final words =
372
+ SeedValidator.getWordList(type: WalletType.monero, language: 'en');
373
+
374
+ Future<void> _pasteAddress() async {
375
+ final value = await Clipboard.getData('text/plain');
376
+
377
+ if (value?.text?.isNotEmpty ?? false) {
378
+ controller.text = value.text;
379
+ }
380
+ }
381
+
382
@override
383
Widget build(BuildContext context) {
384
+ print('build');
385
return Container(
204
- child: Column(children: [
205
- Flexible(
206
- fit: FlexFit.tight,
207
- flex: 2,
208
- child: Container(
209
- width: double.infinity,
210
- height: double.infinity,
211
- padding: EdgeInsets.all(0),
212
- decoration: BoxDecoration(
213
- borderRadius: BorderRadius.only(
214
- bottomLeft: Radius.circular(24),
215
- bottomRight: Radius.circular(24)),
216
- gradient: LinearGradient(colors: [
217
- Theme.of(context).primaryTextTheme.subhead.color,
218
- Theme.of(context).primaryTextTheme.subhead.decorationColor,
219
- ], begin: Alignment.topLeft, end: Alignment.bottomRight)),
220
- child: Column(
221
- children: <Widget>[
222
- CupertinoNavigationBar(
223
- leading: widget.leading,
224
- middle: widget.middle,
225
- backgroundColor: Colors.transparent,
226
- border: null,
227
- ),
228
- Expanded(
229
- child: Container(
230
- padding: EdgeInsets.all(24),
231
- alignment: Alignment.topLeft,
232
- child: SingleChildScrollView(
233
- child: Column(
234
- mainAxisAlignment: MainAxisAlignment.start,
235
- crossAxisAlignment: CrossAxisAlignment.start,
236
- children: <Widget>[
237
- Text(
238
- S.of(context).restore_active_seed,
239
- style: TextStyle(
240
- fontSize: 14,
241
- fontWeight: FontWeight.w500,
242
- color: Theme.of(context)
243
- .textTheme
244
- .overline
245
- .backgroundColor),
246
- ),
247
- Padding(
248
- padding: EdgeInsets.only(top: 5),
249
- child: Wrap(
250
- children: items.map((item) {
251
- final isValid =
252
- widget.validator.isValid(item);
253
- final isSelected = selectedItem == item;
254
-
255
- return InkWell(
256
- onTap: () => onMnemonicTap(item),
257
- child: Container(
258
- decoration: BoxDecoration(
259
- color: isValid
260
- ? Colors.transparent
261
- : Palette.red),
262
- margin: EdgeInsets.only(
263
- right: 7, bottom: 8),
264
- child: Text(
265
- item.toString(),
266
- style: TextStyle(
267
- color: isValid
268
- ? Colors.white
269
- : Colors.grey,
270
- fontSize: 16,
271
- fontWeight: isSelected
272
- ? FontWeight.w900
273
- : FontWeight.w600,
274
- decoration: isSelected
275
- ? TextDecoration.underline
276
- : TextDecoration.none),
277
- )),
278
- );
279
- }).toList(),
280
- ))
281
- ],
282
- ),
283
- ),
284
- ))
285
- ],
286
- )),
287
- ),
288
- Flexible(
289
- fit: FlexFit.tight,
290
- flex: 3,
291
- child: Padding(
292
- padding:
293
- EdgeInsets.only(left: 24, top: 48, right: 24, bottom: 24),
294
- child: Column(
295
- mainAxisAlignment: MainAxisAlignment.start,
296
- crossAxisAlignment: CrossAxisAlignment.center,
297
- children: <Widget>[
298
- Text(
299
- S.of(context).restore_new_seed,
386
+ child: Column(
387
+ crossAxisAlignment: CrossAxisAlignment.start,
388
+ mainAxisAlignment: MainAxisAlignment.start,
389
+ children: [
390
+ Stack(children: [
391
+ SizedBox(height: 35),
392
+ if (showPlaceholder)
393
+ Positioned(
394
+ top: 10,
395
+ left: 0,
396
+ child: Text('Enter your seed',
397
style: TextStyle(
301
- fontSize: 20,
302
- fontWeight: FontWeight.w500,
303
- color:
304
- Theme.of(context).primaryTextTheme.title.color),
305
- ),
306
- Padding(
307
- padding: EdgeInsets.only(top: 24),
308
- child: TextFormField(
309
- key: _seedTextFieldKey,
310
- onFieldSubmitted: (text) => isCurrentMnemonicValid
311
- ? saveCurrentMnemonicToItems()
312
- : null,
313
- style: TextStyle(
314
- fontSize: 16.0,
315
- fontWeight: FontWeight.normal,
316
- color:
317
- Theme.of(context).primaryTextTheme.title.color),
318
- controller: _seedController,
319
- textInputAction: TextInputAction.done,
320
- decoration: InputDecoration(
321
- suffixIcon: GestureDetector(
322
- behavior: HitTestBehavior.opaque,
323
- child: ConstrainedBox(
324
- constraints: BoxConstraints(maxWidth: 145),
325
- child: Row(
326
- mainAxisAlignment: MainAxisAlignment.end,
327
- children: <Widget>[
328
- Text('${items.length}/$maxLength',
329
- style: TextStyle(
330
- color: Theme.of(context)
331
- .accentTextTheme
332
- .display2
333
- .decorationColor,
334
- fontWeight: FontWeight.normal,
335
- fontSize: 16)),
336
- SizedBox(width: 10),
337
- InkWell(
338
- onTap: () async =>
339
- Clipboard.getData('text/plain').then(
340
- (clipboard) =>
341
- replaceText(clipboard.text)),
342
- child: Container(
343
- height: 35,
344
- padding: EdgeInsets.all(7),
345
- decoration: BoxDecoration(
346
- color: Theme.of(context)
347
- .accentTextTheme
348
- .caption
349
- .color,
350
- borderRadius:
351
- BorderRadius.circular(10.0)),
352
- child: Text(
353
- S.of(context).paste,
354
- style: TextStyle(
355
- color: Palette.blueCraiola),
356
- )),
357
- )
358
- ],
359
- ),
360
- ),
361
- ),
362
- hintStyle: TextStyle(
363
- color: Theme.of(context)
364
- .accentTextTheme
365
- .display2
366
- .decorationColor,
367
- fontWeight: FontWeight.normal,
368
- fontSize: 16),
369
- hintText:
370
- S.of(context).restore_from_seed_placeholder,
371
- errorText: _errorMessage,
372
- focusedBorder: UnderlineInputBorder(
373
- borderSide: BorderSide(
374
- color: Theme.of(context)
375
- .accentTextTheme
376
- .subtitle
377
- .backgroundColor,
378
- width: 1.0)),
379
- enabledBorder: UnderlineInputBorder(
380
- borderSide: BorderSide(
381
- color: Theme.of(context)
382
- .accentTextTheme
383
- .subtitle
384
- .backgroundColor,
385
- width: 1.0))),
386
- enableInteractiveSelection: false,
387
- ),
388
- )
389
- ]),
390
- )),
391
- Padding(
392
- padding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
393
- child: Row(
394
- children: <Widget>[
395
- Flexible(
396
- child: Padding(
397
- padding: EdgeInsets.only(right: 8),
398
- child: PrimaryButton(
399
- onPressed: clear,
400
- text: S.of(context).clear,
401
- color: Colors.orange,
402
- textColor: Colors.white,
403
- isDisabled: items.isEmpty,
404
- ),
405
- )),
406
- Flexible(
407
- child: Padding(
408
- padding: EdgeInsets.only(left: 8),
409
- child: (selectedItem == null && items.length == maxLength)
410
- ? PrimaryButton(
411
- text: S.of(context).restore_next,
412
- isDisabled: !isSeedValid(),
413
- onPressed: () => widget.onFinish != null
414
- ? widget.onFinish()
415
- : null,
416
- color: Theme.of(context).accentTextTheme.body2.color,
417
- textColor: Colors.white)
418
- : PrimaryButton(
419
- text: selectedItem != null
420
- ? S.of(context).save
421
- : S.of(context).add_new_word,
422
- onPressed: () => isCurrentMnemonicValid
423
- ? saveCurrentMnemonicToItems()
424
- : null,
425
- onDisabledPressed: () => showErrorIfExist(),
426
- isDisabled: !isCurrentMnemonicValid,
427
- color: Theme.of(context).accentTextTheme.body2.color,
428
- textColor: Colors.white),
429
- ),
430
- )
431
- ],
432
- ))
433
- ]),
434
- );
398
+ fontSize: 16.0, color: Theme.of(context).hintColor))),
399
+ Padding(
400
+ padding: EdgeInsets.only(right: 40, top: 10),
401
+ child: AnnotatedEditableText(
402
+ cursorColor: Colors.green,
403
+ backgroundCursorColor: Colors.blue,
404
+ style: TextStyle(
405
+ fontSize: 20,
406
+ color: Colors.red,
407
+ fontWeight: FontWeight.normal,
408
+ backgroundColor: Colors.transparent),
409
+ focusNode: focusNode,
410
+ controller: controller,
411
+ words: words)),
412
+ Positioned(
413
+ top: 0,
414
+ right: 0,
415
+ child: Container(
416
+ width: 34,
417
+ height: 34,
418
+ child: InkWell(
419
+ onTap: () async => _pasteAddress(),
420
+ child: Container(
421
+ decoration: BoxDecoration(
422
+ color: Theme.of(context).hintColor,
423
+ borderRadius:
424
+ BorderRadius.all(Radius.circular(6))),
425
+ child: Image.asset('assets/images/duplicate.png',
426
+ color: Theme.of(context)
427
+ .primaryTextTheme
428
+ .display1
429
+ .decorationColor)),
430
+ )))
431
+ ]),
432
+ Container(
433
+ margin: EdgeInsets.only(top: 15),
434
+ height: 1.0,
435
+ color: Theme.of(context).primaryTextTheme.title.backgroundColor),
436
+ ]));
437
+ // return Container(
438
+ // child: Column(children: [
439
+ // Flexible(
440
+ // fit: FlexFit.tight,
441
+ // flex: 2,
442
+ // child: Container(
443
+ // width: double.infinity,
444
+ // height: double.infinity,
445
+ // padding: EdgeInsets.all(0),
446
+ // decoration: BoxDecoration(
447
+ // borderRadius: BorderRadius.only(
448
+ // bottomLeft: Radius.circular(24),
449
+ // bottomRight: Radius.circular(24)),
450
+ // gradient: LinearGradient(colors: [
451
+ // Theme.of(context).primaryTextTheme.subhead.color,
452
+ // Theme.of(context).primaryTextTheme.subhead.decorationColor,
453
+ // ], begin: Alignment.topLeft, end: Alignment.bottomRight)),
454
+ // child: Column(
455
+ // children: <Widget>[
456
+ // CupertinoNavigationBar(
457
+ // leading: widget.leading,
458
+ // middle: widget.middle,
459
+ // backgroundColor: Colors.transparent,
460
+ // border: null,
461
+ // ),
462
+ // Expanded(
463
+ // child: Container(
464
+ // padding: EdgeInsets.all(24),
465
+ // alignment: Alignment.topLeft,
466
+ // child: SingleChildScrollView(
467
+ // child: Column(
468
+ // mainAxisAlignment: MainAxisAlignment.start,
469
+ // crossAxisAlignment: CrossAxisAlignment.start,
470
+ // children: <Widget>[
471
+ // Text(
472
+ // S.of(context).restore_active_seed,
473
+ // style: TextStyle(
474
+ // fontSize: 14,
475
+ // fontWeight: FontWeight.w500,
476
+ // color: Theme.of(context)
477
+ // .textTheme
478
+ // .overline
479
+ // .backgroundColor),
480
+ // ),
481
+ // Padding(
482
+ // padding: EdgeInsets.only(top: 5),
483
+ // child: Wrap(
484
+ // children: items.map((item) {
485
+ // final isValid =
486
+ // widget.validator.isValid(item);
487
+ // final isSelected = selectedItem == item;
488
+ //
489
+ // return InkWell(
490
+ // onTap: () => onMnemonicTap(item),
491
+ // child: Container(
492
+ // decoration: BoxDecoration(
493
+ // color: isValid
494
+ // ? Colors.transparent
495
+ // : Palette.red),
496
+ // margin: EdgeInsets.only(
497
+ // right: 7, bottom: 8),
498
+ // child: Text(
499
+ // item.toString(),
500
+ // style: TextStyle(
501
+ // color: isValid
502
+ // ? Colors.white
503
+ // : Colors.grey,
504
+ // fontSize: 16,
505
+ // fontWeight: isSelected
506
+ // ? FontWeight.w900
507
+ // : FontWeight.w600,
508
+ // decoration: isSelected
509
+ // ? TextDecoration.underline
510
+ // : TextDecoration.none),
511
+ // )),
512
+ // );
513
+ // }).toList(),
514
+ // ))
515
+ // ],
516
+ // ),
517
+ // ),
518
+ // ))
519
+ // ],
520
+ // )),
521
+ // ),
522
+ // Flexible(
523
+ // fit: FlexFit.tight,
524
+ // flex: 3,
525
+ // child: Padding(
526
+ // padding:
527
+ // EdgeInsets.only(left: 24, top: 48, right: 24, bottom: 24),
528
+ // child: Column(
529
+ // mainAxisAlignment: MainAxisAlignment.start,
530
+ // crossAxisAlignment: CrossAxisAlignment.center,
531
+ // children: <Widget>[
532
+ // Text(
533
+ // S.of(context).restore_new_seed,
534
+ // style: TextStyle(
535
+ // fontSize: 20,
536
+ // fontWeight: FontWeight.w500,
537
+ // color:
538
+ // Theme.of(context).primaryTextTheme.title.color),
539
+ // ),
540
+ // Padding(
541
+ // padding: EdgeInsets.only(top: 24),
542
+ // child: TextFormField(
543
+ // key: _seedTextFieldKey,
544
+ // onFieldSubmitted: (text) => isCurrentMnemonicValid
545
+ // ? saveCurrentMnemonicToItems()
546
+ // : null,
547
+ // style: TextStyle(
548
+ // fontSize: 16.0,
549
+ // fontWeight: FontWeight.normal,
550
+ // color:
551
+ // Theme.of(context).primaryTextTheme.title.color),
552
+ // controller: _seedController,
553
+ // textInputAction: TextInputAction.done,
554
+ // decoration: InputDecoration(
555
+ // suffixIcon: GestureDetector(
556
+ // behavior: HitTestBehavior.opaque,
557
+ // child: ConstrainedBox(
558
+ // constraints: BoxConstraints(maxWidth: 145),
559
+ // child: Row(
560
+ // mainAxisAlignment: MainAxisAlignment.end,
561
+ // children: <Widget>[
562
+ // Text('${items.length}/$maxLength',
563
+ // style: TextStyle(
564
+ // color: Theme.of(context)
565
+ // .accentTextTheme
566
+ // .display2
567
+ // .decorationColor,
568
+ // fontWeight: FontWeight.normal,
569
+ // fontSize: 16)),
570
+ // SizedBox(width: 10),
571
+ // InkWell(
572
+ // onTap: () async =>
573
+ // Clipboard.getData('text/plain').then(
574
+ // (clipboard) =>
575
+ // replaceText(clipboard.text)),
576
+ // child: Container(
577
+ // height: 35,
578
+ // padding: EdgeInsets.all(7),
579
+ // decoration: BoxDecoration(
580
+ // color: Theme.of(context)
581
+ // .accentTextTheme
582
+ // .caption
583
+ // .color,
584
+ // borderRadius:
585
+ // BorderRadius.circular(10.0)),
586
+ // child: Text(
587
+ // S.of(context).paste,
588
+ // style: TextStyle(
589
+ // color: Palette.blueCraiola),
590
+ // )),
591
+ // )
592
+ // ],
593
+ // ),
594
+ // ),
595
+ // ),
596
+ // hintStyle: TextStyle(
597
+ // color: Theme.of(context)
598
+ // .accentTextTheme
599
+ // .display2
600
+ // .decorationColor,
601
+ // fontWeight: FontWeight.normal,
602
+ // fontSize: 16),
603
+ // hintText:
604
+ // S.of(context).restore_from_seed_placeholder,
605
+ // errorText: _errorMessage,
606
+ // focusedBorder: UnderlineInputBorder(
607
+ // borderSide: BorderSide(
608
+ // color: Theme.of(context)
609
+ // .accentTextTheme
610
+ // .subtitle
611
+ // .backgroundColor,
612
+ // width: 1.0)),
613
+ // enabledBorder: UnderlineInputBorder(
614
+ // borderSide: BorderSide(
615
+ // color: Theme.of(context)
616
+ // .accentTextTheme
617
+ // .subtitle
618
+ // .backgroundColor,
619
+ // width: 1.0))),
620
+ // enableInteractiveSelection: false,
621
+ // ),
622
+ // )
623
+ // ]),
624
+ // )),
625
+ // Padding(
626
+ // padding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
627
+ // child: Row(
628
+ // children: <Widget>[
629
+ // Flexible(
630
+ // child: Padding(
631
+ // padding: EdgeInsets.only(right: 8),
632
+ // child: PrimaryButton(
633
+ // onPressed: clear,
634
+ // text: S.of(context).clear,
635
+ // color: Colors.orange,
636
+ // textColor: Colors.white,
637
+ // isDisabled: items.isEmpty,
638
+ // ),
639
+ // )),
640
+ // Flexible(
641
+ // child: Padding(
642
+ // padding: EdgeInsets.only(left: 8),
643
+ // child: (selectedItem == null && items.length == maxLength)
644
+ // ? PrimaryButton(
645
+ // text: S.of(context).restore_next,
646
+ // isDisabled: !isSeedValid(),
647
+ // onPressed: () => widget.onFinish != null
648
+ // ? widget.onFinish()
649
+ // : null,
650
+ // color: Theme.of(context).accentTextTheme.body2.color,
651
+ // textColor: Colors.white)
652
+ // : PrimaryButton(
653
+ // text: selectedItem != null
654
+ // ? S.of(context).save
655
+ // : S.of(context).add_new_word,
656
+ // onPressed: () => isCurrentMnemonicValid
657
+ // ? saveCurrentMnemonicToItems()
658
+ // : null,
659
+ // onDisabledPressed: () => showErrorIfExist(),
660
+ // isDisabled: !isCurrentMnemonicValid,
661
+ // color: Theme.of(context).accentTextTheme.body2.color,
662
+ // textColor: Colors.white),
663
+ // ),
664
+ // )
665
+ // ],
666
+ // ))
667
+ // ]),
668
+ // );
669
}
670
}