mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-10 12:54:38 +00:00
CAKE-150
This commit is contained in:
parent
76581505a0
commit
7e33f1ae0a
5 changed files with 188 additions and 165 deletions
|
@ -46,6 +46,11 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
|||
context: context,
|
||||
builder: (BuildContext context) =>
|
||||
SeedLanguagePicker(selected: language));
|
||||
|
||||
if (selected == null || selected.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
_changeLanguage(selected);
|
||||
},
|
||||
child: Container(
|
||||
|
|
|
@ -92,6 +92,7 @@ class SeedLanguagePickerState extends State<SeedLanguagePicker> {
|
|||
width: 300,
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
child: GridView.count(
|
||||
padding: EdgeInsets.all(0),
|
||||
shrinkWrap: true,
|
||||
crossAxisCount: 3,
|
||||
childAspectRatio: 1,
|
||||
|
|
|
@ -1,160 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class Annotation extends Comparable<Annotation> {
|
||||
Annotation({@required this.range, this.style});
|
||||
|
||||
final TextRange range;
|
||||
final TextStyle style;
|
||||
|
||||
@override
|
||||
int compareTo(Annotation other) => range.start.compareTo(other.range.start);
|
||||
}
|
||||
|
||||
class TextAnnotation extends Comparable<TextAnnotation> {
|
||||
TextAnnotation({@required this.text, this.style});
|
||||
|
||||
final TextStyle style;
|
||||
final String text;
|
||||
|
||||
@override
|
||||
int compareTo(TextAnnotation other) => text.compareTo(other.text);
|
||||
}
|
||||
|
||||
class AnnotatedEditableText extends EditableText {
|
||||
AnnotatedEditableText({
|
||||
Key key,
|
||||
FocusNode focusNode,
|
||||
TextEditingController controller,
|
||||
TextStyle style,
|
||||
ValueChanged<String> onChanged,
|
||||
ValueChanged<String> onSubmitted,
|
||||
Color cursorColor,
|
||||
Color selectionColor,
|
||||
Color backgroundCursorColor,
|
||||
TextSelectionControls selectionControls,
|
||||
TextStyle textStyle = const TextStyle(
|
||||
color: Colors.black,
|
||||
backgroundColor: Colors.transparent,
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: 16),
|
||||
@required this.words,
|
||||
}) : textAnnotations = words
|
||||
.map((word) => TextAnnotation(text: word, style: textStyle))
|
||||
.toList(),
|
||||
super(
|
||||
maxLines: null,
|
||||
key: key,
|
||||
focusNode: focusNode,
|
||||
controller: controller,
|
||||
cursorColor: cursorColor,
|
||||
style: style,
|
||||
keyboardType: TextInputType.text,
|
||||
autocorrect: false,
|
||||
autofocus: false,
|
||||
selectionColor: selectionColor,
|
||||
selectionControls: selectionControls,
|
||||
backgroundCursorColor: backgroundCursorColor,
|
||||
onChanged: onChanged,
|
||||
onSubmitted: onSubmitted,
|
||||
toolbarOptions: const ToolbarOptions(
|
||||
copy: true,
|
||||
cut: true,
|
||||
paste: true,
|
||||
selectAll: true,
|
||||
),
|
||||
enableSuggestions: false,
|
||||
enableInteractiveSelection: true,
|
||||
showSelectionHandles: true,
|
||||
showCursor: true,
|
||||
) {
|
||||
textAnnotations.add(TextAnnotation(
|
||||
text: ' ', style: TextStyle(backgroundColor: Colors.transparent)));
|
||||
}
|
||||
|
||||
final List<String> words;
|
||||
final List<TextAnnotation> textAnnotations;
|
||||
|
||||
@override
|
||||
AnnotatedEditableTextState createState() => AnnotatedEditableTextState();
|
||||
}
|
||||
|
||||
class AnnotatedEditableTextState extends EditableTextState {
|
||||
@override
|
||||
AnnotatedEditableText get widget => super.widget as AnnotatedEditableText;
|
||||
|
||||
List<Annotation> getRanges() {
|
||||
final source = widget.textAnnotations
|
||||
.map((item) => range(item.text, textEditingValue.text)
|
||||
.map((range) => Annotation(style: item.style, range: range)))
|
||||
.expand((e) => e)
|
||||
.toList();
|
||||
final result = List<Annotation>();
|
||||
final text = textEditingValue.text;
|
||||
source.sort();
|
||||
Annotation prev;
|
||||
|
||||
for (var item in source) {
|
||||
if (prev == null) {
|
||||
if (item.range.start > 0) {
|
||||
result.add(Annotation(
|
||||
range: TextRange(start: 0, end: item.range.start),
|
||||
style: TextStyle(
|
||||
color: Colors.black, backgroundColor: Colors.transparent)));
|
||||
}
|
||||
result.add(item);
|
||||
prev = item;
|
||||
continue;
|
||||
} else {
|
||||
if (prev.range.end > item.range.start) {
|
||||
// throw StateError('Invalid (intersecting) ranges for annotated field');
|
||||
} else if (prev.range.end < item.range.start) {
|
||||
result.add(Annotation(
|
||||
range: TextRange(start: prev.range.end, end: item.range.start),
|
||||
style: TextStyle(
|
||||
color: Colors.red, backgroundColor: Colors.transparent)));
|
||||
}
|
||||
|
||||
result.add(item);
|
||||
prev = item;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.length > 0 && result.last.range.end < text.length) {
|
||||
result.add(Annotation(
|
||||
range: TextRange(start: result.last.range.end, end: text.length),
|
||||
style: TextStyle(backgroundColor: Colors.transparent)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
List<TextRange> range(String pattern, String source) {
|
||||
final result = List<TextRange>();
|
||||
|
||||
for (int index = source.indexOf(pattern);
|
||||
index >= 0;
|
||||
index = source.indexOf(pattern, index + 1)) {
|
||||
final start = index;
|
||||
final end = start + pattern.length;
|
||||
result.add(TextRange(start: start, end: end));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@override
|
||||
TextSpan buildTextSpan() {
|
||||
final text = textEditingValue.text;
|
||||
final ranges = getRanges();
|
||||
|
||||
if (ranges.isNotEmpty) {
|
||||
return TextSpan(
|
||||
style: widget.style,
|
||||
children: ranges
|
||||
.map((item) => TextSpan(
|
||||
style: item.style, text: item.range.textInside(text)))
|
||||
.toList());
|
||||
}
|
||||
|
||||
return TextSpan(style: widget.style, text: text);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:cake_wallet/entities/wallet_type.dart';
|
||||
import 'package:cake_wallet/src/widgets/annotated_editable_text.dart';
|
||||
import 'package:cake_wallet/src/widgets/validable_annotated_editable_text.dart';
|
||||
import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -77,10 +77,15 @@ class SeedWidgetState extends State<SeedWidget> {
|
|||
fontSize: 16.0, color: Theme.of(context).hintColor))),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(right: 40, top: 10),
|
||||
child: AnnotatedEditableText(
|
||||
child: ValidableAnnotatedEditableText(
|
||||
cursorColor: Colors.blue,
|
||||
backgroundCursorColor: Colors.blue,
|
||||
style: TextStyle(
|
||||
validStyle: TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
backgroundColor: Colors.transparent,
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: 16),
|
||||
invalidStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.red,
|
||||
fontWeight: FontWeight.normal,
|
||||
|
@ -101,7 +106,7 @@ class SeedWidgetState extends State<SeedWidget> {
|
|||
width: 34,
|
||||
height: 34,
|
||||
child: InkWell(
|
||||
onTap: () async => _pasteAddress(),
|
||||
onTap: () async => _pasteText(),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
|
@ -122,7 +127,7 @@ class SeedWidgetState extends State<SeedWidget> {
|
|||
]));
|
||||
}
|
||||
|
||||
Future<void> _pasteAddress() async {
|
||||
Future<void> _pasteText() async {
|
||||
final value = await Clipboard.getData('text/plain');
|
||||
|
||||
if (value?.text?.isNotEmpty ?? false) {
|
||||
|
|
172
lib/src/widgets/validable_annotated_editable_text.dart
Normal file
172
lib/src/widgets/validable_annotated_editable_text.dart
Normal file
|
@ -0,0 +1,172 @@
|
|||
import 'package:cake_wallet/core/seed_validator.dart';
|
||||
import 'package:cake_wallet/entities/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class Annotation extends Comparable<Annotation> {
|
||||
Annotation({@required this.range, this.style});
|
||||
|
||||
final TextRange range;
|
||||
final TextStyle style;
|
||||
|
||||
@override
|
||||
int compareTo(Annotation other) => range.start.compareTo(other.range.start);
|
||||
}
|
||||
|
||||
class TextAnnotation extends Comparable<TextAnnotation> {
|
||||
TextAnnotation({@required this.text, this.style});
|
||||
|
||||
final TextStyle style;
|
||||
final String text;
|
||||
|
||||
@override
|
||||
int compareTo(TextAnnotation other) => text.compareTo(other.text);
|
||||
}
|
||||
|
||||
class ValidableAnnotatedEditableText extends EditableText {
|
||||
ValidableAnnotatedEditableText({
|
||||
Key key,
|
||||
FocusNode focusNode,
|
||||
TextEditingController controller,
|
||||
List<String> wordList,
|
||||
ValueChanged<String> onChanged,
|
||||
ValueChanged<String> onSubmitted,
|
||||
Color cursorColor,
|
||||
Color selectionColor,
|
||||
Color backgroundCursorColor,
|
||||
TextSelectionControls selectionControls,
|
||||
this.validStyle,
|
||||
this.invalidStyle,
|
||||
TextStyle textStyle = const TextStyle(
|
||||
color: Colors.black,
|
||||
backgroundColor: Colors.transparent,
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: 16),
|
||||
@required this.words,
|
||||
}) : super(
|
||||
maxLines: null,
|
||||
key: key,
|
||||
focusNode: focusNode,
|
||||
controller: controller,
|
||||
cursorColor: cursorColor,
|
||||
style: validStyle,
|
||||
keyboardType: TextInputType.text,
|
||||
autocorrect: false,
|
||||
autofocus: false,
|
||||
selectionColor: selectionColor,
|
||||
selectionControls: selectionControls,
|
||||
backgroundCursorColor: backgroundCursorColor,
|
||||
onChanged: onChanged,
|
||||
onSubmitted: onSubmitted,
|
||||
toolbarOptions: const ToolbarOptions(
|
||||
copy: true,
|
||||
cut: true,
|
||||
paste: true,
|
||||
selectAll: true,
|
||||
),
|
||||
enableSuggestions: false,
|
||||
enableInteractiveSelection: true,
|
||||
showSelectionHandles: true,
|
||||
showCursor: true);
|
||||
|
||||
final List<String> words;
|
||||
final TextStyle validStyle;
|
||||
final TextStyle invalidStyle;
|
||||
|
||||
@override
|
||||
ValidableAnnotatedEditableTextState createState() => ValidableAnnotatedEditableTextState();
|
||||
}
|
||||
|
||||
class ValidableAnnotatedEditableTextState extends EditableTextState {
|
||||
@override
|
||||
ValidableAnnotatedEditableText get widget => super.widget as ValidableAnnotatedEditableText;
|
||||
|
||||
List<Annotation> getRanges() {
|
||||
final result = List<Annotation>();
|
||||
final text = textEditingValue.text;
|
||||
final source = text
|
||||
.split(' ')
|
||||
.map((word) {
|
||||
final ranges = range(word, text);
|
||||
final isValid = validate(word);
|
||||
|
||||
return ranges.map((range) => Annotation(
|
||||
style: isValid ? widget.validStyle : widget.invalidStyle,
|
||||
range: range));
|
||||
})
|
||||
.expand((e) => e)
|
||||
.toList();
|
||||
source.sort();
|
||||
Annotation prev;
|
||||
|
||||
for (var item in source) {
|
||||
Annotation annotation;
|
||||
|
||||
if (prev == null) {
|
||||
annotation = Annotation(
|
||||
range: TextRange(start: 0, end: item.range.start),
|
||||
style: TextStyle(
|
||||
color: Colors.black, backgroundColor: Colors.transparent));
|
||||
} else if (prev.range.end < item.range.start) {
|
||||
annotation = Annotation(
|
||||
range: TextRange(start: prev.range.end, end: item.range.start),
|
||||
style: TextStyle(
|
||||
color: Colors.red, backgroundColor: Colors.transparent));
|
||||
}
|
||||
|
||||
if (annotation != null) {
|
||||
result.add(annotation);
|
||||
result.add(item);
|
||||
prev = item;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.length > 0 && result.last.range.end < text.length) {
|
||||
result.add(Annotation(
|
||||
range: TextRange(start: result.last.range.end, end: text.length),
|
||||
style: TextStyle(backgroundColor: Colors.transparent)));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool validate(String source) => widget.words.indexOf(source) >= 0;
|
||||
|
||||
List<TextRange> range(String pattern, String source) {
|
||||
final result = List<TextRange>();
|
||||
|
||||
if (pattern.isEmpty || source.isEmpty) {
|
||||
return result;
|
||||
}
|
||||
|
||||
for (int index = source.indexOf(pattern);
|
||||
index >= 0;
|
||||
index = source.indexOf(pattern, index + 1)) {
|
||||
final start = index;
|
||||
final end = start + pattern.length;
|
||||
result.add(TextRange(start: start, end: end));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@override
|
||||
TextSpan buildTextSpan() {
|
||||
final text = textEditingValue.text;
|
||||
final ranges = getRanges().toSet();
|
||||
|
||||
print('text $text');
|
||||
|
||||
if (ranges.isNotEmpty) {
|
||||
return TextSpan(
|
||||
style: widget.style,
|
||||
children: ranges.map((item) {
|
||||
final _text = item.range.textInside(text);
|
||||
print(
|
||||
'_text $_text; range ${item.range.start} : ${item.range.end}');
|
||||
return TextSpan(style: item.style, text: _text);
|
||||
}).toList());
|
||||
}
|
||||
|
||||
return TextSpan(style: widget.style, text: text);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue