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 }