diff --git a/drongo b/drongo index 7eab644c..fe19c865 160000 --- a/drongo +++ b/drongo @@ -1 +1 @@ -Subproject commit 7eab644cecc71e591ba805cff1a408b9f31a9303 +Subproject commit fe19c86544d75d0ce0d8c32b0cbbd44de64ae463 diff --git a/src/main/java/com/sparrowwallet/sparrow/control/MnemonicKeystorePane.java b/src/main/java/com/sparrowwallet/sparrow/control/MnemonicKeystorePane.java index 9a6bba43..35dc2568 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/MnemonicKeystorePane.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/MnemonicKeystorePane.java @@ -21,7 +21,6 @@ import javafx.scene.input.Clipboard; import javafx.scene.layout.*; import javafx.util.Callback; import org.controlsfx.control.textfield.AutoCompletionBinding; -import org.controlsfx.control.textfield.CustomTextField; import org.controlsfx.control.textfield.TextFields; import org.controlsfx.glyphfont.Glyph; import org.controlsfx.validation.ValidationResult; @@ -250,9 +249,14 @@ public class MnemonicKeystorePane extends TitledDescriptionPane { if(clipboard.hasString() && clipboard.getString().matches("(?m).+[\\n\\s][\\S\\s]*")) { String[] words = clipboard.getString().split("[\\n\\s]"); WordEntry entry = WordEntry.this; - for(String word : words) { + for(int i = 0; i < words.length; i++) { + String word = words[i]; if(entry.nextField != null) { - entry.nextField.requestFocus(); + if(i == words.length - 2 && isValid(word)) { + label.requestFocus(); + } else { + entry.nextField.requestFocus(); + } } entry.wordField.setText(word); @@ -282,7 +286,7 @@ public class MnemonicKeystorePane extends TitledDescriptionPane { wordField.setTextFormatter(formatter); wordList = Bip39MnemonicCode.INSTANCE.getWordList(); - AutoCompletionBinding autoCompletionBinding = TextFields.bindAutoCompletion(wordField, new WordlistSuggestionProvider(wordList)); + AutoCompletionBinding autoCompletionBinding = TextFields.bindAutoCompletion(wordField, new WordlistSuggestionProvider(wordList, wordNumber, wordEntryList)); autoCompletionBinding.setDelay(50); autoCompletionBinding.setOnAutoCompleted(event -> { if(nextField != null) { @@ -290,11 +294,20 @@ public class MnemonicKeystorePane extends TitledDescriptionPane { } }); + //Show autocomplete for the last word on focus if empty + boolean lastWord = wordNumber == wordEntryList.size() - 1; + if(lastWord) { + wordField.focusedProperty().addListener((observable, oldValue, focused) -> { + if(focused && wordField.getText().isEmpty()) { + autoCompletionBinding.setUserInput(""); + } + }); + } + ValidationSupport validationSupport = new ValidationSupport(); validationSupport.setValidationDecorator(new StyleClassValidationDecoration()); validationSupport.registerValidator(wordField, Validator.combine( - Validator.createEmptyValidator("Word is required"), - (Control c, String newValue) -> ValidationResult.fromErrorIf( c, "Invalid word", !wordList.contains(newValue)) + (Control c, String newValue) -> ValidationResult.fromErrorIf( c, "Invalid word", (newValue.length() > 0 || !lastWord) && !wordList.contains(newValue)) )); wordField.textProperty().addListener((observable, oldValue, newValue) -> { @@ -323,13 +336,30 @@ public class MnemonicKeystorePane extends TitledDescriptionPane { protected static class WordlistSuggestionProvider implements Callback> { private final List wordList; + private final int wordNumber; + private final ObservableList wordEntryList; - public WordlistSuggestionProvider(List wordList) { + public WordlistSuggestionProvider(List wordList, int wordNumber, ObservableList wordEntryList) { this.wordList = wordList; + this.wordNumber = wordNumber; + this.wordEntryList = wordEntryList; } @Override public Collection call(AutoCompletionBinding.ISuggestionRequest request) { + if(wordNumber == wordEntryList.size() - 1 && allPreviousWordsValid()) { + try { + List possibleLastWords = Bip39MnemonicCode.INSTANCE.getPossibleLastWords(wordEntryList.subList(0, wordEntryList.size() - 1)); + if(!request.getUserText().isEmpty()) { + possibleLastWords.removeIf(s -> !s.startsWith(request.getUserText())); + } + + return possibleLastWords; + } catch(Exception e) { + log.warn("Cannot determine possible last words", e); + } + } + List suggestions = new ArrayList<>(); if(!request.getUserText().isEmpty()) { for(String word : wordList) { @@ -341,6 +371,16 @@ public class MnemonicKeystorePane extends TitledDescriptionPane { return suggestions; } + + private boolean allPreviousWordsValid() { + for(int i = 0; i < wordEntryList.size() - 1; i++) { + if(!WordEntry.isValid(wordEntryList.get(i))) { + return false; + } + } + + return true; + } } protected class PassphraseEntry extends HBox {