This commit is contained in:
M 2020-11-04 00:29:06 +02:00
parent 76581505a0
commit 7e33f1ae0a
5 changed files with 188 additions and 165 deletions

View file

@ -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(

View file

@ -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,

View file

@ -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);
}
}

View file

@ -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) {

View 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);
}
}