avoid multiple selection on border wallets grid, display word number, clarify recovery phrase purpose on pdf

This commit is contained in:
Craig Raw 2023-05-30 14:01:45 +02:00
parent 29b630f6bf
commit 2a542bb8b9
3 changed files with 46 additions and 21 deletions

View file

@ -10,22 +10,20 @@ import javafx.beans.property.SimpleBooleanProperty;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener; import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.event.Event;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.control.*; import javafx.scene.control.*;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPane;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.FileChooser; import javafx.stage.FileChooser;
import org.controlsfx.control.spreadsheet.*; import org.controlsfx.control.spreadsheet.*;
import org.controlsfx.glyphfont.Glyph; import org.controlsfx.glyphfont.Glyph;
import org.controlsfx.tools.Platform;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -41,7 +39,7 @@ public class MnemonicGridDialog extends Dialog<List<String>> {
private final BooleanProperty initializedProperty = new SimpleBooleanProperty(false); private final BooleanProperty initializedProperty = new SimpleBooleanProperty(false);
private final BooleanProperty wordsSelectedProperty = new SimpleBooleanProperty(false); private final BooleanProperty wordsSelectedProperty = new SimpleBooleanProperty(false);
private final List<TablePosition> selectedCells = new ArrayList<>(); private final ObservableList<TablePosition> selectedCells = FXCollections.observableArrayList();
public MnemonicGridDialog() { public MnemonicGridDialog() {
DialogPane dialogPane = new MnemonicGridDialogPane(); DialogPane dialogPane = new MnemonicGridDialogPane();
@ -49,7 +47,7 @@ public class MnemonicGridDialog extends Dialog<List<String>> {
setTitle("Border Wallets Grid"); setTitle("Border Wallets Grid");
dialogPane.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm()); dialogPane.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
dialogPane.getStylesheets().add(AppServices.class.getResource("grid.css").toExternalForm()); dialogPane.getStylesheets().add(AppServices.class.getResource("grid.css").toExternalForm());
dialogPane.setHeaderText("Load a Border Wallets PDF, or generate a grid from a BIP39 seed.\nThen select 11 or 23 words in a pattern on the grid, one at a time (do not drag).\nThe order of selection is important!"); dialogPane.setHeaderText("Load a Border Wallets PDF, or generate a grid from a BIP39 seed.\nThen select 11 or 23 words in a pattern on the grid.\nThe order of selection is important!");
javafx.scene.image.Image image = new Image("/image/border-wallets.png"); javafx.scene.image.Image image = new Image("/image/border-wallets.png");
dialogPane.setGraphic(new ImageView(image)); dialogPane.setGraphic(new ImageView(image));
@ -57,37 +55,56 @@ public class MnemonicGridDialog extends Dialog<List<String>> {
Grid grid = getGrid(emptyWordGrid); Grid grid = getGrid(emptyWordGrid);
spreadsheetView = new SpreadsheetView(grid); spreadsheetView = new SpreadsheetView(grid);
spreadsheetView.addEventFilter(MouseEvent.MOUSE_PRESSED, event -> {
try {
Field f = event.getClass().getDeclaredField(Platform.getCurrent() == Platform.OSX ? "metaDown" : "controlDown");
f.setAccessible(true);
f.set(event, true);
} catch(IllegalAccessException | NoSuchFieldException e) {
//ignore
}
});
spreadsheetView.setId("grid"); spreadsheetView.setId("grid");
spreadsheetView.setEditable(false); spreadsheetView.setEditable(false);
spreadsheetView.setFixingColumnsAllowed(false); spreadsheetView.setFixingColumnsAllowed(false);
spreadsheetView.setFixingRowsAllowed(false); spreadsheetView.setFixingRowsAllowed(false);
spreadsheetView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
spreadsheetView.getSelectionModel().getSelectedCells().addListener(new ListChangeListener<>() { spreadsheetView.getSelectionModel().getSelectedCells().addListener(new ListChangeListener<>() {
@Override @Override
public void onChanged(Change<? extends TablePosition> c) { public void onChanged(Change<? extends TablePosition> c) {
while(c.next()) { while(c.next()) {
if(c.wasRemoved()) {
selectedCells.removeAll(c.getRemoved());
}
if(c.wasAdded()) { if(c.wasAdded()) {
selectedCells.addAll(c.getAddedSubList()); for(TablePosition<?, ?> pos : c.getAddedSubList()) {
if(selectedCells.contains(pos)) {
selectedCells.remove(pos);
} else {
selectedCells.add(pos);
}
}
} }
} }
int numWords = c.getList().size(); int numWords = selectedCells.size();
wordsSelectedProperty.set(numWords == 11 || numWords == 23); wordsSelectedProperty.set(numWords == 11 || numWords == 23);
} }
}); });
selectedCells.addListener((ListChangeListener<? super TablePosition>) c -> {
while(c.next()) {
if(c.wasRemoved()) {
for(TablePosition<?,?> pos : c.getRemoved()) {
SpreadsheetCell cell = spreadsheetView.getGrid().getRows().get(pos.getRow()).get(pos.getColumn());
cell.getStyleClass().remove("selection");
cell.setGraphic(null);
}
}
if(c.wasAdded()) {
for(TablePosition<?,?> pos : c.getAddedSubList()) {
SpreadsheetCell cell = spreadsheetView.getGrid().getRows().get(pos.getRow()).get(pos.getColumn());
cell.getStyleClass().add("selection");
}
}
for(int i = 0; i < selectedCells.size(); i++) {
Text index = new Text(Integer.toString(i+1));
index.setFont(Font.font(8));
SpreadsheetCell cell = spreadsheetView.getGrid().getRows().get(selectedCells.get(i).getRow()).get(selectedCells.get(i).getColumn());
cell.setGraphic(index);
}
}
});
StackPane stackPane = new StackPane(); StackPane stackPane = new StackPane();
stackPane.getChildren().add(spreadsheetView); stackPane.getChildren().add(spreadsheetView);
dialogPane.setContent(stackPane); dialogPane.setContent(stackPane);

View file

@ -157,7 +157,7 @@ public class PdfUtils {
Font headerFont = new Font(Font.HELVETICA, 8, Font.BOLD, Color.DARK_GRAY); Font headerFont = new Font(Font.HELVETICA, 8, Font.BOLD, Color.DARK_GRAY);
Font font = new Font(Font.HELVETICA, 8, Font.NORMAL, Color.DARK_GRAY); Font font = new Font(Font.HELVETICA, 8, Font.NORMAL, Color.DARK_GRAY);
HeaderFooter footer = new HeaderFooter(false, new Phrase("Recovery Phrase: " + String.join(" ", mnemonicWords), font)); HeaderFooter footer = new HeaderFooter(false, new Phrase("Recovery Phrase (to regenerate grid): " + String.join(" ", mnemonicWords), font));
footer.setAlignment(Element.ALIGN_CENTER); footer.setAlignment(Element.ALIGN_CENTER);
footer.setBorder(Rectangle.NO_BORDER); footer.setBorder(Rectangle.NO_BORDER);
footer.setBorderWidth(0); footer.setBorderWidth(0);

View file

@ -1,5 +1,13 @@
#grid .spreadsheet-cell:selected, #grid .spreadsheet-cell:selected,
#grid .spreadsheet-cell:focused:selected, #grid .spreadsheet-cell:focused:selected,
#grid .spreadsheet-cell:focused:selected:hover { #grid .spreadsheet-cell:focused:selected:hover {
-fx-background-color: transparent;
}
#grid .spreadsheet-cell.selection:selected,
#grid .spreadsheet-cell.selection:focused:selected,
#grid .spreadsheet-cell.selection:focused:selected:hover,
#grid .spreadsheet-cell.selection {
-fx-background-color: rgb(238, 210, 2); -fx-background-color: rgb(238, 210, 2);
-fx-content-display: RIGHT;
} }