mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-25 05:06:45 +00:00
fix webcam opening/closing issues, display progress bar for qr animation scanning progress
This commit is contained in:
parent
b74741bccb
commit
11a201b3f5
3 changed files with 55 additions and 13 deletions
|
@ -51,7 +51,7 @@ dependencies {
|
||||||
implementation('com.github.arteam:simple-json-rpc-server:1.0') {
|
implementation('com.github.arteam:simple-json-rpc-server:1.0') {
|
||||||
exclude group: 'org.slf4j'
|
exclude group: 'org.slf4j'
|
||||||
}
|
}
|
||||||
implementation('com.sparrowwallet:hummingbird:1.5.2')
|
implementation('com.sparrowwallet:hummingbird:1.5.3')
|
||||||
implementation('com.nativelibs4java:bridj:0.7-20140918-3') {
|
implementation('com.nativelibs4java:bridj:0.7-20140918-3') {
|
||||||
exclude group: 'com.google.android.tools', module: 'dx'
|
exclude group: 'com.google.android.tools', module: 'dx'
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,13 +28,16 @@ import com.sparrowwallet.sparrow.AppServices;
|
||||||
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
||||||
import com.sparrowwallet.sparrow.io.Config;
|
import com.sparrowwallet.sparrow.io.Config;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
import javafx.beans.property.DoubleProperty;
|
||||||
import javafx.beans.property.ObjectProperty;
|
import javafx.beans.property.ObjectProperty;
|
||||||
|
import javafx.beans.property.SimpleDoubleProperty;
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
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.geometry.Insets;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.*;
|
||||||
import org.controlsfx.glyphfont.Glyph;
|
import org.controlsfx.glyphfont.Glyph;
|
||||||
import org.controlsfx.tools.Borders;
|
import org.controlsfx.tools.Borders;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -59,13 +62,14 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
private final WebcamService webcamService;
|
private final WebcamService webcamService;
|
||||||
private List<String> parts;
|
private List<String> parts;
|
||||||
|
|
||||||
private boolean isUr;
|
|
||||||
private QRScanDialog.Result result;
|
private QRScanDialog.Result 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);
|
private final ObjectProperty<WebcamResolution> webcamResolutionProperty = new SimpleObjectProperty<>(WebcamResolution.VGA);
|
||||||
|
|
||||||
|
private final DoubleProperty percentComplete = new SimpleDoubleProperty(0.0);
|
||||||
|
|
||||||
public QRScanDialog() {
|
public QRScanDialog() {
|
||||||
this.decoder = new URDecoder();
|
this.decoder = new URDecoder();
|
||||||
this.legacyDecoder = new LegacyURDecoder();
|
this.legacyDecoder = new LegacyURDecoder();
|
||||||
|
@ -83,8 +87,23 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
|
|
||||||
StackPane stackPane = new StackPane();
|
StackPane stackPane = new StackPane();
|
||||||
stackPane.getChildren().add(webcamView.getView());
|
stackPane.getChildren().add(webcamView.getView());
|
||||||
|
Node wrappedView = Borders.wrap(stackPane).lineBorder().buildAll();
|
||||||
|
|
||||||
dialogPane.setContent(Borders.wrap(stackPane).lineBorder().buildAll());
|
ProgressBar progressBar = new ProgressBar();
|
||||||
|
progressBar.setMinHeight(20);
|
||||||
|
progressBar.setPadding(new Insets(0, 10, 0, 10));
|
||||||
|
progressBar.setPrefWidth(Integer.MAX_VALUE);
|
||||||
|
progressBar.progressProperty().bind(percentComplete);
|
||||||
|
webcamService.openingProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
if(percentComplete.get() <= 0.0) {
|
||||||
|
Platform.runLater(() -> percentComplete.set(newValue ? 0.0 : -1.0));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
VBox vBox = new VBox(20);
|
||||||
|
vBox.getChildren().addAll(wrappedView, progressBar);
|
||||||
|
|
||||||
|
dialogPane.setContent(vBox);
|
||||||
|
|
||||||
webcamService.resultProperty().addListener(new QRResultListener());
|
webcamService.resultProperty().addListener(new QRResultListener());
|
||||||
webcamService.setOnFailed(failedEvent -> {
|
webcamService.setOnFailed(failedEvent -> {
|
||||||
|
@ -111,7 +130,7 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
final ButtonType hdButtonType = new javafx.scene.control.ButtonType("Use HD Capture", ButtonBar.ButtonData.LEFT);
|
final ButtonType hdButtonType = new javafx.scene.control.ButtonType("Use HD Capture", ButtonBar.ButtonData.LEFT);
|
||||||
dialogPane.getButtonTypes().addAll(hdButtonType, cancelButtonType);
|
dialogPane.getButtonTypes().addAll(hdButtonType, cancelButtonType);
|
||||||
dialogPane.setPrefWidth(646);
|
dialogPane.setPrefWidth(646);
|
||||||
dialogPane.setPrefHeight(webcamResolutionProperty.get() == WebcamResolution.HD ? 450 : 550);
|
dialogPane.setPrefHeight(webcamResolutionProperty.get() == WebcamResolution.HD ? 490 : 590);
|
||||||
|
|
||||||
setResultConverter(dialogButton -> dialogButton != cancelButtonType ? result : null);
|
setResultConverter(dialogButton -> dialogButton != cancelButtonType ? result : null);
|
||||||
}
|
}
|
||||||
|
@ -127,11 +146,10 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
String qrtext = qrResult.getText();
|
String qrtext = qrResult.getText();
|
||||||
Matcher partMatcher = PART_PATTERN.matcher(qrtext);
|
Matcher partMatcher = PART_PATTERN.matcher(qrtext);
|
||||||
|
|
||||||
if(isUr || qrtext.toLowerCase().startsWith(UR.UR_PREFIX)) {
|
if(qrtext.toLowerCase().startsWith(UR.UR_PREFIX)) {
|
||||||
isUr = true;
|
if(LegacyURDecoder.isLegacyURFragment(qrtext.toLowerCase())) {
|
||||||
|
|
||||||
if(LegacyURDecoder.isLegacyURFragment(qrtext)) {
|
|
||||||
legacyDecoder.receivePart(qrtext.toLowerCase());
|
legacyDecoder.receivePart(qrtext.toLowerCase());
|
||||||
|
Platform.runLater(() -> percentComplete.setValue(legacyDecoder.getPercentComplete()));
|
||||||
|
|
||||||
if(legacyDecoder.isComplete()) {
|
if(legacyDecoder.isComplete()) {
|
||||||
try {
|
try {
|
||||||
|
@ -143,6 +161,7 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
decoder.receivePart(qrtext);
|
decoder.receivePart(qrtext);
|
||||||
|
Platform.runLater(() -> percentComplete.setValue(decoder.getEstimatedPercentComplete()));
|
||||||
|
|
||||||
if(decoder.getResult() != null) {
|
if(decoder.getResult() != null) {
|
||||||
URDecoder.Result urResult = decoder.getResult();
|
URDecoder.Result urResult = decoder.getResult();
|
||||||
|
@ -164,6 +183,10 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
}
|
}
|
||||||
parts.set(m - 1, payload);
|
parts.set(m - 1, payload);
|
||||||
|
|
||||||
|
if(n > 0) {
|
||||||
|
Platform.runLater(() -> percentComplete.setValue((double)parts.stream().filter(Objects::nonNull).count() / n));
|
||||||
|
}
|
||||||
|
|
||||||
if(parts.stream().filter(Objects::nonNull).count() == n) {
|
if(parts.stream().filter(Objects::nonNull).count() == n) {
|
||||||
String complete = String.join("", parts);
|
String complete = String.join("", parts);
|
||||||
try {
|
try {
|
||||||
|
@ -484,6 +507,7 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
private class QRScanDialogPane extends DialogPane {
|
private class QRScanDialogPane extends DialogPane {
|
||||||
@Override
|
@Override
|
||||||
protected Node createButton(ButtonType buttonType) {
|
protected Node createButton(ButtonType buttonType) {
|
||||||
|
Node button = null;
|
||||||
if(buttonType.getButtonData() == ButtonBar.ButtonData.LEFT) {
|
if(buttonType.getButtonData() == ButtonBar.ButtonData.LEFT) {
|
||||||
ToggleButton hd = new ToggleButton(buttonType.getText());
|
ToggleButton hd = new ToggleButton(buttonType.getText());
|
||||||
hd.setSelected(webcamResolutionProperty.get() == WebcamResolution.HD);
|
hd.setSelected(webcamResolutionProperty.get() == WebcamResolution.HD);
|
||||||
|
@ -497,10 +521,13 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
setHdGraphic(hd, newValue);
|
setHdGraphic(hd, newValue);
|
||||||
});
|
});
|
||||||
|
|
||||||
return hd;
|
button = hd;
|
||||||
|
} else {
|
||||||
|
button = super.createButton(buttonType);
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.createButton(buttonType);
|
button.disableProperty().bind(webcamService.openingProperty());
|
||||||
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setHdGraphic(ToggleButton hd, boolean isHd) {
|
private void setHdGraphic(ToggleButton hd, boolean isHd) {
|
||||||
|
|
|
@ -6,7 +6,9 @@ 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;
|
||||||
import com.google.zxing.common.HybridBinarizer;
|
import com.google.zxing.common.HybridBinarizer;
|
||||||
|
import javafx.beans.property.BooleanProperty;
|
||||||
import javafx.beans.property.ObjectProperty;
|
import javafx.beans.property.ObjectProperty;
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
import javafx.concurrent.Service;
|
import javafx.concurrent.Service;
|
||||||
import javafx.concurrent.Task;
|
import javafx.concurrent.Task;
|
||||||
|
@ -20,6 +22,7 @@ import java.util.concurrent.TimeUnit;
|
||||||
public class WebcamService extends Service<Image> {
|
public class WebcamService extends Service<Image> {
|
||||||
private WebcamResolution resolution;
|
private WebcamResolution resolution;
|
||||||
private final WebcamListener listener;
|
private final WebcamListener listener;
|
||||||
|
private BooleanProperty opening = new SimpleBooleanProperty(false);
|
||||||
|
|
||||||
private final ObjectProperty<Result> resultProperty = new SimpleObjectProperty<>(null);
|
private final ObjectProperty<Result> resultProperty = new SimpleObjectProperty<>(null);
|
||||||
|
|
||||||
|
@ -41,7 +44,9 @@ public class WebcamService extends Service<Image> {
|
||||||
cam.addWebcamListener(listener);
|
cam.addWebcamListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
opening.set(true);
|
||||||
cam.open();
|
cam.open();
|
||||||
|
opening.set(false);
|
||||||
while(!isCancelled()) {
|
while(!isCancelled()) {
|
||||||
if(cam.isImageNew()) {
|
if(cam.isImageNew()) {
|
||||||
BufferedImage bimg = cam.getImage();
|
BufferedImage bimg = cam.getImage();
|
||||||
|
@ -49,12 +54,14 @@ public class WebcamService extends Service<Image> {
|
||||||
readQR(bimg);
|
readQR(bimg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cam.close();
|
|
||||||
return getValue();
|
return getValue();
|
||||||
} finally {
|
} finally {
|
||||||
|
opening.set(false);
|
||||||
|
if(!cam.close()) {
|
||||||
cam.close();
|
cam.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,4 +96,12 @@ public class WebcamService extends Service<Image> {
|
||||||
public void setResolution(WebcamResolution resolution) {
|
public void setResolution(WebcamResolution resolution) {
|
||||||
this.resolution = resolution;
|
this.resolution = resolution;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isOpening() {
|
||||||
|
return opening.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BooleanProperty openingProperty() {
|
||||||
|
return opening;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue