mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-24 12:46: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') {
|
||||
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') {
|
||||
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.io.Config;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.DoubleProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleDoubleProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.layout.*;
|
||||
import org.controlsfx.glyphfont.Glyph;
|
||||
import org.controlsfx.tools.Borders;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -59,13 +62,14 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
|||
private final WebcamService webcamService;
|
||||
private List<String> parts;
|
||||
|
||||
private boolean isUr;
|
||||
private QRScanDialog.Result result;
|
||||
|
||||
private static final Pattern PART_PATTERN = Pattern.compile("p(\\d+)of(\\d+) (.+)");
|
||||
|
||||
private final ObjectProperty<WebcamResolution> webcamResolutionProperty = new SimpleObjectProperty<>(WebcamResolution.VGA);
|
||||
|
||||
private final DoubleProperty percentComplete = new SimpleDoubleProperty(0.0);
|
||||
|
||||
public QRScanDialog() {
|
||||
this.decoder = new URDecoder();
|
||||
this.legacyDecoder = new LegacyURDecoder();
|
||||
|
@ -83,8 +87,23 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
|||
|
||||
StackPane stackPane = new StackPane();
|
||||
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.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);
|
||||
dialogPane.getButtonTypes().addAll(hdButtonType, cancelButtonType);
|
||||
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);
|
||||
}
|
||||
|
@ -127,11 +146,10 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
|||
String qrtext = qrResult.getText();
|
||||
Matcher partMatcher = PART_PATTERN.matcher(qrtext);
|
||||
|
||||
if(isUr || qrtext.toLowerCase().startsWith(UR.UR_PREFIX)) {
|
||||
isUr = true;
|
||||
|
||||
if(LegacyURDecoder.isLegacyURFragment(qrtext)) {
|
||||
if(qrtext.toLowerCase().startsWith(UR.UR_PREFIX)) {
|
||||
if(LegacyURDecoder.isLegacyURFragment(qrtext.toLowerCase())) {
|
||||
legacyDecoder.receivePart(qrtext.toLowerCase());
|
||||
Platform.runLater(() -> percentComplete.setValue(legacyDecoder.getPercentComplete()));
|
||||
|
||||
if(legacyDecoder.isComplete()) {
|
||||
try {
|
||||
|
@ -143,6 +161,7 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
|||
}
|
||||
} else {
|
||||
decoder.receivePart(qrtext);
|
||||
Platform.runLater(() -> percentComplete.setValue(decoder.getEstimatedPercentComplete()));
|
||||
|
||||
if(decoder.getResult() != null) {
|
||||
URDecoder.Result urResult = decoder.getResult();
|
||||
|
@ -164,6 +183,10 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
|||
}
|
||||
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) {
|
||||
String complete = String.join("", parts);
|
||||
try {
|
||||
|
@ -484,6 +507,7 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
|||
private class QRScanDialogPane extends DialogPane {
|
||||
@Override
|
||||
protected Node createButton(ButtonType buttonType) {
|
||||
Node button = null;
|
||||
if(buttonType.getButtonData() == ButtonBar.ButtonData.LEFT) {
|
||||
ToggleButton hd = new ToggleButton(buttonType.getText());
|
||||
hd.setSelected(webcamResolutionProperty.get() == WebcamResolution.HD);
|
||||
|
@ -497,10 +521,13 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
|||
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) {
|
||||
|
|
|
@ -6,7 +6,9 @@ import com.github.sarxos.webcam.WebcamResolution;
|
|||
import com.google.zxing.*;
|
||||
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
|
||||
import com.google.zxing.common.HybridBinarizer;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.concurrent.Service;
|
||||
import javafx.concurrent.Task;
|
||||
|
@ -20,6 +22,7 @@ import java.util.concurrent.TimeUnit;
|
|||
public class WebcamService extends Service<Image> {
|
||||
private WebcamResolution resolution;
|
||||
private final WebcamListener listener;
|
||||
private BooleanProperty opening = new SimpleBooleanProperty(false);
|
||||
|
||||
private final ObjectProperty<Result> resultProperty = new SimpleObjectProperty<>(null);
|
||||
|
||||
|
@ -41,7 +44,9 @@ public class WebcamService extends Service<Image> {
|
|||
cam.addWebcamListener(listener);
|
||||
}
|
||||
|
||||
opening.set(true);
|
||||
cam.open();
|
||||
opening.set(false);
|
||||
while(!isCancelled()) {
|
||||
if(cam.isImageNew()) {
|
||||
BufferedImage bimg = cam.getImage();
|
||||
|
@ -49,10 +54,12 @@ public class WebcamService extends Service<Image> {
|
|||
readQR(bimg);
|
||||
}
|
||||
}
|
||||
cam.close();
|
||||
return getValue();
|
||||
} finally {
|
||||
cam.close();
|
||||
opening.set(false);
|
||||
if(!cam.close()) {
|
||||
cam.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -89,4 +96,12 @@ public class WebcamService extends Service<Image> {
|
|||
public void setResolution(WebcamResolution resolution) {
|
||||
this.resolution = resolution;
|
||||
}
|
||||
|
||||
public boolean isOpening() {
|
||||
return opening.get();
|
||||
}
|
||||
|
||||
public BooleanProperty openingProperty() {
|
||||
return opening;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue