CAKE-150

M committed Nov 4, 2020 at 00:29 UTC 7e33f1ae0afad359a4f86996e71afb3f7bffe5b5
5 files changed +188 -165
lib/src/screens/restore/wallet_restore_from_seed_form.dart
+5
@@ -46,6 +46,11 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
46 context: context,
47 builder: (BuildContext context) =>
48 SeedLanguagePicker(selected: language));
49 +
50 + if (selected == null || selected.isEmpty) {
51 + return;
52 + }
53 +
54 _changeLanguage(selected);
55 },
56 child: Container(
lib/src/screens/seed_language/widgets/seed_language_picker.dart
+1
@@ -92,6 +92,7 @@ class SeedLanguagePickerState extends State<SeedLanguagePicker> {
92 width: 300,
93 color: Theme.of(context).accentTextTheme.title.backgroundColor,
94 child: GridView.count(
95 + padding: EdgeInsets.all(0),
96 shrinkWrap: true,
97 crossAxisCount: 3,
98 childAspectRatio: 1,
lib/src/widgets/annotated_editable_text.dart deleted
-160
@@ -1,160 +0,0 @@
1 -import 'package:flutter/material.dart';
2 -
3 -class Annotation extends Comparable<Annotation> {
4 - Annotation({@required this.range, this.style});
5 -
6 - final TextRange range;
7 - final TextStyle style;
8 -
9 - @override
10 - int compareTo(Annotation other) => range.start.compareTo(other.range.start);
11 -}
12 -
13 -class TextAnnotation extends Comparable<TextAnnotation> {
14 - TextAnnotation({@required this.text, this.style});
15 -
16 - final TextStyle style;
17 - final String text;
18 -
19 - @override
20 - int compareTo(TextAnnotation other) => text.compareTo(other.text);
21 -}
22 -
23 -class AnnotatedEditableText extends EditableText {
24 - AnnotatedEditableText({
25 - Key key,
26 - FocusNode focusNode,
27 - TextEditingController controller,
28 - TextStyle style,
29 - ValueChanged<String> onChanged,
30 - ValueChanged<String> onSubmitted,
31 - Color cursorColor,
32 - Color selectionColor,
33 - Color backgroundCursorColor,
34 - TextSelectionControls selectionControls,
35 - TextStyle textStyle = const TextStyle(
36 - color: Colors.black,
37 - backgroundColor: Colors.transparent,
38 - fontWeight: FontWeight.normal,
39 - fontSize: 16),
40 - @required this.words,
41 - }) : textAnnotations = words
42 - .map((word) => TextAnnotation(text: word, style: textStyle))
43 - .toList(),
44 - super(
45 - maxLines: null,
46 - key: key,
47 - focusNode: focusNode,
48 - controller: controller,
49 - cursorColor: cursorColor,
50 - style: style,
51 - keyboardType: TextInputType.text,
52 - autocorrect: false,
53 - autofocus: false,
54 - selectionColor: selectionColor,
55 - selectionControls: selectionControls,
56 - backgroundCursorColor: backgroundCursorColor,
57 - onChanged: onChanged,
58 - onSubmitted: onSubmitted,
59 - toolbarOptions: const ToolbarOptions(
60 - copy: true,
61 - cut: true,
62 - paste: true,
63 - selectAll: true,
64 - ),
65 - enableSuggestions: false,
66 - enableInteractiveSelection: true,
67 - showSelectionHandles: true,
68 - showCursor: true,
69 - ) {
70 - textAnnotations.add(TextAnnotation(
71 - text: ' ', style: TextStyle(backgroundColor: Colors.transparent)));
72 - }
73 -
74 - final List<String> words;
75 - final List<TextAnnotation> textAnnotations;
76 -
77 - @override
78 - AnnotatedEditableTextState createState() => AnnotatedEditableTextState();
79 -}
80 -
81 -class AnnotatedEditableTextState extends EditableTextState {
82 - @override
83 - AnnotatedEditableText get widget => super.widget as AnnotatedEditableText;
84 -
85 - List<Annotation> getRanges() {
86 - final source = widget.textAnnotations
87 - .map((item) => range(item.text, textEditingValue.text)
88 - .map((range) => Annotation(style: item.style, range: range)))
89 - .expand((e) => e)
90 - .toList();
91 - final result = List<Annotation>();
92 - final text = textEditingValue.text;
93 - source.sort();
94 - Annotation prev;
95 -
96 - for (var item in source) {
97 - if (prev == null) {
98 - if (item.range.start > 0) {
99 - result.add(Annotation(
100 - range: TextRange(start: 0, end: item.range.start),
101 - style: TextStyle(
102 - color: Colors.black, backgroundColor: Colors.transparent)));
103 - }
104 - result.add(item);
105 - prev = item;
106 - continue;
107 - } else {
108 - if (prev.range.end > item.range.start) {
109 - // throw StateError('Invalid (intersecting) ranges for annotated field');
110 - } else if (prev.range.end < item.range.start) {
111 - result.add(Annotation(
112 - range: TextRange(start: prev.range.end, end: item.range.start),
113 - style: TextStyle(
114 - color: Colors.red, backgroundColor: Colors.transparent)));
115 - }
116 -
117 - result.add(item);
118 - prev = item;
119 - }
120 - }
121 -
122 - if (result.length > 0 && result.last.range.end < text.length) {
123 - result.add(Annotation(
124 - range: TextRange(start: result.last.range.end, end: text.length),
125 - style: TextStyle(backgroundColor: Colors.transparent)));
126 - }
127 - return result;
128 - }
129 -
130 - List<TextRange> range(String pattern, String source) {
131 - final result = List<TextRange>();
132 -
133 - for (int index = source.indexOf(pattern);
134 - index >= 0;
135 - index = source.indexOf(pattern, index + 1)) {
136 - final start = index;
137 - final end = start + pattern.length;
138 - result.add(TextRange(start: start, end: end));
139 - }
140 -
141 - return result;
142 - }
143 -
144 - @override
145 - TextSpan buildTextSpan() {
146 - final text = textEditingValue.text;
147 - final ranges = getRanges();
148 -
149 - if (ranges.isNotEmpty) {
150 - return TextSpan(
151 - style: widget.style,
152 - children: ranges
153 - .map((item) => TextSpan(
154 - style: item.style, text: item.range.textInside(text)))
155 - .toList());
156 - }
157 -
158 - return TextSpan(style: widget.style, text: text);
159 - }
160 -}
lib/src/widgets/seed_widget.dart
+10 -5
@@ -1,5 +1,5 @@
1 import 'package:cake_wallet/entities/wallet_type.dart';
2 -import 'package:cake_wallet/src/widgets/annotated_editable_text.dart';
2 +import 'package:cake_wallet/src/widgets/validable_annotated_editable_text.dart';
3 import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
4 import 'package:flutter/cupertino.dart';
5 import 'package:flutter/material.dart';
@@ -77,10 +77,15 @@ class SeedWidgetState extends State<SeedWidget> {
77 fontSize: 16.0, color: Theme.of(context).hintColor))),
78 Padding(
79 padding: EdgeInsets.only(right: 40, top: 10),
80 - child: AnnotatedEditableText(
80 + child: ValidableAnnotatedEditableText(
81 cursorColor: Colors.blue,
82 backgroundCursorColor: Colors.blue,
83 - style: TextStyle(
83 + validStyle: TextStyle(
84 + color: Theme.of(context).primaryTextTheme.title.color,
85 + backgroundColor: Colors.transparent,
86 + fontWeight: FontWeight.normal,
87 + fontSize: 16),
88 + invalidStyle: TextStyle(
89 fontSize: 16,
90 color: Colors.red,
91 fontWeight: FontWeight.normal,
@@ -101,7 +106,7 @@ class SeedWidgetState extends State<SeedWidget> {
106 width: 34,
107 height: 34,
108 child: InkWell(
104 - onTap: () async => _pasteAddress(),
109 + onTap: () async => _pasteText(),
110 child: Container(
111 padding: EdgeInsets.all(8),
112 decoration: BoxDecoration(
@@ -122,7 +127,7 @@ class SeedWidgetState extends State<SeedWidget> {
127 ]));
128 }
129
125 - Future<void> _pasteAddress() async {
130 + Future<void> _pasteText() async {
131 final value = await Clipboard.getData('text/plain');
132
133 if (value?.text?.isNotEmpty ?? false) {
lib/src/widgets/validable_annotated_editable_text.dart new
+172
@@ -0,0 +1,172 @@
1 +import 'package:cake_wallet/core/seed_validator.dart';
2 +import 'package:cake_wallet/entities/wallet_type.dart';
3 +import 'package:flutter/material.dart';
4 +
5 +class Annotation extends Comparable<Annotation> {
6 + Annotation({@required this.range, this.style});
7 +
8 + final TextRange range;
9 + final TextStyle style;
10 +
11 + @override
12 + int compareTo(Annotation other) => range.start.compareTo(other.range.start);
13 +}
14 +
15 +class TextAnnotation extends Comparable<TextAnnotation> {
16 + TextAnnotation({@required this.text, this.style});
17 +
18 + final TextStyle style;
19 + final String text;
20 +
21 + @override
22 + int compareTo(TextAnnotation other) => text.compareTo(other.text);
23 +}
24 +
25 +class ValidableAnnotatedEditableText extends EditableText {
26 + ValidableAnnotatedEditableText({
27 + Key key,
28 + FocusNode focusNode,
29 + TextEditingController controller,
30 + List<String> wordList,
31 + ValueChanged<String> onChanged,
32 + ValueChanged<String> onSubmitted,
33 + Color cursorColor,
34 + Color selectionColor,
35 + Color backgroundCursorColor,
36 + TextSelectionControls selectionControls,
37 + this.validStyle,
38 + this.invalidStyle,
39 + TextStyle textStyle = const TextStyle(
40 + color: Colors.black,
41 + backgroundColor: Colors.transparent,
42 + fontWeight: FontWeight.normal,
43 + fontSize: 16),
44 + @required this.words,
45 + }) : super(
46 + maxLines: null,
47 + key: key,
48 + focusNode: focusNode,
49 + controller: controller,
50 + cursorColor: cursorColor,
51 + style: validStyle,
52 + keyboardType: TextInputType.text,
53 + autocorrect: false,
54 + autofocus: false,
55 + selectionColor: selectionColor,
56 + selectionControls: selectionControls,
57 + backgroundCursorColor: backgroundCursorColor,
58 + onChanged: onChanged,
59 + onSubmitted: onSubmitted,
60 + toolbarOptions: const ToolbarOptions(
61 + copy: true,
62 + cut: true,
63 + paste: true,
64 + selectAll: true,
65 + ),
66 + enableSuggestions: false,
67 + enableInteractiveSelection: true,
68 + showSelectionHandles: true,
69 + showCursor: true);
70 +
71 + final List<String> words;
72 + final TextStyle validStyle;
73 + final TextStyle invalidStyle;
74 +
75 + @override
76 + ValidableAnnotatedEditableTextState createState() => ValidableAnnotatedEditableTextState();
77 +}
78 +
79 +class ValidableAnnotatedEditableTextState extends EditableTextState {
80 + @override
81 + ValidableAnnotatedEditableText get widget => super.widget as ValidableAnnotatedEditableText;
82 +
83 + List<Annotation> getRanges() {
84 + final result = List<Annotation>();
85 + final text = textEditingValue.text;
86 + final source = text
87 + .split(' ')
88 + .map((word) {
89 + final ranges = range(word, text);
90 + final isValid = validate(word);
91 +
92 + return ranges.map((range) => Annotation(
93 + style: isValid ? widget.validStyle : widget.invalidStyle,
94 + range: range));
95 + })
96 + .expand((e) => e)
97 + .toList();
98 + source.sort();
99 + Annotation prev;
100 +
101 + for (var item in source) {
102 + Annotation annotation;
103 +
104 + if (prev == null) {
105 + annotation = Annotation(
106 + range: TextRange(start: 0, end: item.range.start),
107 + style: TextStyle(
108 + color: Colors.black, backgroundColor: Colors.transparent));
109 + } else if (prev.range.end < item.range.start) {
110 + annotation = Annotation(
111 + range: TextRange(start: prev.range.end, end: item.range.start),
112 + style: TextStyle(
113 + color: Colors.red, backgroundColor: Colors.transparent));
114 + }
115 +
116 + if (annotation != null) {
117 + result.add(annotation);
118 + result.add(item);
119 + prev = item;
120 + }
121 + }
122 +
123 + if (result.length > 0 && result.last.range.end < text.length) {
124 + result.add(Annotation(
125 + range: TextRange(start: result.last.range.end, end: text.length),
126 + style: TextStyle(backgroundColor: Colors.transparent)));
127 + }
128 +
129 + return result;
130 + }
131 +
132 + bool validate(String source) => widget.words.indexOf(source) >= 0;
133 +
134 + List<TextRange> range(String pattern, String source) {
135 + final result = List<TextRange>();
136 +
137 + if (pattern.isEmpty || source.isEmpty) {
138 + return result;
139 + }
140 +
141 + for (int index = source.indexOf(pattern);
142 + index >= 0;
143 + index = source.indexOf(pattern, index + 1)) {
144 + final start = index;
145 + final end = start + pattern.length;
146 + result.add(TextRange(start: start, end: end));
147 + }
148 +
149 + return result;
150 + }
151 +
152 + @override
153 + TextSpan buildTextSpan() {
154 + final text = textEditingValue.text;
155 + final ranges = getRanges().toSet();
156 +
157 + print('text $text');
158 +
159 + if (ranges.isNotEmpty) {
160 + return TextSpan(
161 + style: widget.style,
162 + children: ranges.map((item) {
163 + final _text = item.range.textInside(text);
164 + print(
165 + '_text $_text; range ${item.range.start} : ${item.range.end}');
166 + return TextSpan(style: item.style, text: _text);
167 + }).toList());
168 + }
169 +
170 + return TextSpan(style: widget.style, text: text);
171 + }
172 +}