mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-25 05:06:45 +00:00
add hd capture toggle for qr scanning
This commit is contained in:
parent
aacecc8517
commit
ff83af2e0d
3 changed files with 130 additions and 12 deletions
|
@ -1,5 +1,7 @@
|
||||||
package com.sparrowwallet.sparrow.control;
|
package com.sparrowwallet.sparrow.control;
|
||||||
|
|
||||||
|
import com.github.sarxos.webcam.WebcamEvent;
|
||||||
|
import com.github.sarxos.webcam.WebcamListener;
|
||||||
import com.github.sarxos.webcam.WebcamResolution;
|
import com.github.sarxos.webcam.WebcamResolution;
|
||||||
import com.sparrowwallet.drongo.ExtendedKey;
|
import com.sparrowwallet.drongo.ExtendedKey;
|
||||||
import com.sparrowwallet.drongo.KeyDerivation;
|
import com.sparrowwallet.drongo.KeyDerivation;
|
||||||
|
@ -23,14 +25,17 @@ import com.sparrowwallet.hummingbird.ResultType;
|
||||||
import com.sparrowwallet.hummingbird.UR;
|
import com.sparrowwallet.hummingbird.UR;
|
||||||
import com.sparrowwallet.hummingbird.URDecoder;
|
import com.sparrowwallet.hummingbird.URDecoder;
|
||||||
import com.sparrowwallet.sparrow.AppServices;
|
import com.sparrowwallet.sparrow.AppServices;
|
||||||
|
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
||||||
|
import com.sparrowwallet.sparrow.io.Config;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
import javafx.beans.property.ObjectProperty;
|
||||||
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
import javafx.beans.value.ChangeListener;
|
import javafx.beans.value.ChangeListener;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
import javafx.scene.control.ButtonBar;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.ButtonType;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.control.Dialog;
|
|
||||||
import javafx.scene.control.DialogPane;
|
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
|
import org.controlsfx.glyphfont.Glyph;
|
||||||
import org.controlsfx.tools.Borders;
|
import org.controlsfx.tools.Borders;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -40,6 +45,7 @@ import java.nio.CharBuffer;
|
||||||
import java.nio.charset.CharsetDecoder;
|
import java.nio.charset.CharsetDecoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.List;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
@ -58,14 +64,21 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
|
|
||||||
private static final Pattern PART_PATTERN = Pattern.compile("p(\\d+)of(\\d+) (.+)");
|
private static final Pattern PART_PATTERN = Pattern.compile("p(\\d+)of(\\d+) (.+)");
|
||||||
|
|
||||||
|
private final ObjectProperty<WebcamResolution> webcamResolutionProperty = new SimpleObjectProperty<>(WebcamResolution.VGA);
|
||||||
|
|
||||||
public QRScanDialog() {
|
public QRScanDialog() {
|
||||||
this.decoder = new URDecoder();
|
this.decoder = new URDecoder();
|
||||||
this.legacyDecoder = new LegacyURDecoder();
|
this.legacyDecoder = new LegacyURDecoder();
|
||||||
|
|
||||||
this.webcamService = new WebcamService(WebcamResolution.VGA);
|
if(Config.get().isHdCapture()) {
|
||||||
|
webcamResolutionProperty.set(WebcamResolution.HD);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.webcamService = new WebcamService(webcamResolutionProperty.get(), new QRScanListener());
|
||||||
WebcamView webcamView = new WebcamView(webcamService);
|
WebcamView webcamView = new WebcamView(webcamService);
|
||||||
|
|
||||||
final DialogPane dialogPane = getDialogPane();
|
final DialogPane dialogPane = new QRScanDialogPane();
|
||||||
|
setDialogPane(dialogPane);
|
||||||
AppServices.setStageIcon(dialogPane.getScene().getWindow());
|
AppServices.setStageIcon(dialogPane.getScene().getWindow());
|
||||||
|
|
||||||
StackPane stackPane = new StackPane();
|
StackPane stackPane = new StackPane();
|
||||||
|
@ -78,14 +91,27 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
Platform.runLater(() -> setResult(new Result(failedEvent.getSource().getException())));
|
Platform.runLater(() -> setResult(new Result(failedEvent.getSource().getException())));
|
||||||
});
|
});
|
||||||
webcamService.start();
|
webcamService.start();
|
||||||
|
webcamResolutionProperty.addListener((observable, oldValue, newResolution) -> {
|
||||||
|
if(newResolution != null) {
|
||||||
|
setHeight(newResolution == WebcamResolution.HD ? (getHeight() - 100) : (getHeight() + 100));
|
||||||
|
}
|
||||||
|
webcamService.cancel();
|
||||||
|
});
|
||||||
|
|
||||||
setOnCloseRequest(event -> {
|
setOnCloseRequest(event -> {
|
||||||
Platform.runLater(webcamService::cancel);
|
boolean isHdCapture = (webcamResolutionProperty.get() == WebcamResolution.HD);
|
||||||
|
if(Config.get().isHdCapture() != isHdCapture) {
|
||||||
|
Config.get().setHdCapture(isHdCapture);
|
||||||
|
}
|
||||||
|
|
||||||
|
Platform.runLater(() -> webcamResolutionProperty.set(null));
|
||||||
});
|
});
|
||||||
|
|
||||||
final ButtonType cancelButtonType = new javafx.scene.control.ButtonType("Cancel", ButtonBar.ButtonData.CANCEL_CLOSE);
|
final ButtonType cancelButtonType = new javafx.scene.control.ButtonType("Cancel", ButtonBar.ButtonData.CANCEL_CLOSE);
|
||||||
dialogPane.getButtonTypes().addAll(cancelButtonType);
|
final ButtonType hdButtonType = new javafx.scene.control.ButtonType("Use HD Capture", ButtonBar.ButtonData.LEFT);
|
||||||
dialogPane.setPrefWidth(660);
|
dialogPane.getButtonTypes().addAll(hdButtonType, cancelButtonType);
|
||||||
dialogPane.setPrefHeight(550);
|
dialogPane.setPrefWidth(646);
|
||||||
|
dialogPane.setPrefHeight(webcamResolutionProperty.get() == WebcamResolution.HD ? 450 : 550);
|
||||||
|
|
||||||
setResultConverter(dialogButton -> dialogButton != cancelButtonType ? result : null);
|
setResultConverter(dialogButton -> dialogButton != cancelButtonType ? result : null);
|
||||||
}
|
}
|
||||||
|
@ -425,6 +451,77 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class QRScanListener implements WebcamListener {
|
||||||
|
@Override
|
||||||
|
public void webcamOpen(WebcamEvent webcamEvent) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void webcamClosed(WebcamEvent webcamEvent) {
|
||||||
|
if(webcamResolutionProperty.get() != null) {
|
||||||
|
webcamService.setResolution(webcamResolutionProperty.get());
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
if(!webcamService.isRunning()) {
|
||||||
|
webcamService.reset();
|
||||||
|
webcamService.start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void webcamDisposed(WebcamEvent webcamEvent) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void webcamImageObtained(WebcamEvent webcamEvent) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class QRScanDialogPane extends DialogPane {
|
||||||
|
@Override
|
||||||
|
protected Node createButton(ButtonType buttonType) {
|
||||||
|
if(buttonType.getButtonData() == ButtonBar.ButtonData.LEFT) {
|
||||||
|
ToggleButton hd = new ToggleButton(buttonType.getText());
|
||||||
|
hd.setSelected(webcamResolutionProperty.get() == WebcamResolution.HD);
|
||||||
|
hd.setGraphicTextGap(5);
|
||||||
|
setHdGraphic(hd, hd.isSelected());
|
||||||
|
|
||||||
|
final ButtonBar.ButtonData buttonData = buttonType.getButtonData();
|
||||||
|
ButtonBar.setButtonData(hd, buttonData);
|
||||||
|
hd.selectedProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
webcamResolutionProperty.set(newValue ? WebcamResolution.HD : WebcamResolution.VGA);
|
||||||
|
setHdGraphic(hd, newValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
return hd;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.createButton(buttonType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setHdGraphic(ToggleButton hd, boolean isHd) {
|
||||||
|
if(isHd) {
|
||||||
|
hd.setGraphic(getGlyph(FontAwesome5.Glyph.CHECK_CIRCLE, "success"));
|
||||||
|
} else {
|
||||||
|
hd.setGraphic(getGlyph(FontAwesome5.Glyph.QUESTION_CIRCLE, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Glyph getGlyph(FontAwesome5.Glyph glyphName, String styleClass) {
|
||||||
|
Glyph glyph = new Glyph(FontAwesome5.FONT_NAME, glyphName);
|
||||||
|
glyph.setFontSize(12);
|
||||||
|
if(styleClass != null) {
|
||||||
|
glyph.getStyleClass().add(styleClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
return glyph;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class Result {
|
public static class Result {
|
||||||
public final Transaction transaction;
|
public final Transaction transaction;
|
||||||
public final PSBT psbt;
|
public final PSBT psbt;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.sparrowwallet.sparrow.control;
|
package com.sparrowwallet.sparrow.control;
|
||||||
|
|
||||||
import com.github.sarxos.webcam.Webcam;
|
import com.github.sarxos.webcam.Webcam;
|
||||||
|
import com.github.sarxos.webcam.WebcamListener;
|
||||||
import com.github.sarxos.webcam.WebcamResolution;
|
import com.github.sarxos.webcam.WebcamResolution;
|
||||||
import com.google.zxing.*;
|
import com.google.zxing.*;
|
||||||
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
|
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
|
||||||
|
@ -13,15 +14,18 @@ import javafx.embed.swing.SwingFXUtils;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class WebcamService extends Service<Image> {
|
public class WebcamService extends Service<Image> {
|
||||||
private final WebcamResolution resolution ;
|
private WebcamResolution resolution;
|
||||||
|
private final WebcamListener listener;
|
||||||
|
|
||||||
private final ObjectProperty<Result> resultProperty = new SimpleObjectProperty<>(null);
|
private final ObjectProperty<Result> resultProperty = new SimpleObjectProperty<>(null);
|
||||||
|
|
||||||
public WebcamService(WebcamResolution resolution) {
|
public WebcamService(WebcamResolution resolution, WebcamListener listener) {
|
||||||
this.resolution = resolution;
|
this.resolution = resolution;
|
||||||
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -33,6 +37,9 @@ public class WebcamService extends Service<Image> {
|
||||||
try {
|
try {
|
||||||
cam.setCustomViewSizes(resolution.getSize());
|
cam.setCustomViewSizes(resolution.getSize());
|
||||||
cam.setViewSize(resolution.getSize());
|
cam.setViewSize(resolution.getSize());
|
||||||
|
if(!Arrays.asList(cam.getWebcamListeners()).contains(listener)) {
|
||||||
|
cam.addWebcamListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
cam.open();
|
cam.open();
|
||||||
while(!isCancelled()) {
|
while(!isCancelled()) {
|
||||||
|
@ -78,4 +85,8 @@ public class WebcamService extends Service<Image> {
|
||||||
public int getCamHeight() {
|
public int getCamHeight() {
|
||||||
return resolution.getSize().height;
|
return resolution.getSize().height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setResolution(WebcamResolution resolution) {
|
||||||
|
this.resolution = resolution;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ public class Config {
|
||||||
private List<File> recentWalletFiles;
|
private List<File> recentWalletFiles;
|
||||||
private Integer keyDerivationPeriod;
|
private Integer keyDerivationPeriod;
|
||||||
private File hwi;
|
private File hwi;
|
||||||
|
private boolean hdCapture;
|
||||||
private ServerType serverType;
|
private ServerType serverType;
|
||||||
private String coreServer;
|
private String coreServer;
|
||||||
private CoreAuthType coreAuthType;
|
private CoreAuthType coreAuthType;
|
||||||
|
@ -250,6 +251,15 @@ public class Config {
|
||||||
flush();
|
flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isHdCapture() {
|
||||||
|
return hdCapture;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHdCapture(boolean hdCapture) {
|
||||||
|
this.hdCapture = hdCapture;
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
|
||||||
public ServerType getServerType() {
|
public ServerType getServerType() {
|
||||||
return serverType;
|
return serverType;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue