mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-25 05:06:45 +00:00
allow selection of webcam from QR scan dialog
This commit is contained in:
parent
2f153686dd
commit
ada45ee75b
6 changed files with 126 additions and 17 deletions
|
@ -232,7 +232,7 @@ public class QRDisplayDialog extends Dialog<UR> {
|
||||||
if(useLegacyEncoding) {
|
if(useLegacyEncoding) {
|
||||||
legacy.setGraphic(getGlyph(FontAwesome5.Glyph.CHECK_CIRCLE));
|
legacy.setGraphic(getGlyph(FontAwesome5.Glyph.CHECK_CIRCLE));
|
||||||
} else {
|
} else {
|
||||||
legacy.setGraphic(getGlyph(FontAwesome5.Glyph.QUESTION_CIRCLE));
|
legacy.setGraphic(getGlyph(FontAwesome5.Glyph.BAN));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
package com.sparrowwallet.sparrow.control;
|
package com.sparrowwallet.sparrow.control;
|
||||||
|
|
||||||
import com.github.sarxos.webcam.WebcamEvent;
|
import com.github.sarxos.webcam.*;
|
||||||
import com.github.sarxos.webcam.WebcamListener;
|
|
||||||
import com.github.sarxos.webcam.WebcamResolution;
|
|
||||||
import com.github.sarxos.webcam.WebcamUpdater;
|
|
||||||
import com.sparrowwallet.drongo.ExtendedKey;
|
import com.sparrowwallet.drongo.ExtendedKey;
|
||||||
import com.sparrowwallet.drongo.KeyDerivation;
|
import com.sparrowwallet.drongo.KeyDerivation;
|
||||||
import com.sparrowwallet.drongo.OutputDescriptor;
|
import com.sparrowwallet.drongo.OutputDescriptor;
|
||||||
|
@ -41,6 +38,7 @@ import javafx.scene.Node;
|
||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.layout.*;
|
import javafx.scene.layout.*;
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
|
import javafx.util.StringConverter;
|
||||||
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;
|
||||||
|
@ -74,6 +72,8 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
|
|
||||||
private final DoubleProperty percentComplete = new SimpleDoubleProperty(0.0);
|
private final DoubleProperty percentComplete = new SimpleDoubleProperty(0.0);
|
||||||
|
|
||||||
|
private final ObjectProperty<WebcamDevice> webcamDeviceProperty = new SimpleObjectProperty<>();
|
||||||
|
|
||||||
public QRScanDialog() {
|
public QRScanDialog() {
|
||||||
this.decoder = new URDecoder();
|
this.decoder = new URDecoder();
|
||||||
this.legacyDecoder = new LegacyURDecoder();
|
this.legacyDecoder = new LegacyURDecoder();
|
||||||
|
@ -82,7 +82,7 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
webcamResolutionProperty.set(WebcamResolution.HD);
|
webcamResolutionProperty.set(WebcamResolution.HD);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.webcamService = new WebcamService(webcamResolutionProperty.get(), new QRScanListener(), new ScanDelayCalculator());
|
this.webcamService = new WebcamService(webcamResolutionProperty.get(), null, new QRScanListener(), new ScanDelayCalculator());
|
||||||
webcamService.setPeriod(Duration.millis(SCAN_PERIOD_MILLIS));
|
webcamService.setPeriod(Duration.millis(SCAN_PERIOD_MILLIS));
|
||||||
webcamService.setRestartOnFailure(false);
|
webcamService.setRestartOnFailure(false);
|
||||||
WebcamView webcamView = new WebcamView(webcamService);
|
WebcamView webcamView = new WebcamView(webcamService);
|
||||||
|
@ -104,6 +104,15 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
if(percentComplete.get() <= 0.0) {
|
if(percentComplete.get() <= 0.0) {
|
||||||
Platform.runLater(() -> percentComplete.set(newValue ? 0.0 : -1.0));
|
Platform.runLater(() -> percentComplete.set(newValue ? 0.0 : -1.0));
|
||||||
}
|
}
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
if(Config.get().getWebcamDevice() != null && webcamDeviceProperty.get() == null) {
|
||||||
|
for(WebcamDevice device : WebcamScanDriver.getFoundDevices()) {
|
||||||
|
if(device.getName().equals(Config.get().getWebcamDevice())) {
|
||||||
|
webcamDeviceProperty.set(device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
VBox vBox = new VBox(20);
|
VBox vBox = new VBox(20);
|
||||||
|
@ -134,6 +143,12 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
}
|
}
|
||||||
webcamService.cancel();
|
webcamService.cancel();
|
||||||
});
|
});
|
||||||
|
webcamDeviceProperty.addListener((observable, oldValue, newValue) -> {
|
||||||
|
Config.get().setWebcamDevice(newValue.getName());
|
||||||
|
if(!Objects.equals(webcamService.getDevice(), newValue)) {
|
||||||
|
webcamService.cancel();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
setOnCloseRequest(event -> {
|
setOnCloseRequest(event -> {
|
||||||
boolean isHdCapture = (webcamResolutionProperty.get() == WebcamResolution.HD);
|
boolean isHdCapture = (webcamResolutionProperty.get() == WebcamResolution.HD);
|
||||||
|
@ -146,7 +161,8 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
|
|
||||||
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);
|
||||||
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);
|
final ButtonType camButtonType = new javafx.scene.control.ButtonType("Default Camera", ButtonBar.ButtonData.HELP_2);
|
||||||
|
dialogPane.getButtonTypes().addAll(hdButtonType, camButtonType, cancelButtonType);
|
||||||
dialogPane.setPrefWidth(646);
|
dialogPane.setPrefWidth(646);
|
||||||
dialogPane.setPrefHeight(webcamResolutionProperty.get() == WebcamResolution.HD ? 490 : 590);
|
dialogPane.setPrefHeight(webcamResolutionProperty.get() == WebcamResolution.HD ? 490 : 590);
|
||||||
AppServices.moveToActiveWindowScreen(this);
|
AppServices.moveToActiveWindowScreen(this);
|
||||||
|
@ -520,6 +536,7 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
public void webcamClosed(WebcamEvent webcamEvent) {
|
public void webcamClosed(WebcamEvent webcamEvent) {
|
||||||
if(webcamResolutionProperty.get() != null) {
|
if(webcamResolutionProperty.get() != null) {
|
||||||
webcamService.setResolution(webcamResolutionProperty.get());
|
webcamService.setResolution(webcamResolutionProperty.get());
|
||||||
|
webcamService.setDevice(webcamDeviceProperty.get());
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
if(!webcamService.isRunning()) {
|
if(!webcamService.isRunning()) {
|
||||||
webcamService.reset();
|
webcamService.reset();
|
||||||
|
@ -558,10 +575,31 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
});
|
});
|
||||||
|
|
||||||
button = hd;
|
button = hd;
|
||||||
|
} else if(buttonType.getButtonData() == ButtonBar.ButtonData.HELP_2) {
|
||||||
|
ComboBox<WebcamDevice> devicesCombo = new ComboBox<>(WebcamScanDriver.getFoundDevices());
|
||||||
|
devicesCombo.setConverter(new StringConverter<>() {
|
||||||
|
@Override
|
||||||
|
public String toString(WebcamDevice device) {
|
||||||
|
return device instanceof WebcamScanDevice ? ((WebcamScanDevice)device).getDeviceName() : "Default Camera";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WebcamDevice fromString(String string) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
devicesCombo.valueProperty().bindBidirectional(webcamDeviceProperty);
|
||||||
|
ButtonBar.setButtonData(devicesCombo, ButtonBar.ButtonData.LEFT);
|
||||||
|
|
||||||
|
button = devicesCombo;
|
||||||
} else {
|
} else {
|
||||||
button = super.createButton(buttonType);
|
button = super.createButton(buttonType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(button instanceof Region) {
|
||||||
|
((Region)button).setMaxWidth(140);
|
||||||
|
}
|
||||||
|
|
||||||
button.disableProperty().bind(webcamService.openingProperty());
|
button.disableProperty().bind(webcamService.openingProperty());
|
||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
@ -570,7 +608,7 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
||||||
if(isHd) {
|
if(isHd) {
|
||||||
hd.setGraphic(getGlyph(FontAwesome5.Glyph.CHECK_CIRCLE));
|
hd.setGraphic(getGlyph(FontAwesome5.Glyph.CHECK_CIRCLE));
|
||||||
} else {
|
} else {
|
||||||
hd.setGraphic(getGlyph(FontAwesome5.Glyph.QUESTION_CIRCLE));
|
hd.setGraphic(getGlyph(FontAwesome5.Glyph.BAN));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ import java.awt.image.*;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
@ -312,6 +313,23 @@ public class WebcamScanDevice implements WebcamDevice, WebcamDevice.BufferAccess
|
||||||
return this.fps;
|
return this.fps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if(this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
WebcamScanDevice that = (WebcamScanDevice) o;
|
||||||
|
return Objects.equals(fullname, that.fullname);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(fullname);
|
||||||
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
DIMENSIONS = new Dimension[]{WebcamResolution.QQVGA.getSize(), WebcamResolution.QVGA.getSize(), WebcamResolution.VGA.getSize()};
|
DIMENSIONS = new Dimension[]{WebcamResolution.QQVGA.getSize(), WebcamResolution.QVGA.getSize(), WebcamResolution.VGA.getSize()};
|
||||||
BAND_OFFSETS = new int[]{0, 1, 2};
|
BAND_OFFSETS = new int[]{0, 1, 2};
|
||||||
|
|
|
@ -3,16 +3,19 @@ package com.sparrowwallet.sparrow.control;
|
||||||
import com.github.sarxos.webcam.WebcamDevice;
|
import com.github.sarxos.webcam.WebcamDevice;
|
||||||
import com.github.sarxos.webcam.ds.buildin.WebcamDefaultDevice;
|
import com.github.sarxos.webcam.ds.buildin.WebcamDefaultDevice;
|
||||||
import com.github.sarxos.webcam.ds.buildin.WebcamDefaultDriver;
|
import com.github.sarxos.webcam.ds.buildin.WebcamDefaultDriver;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class WebcamScanDriver extends WebcamDefaultDriver {
|
public class WebcamScanDriver extends WebcamDefaultDriver {
|
||||||
private List<WebcamDevice> foundScanDevices;
|
private static final ObservableList<WebcamDevice> webcamDevices = FXCollections.observableArrayList();
|
||||||
|
private static boolean rescan;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<WebcamDevice> getDevices() {
|
public List<WebcamDevice> getDevices() {
|
||||||
if(foundScanDevices == null || foundScanDevices.isEmpty()) {
|
if(rescan || webcamDevices.isEmpty()) {
|
||||||
List<WebcamDevice> devices = super.getDevices();
|
List<WebcamDevice> devices = super.getDevices();
|
||||||
List<WebcamDevice> scanDevices = new ArrayList<>();
|
List<WebcamDevice> scanDevices = new ArrayList<>();
|
||||||
for(WebcamDevice device : devices) {
|
for(WebcamDevice device : devices) {
|
||||||
|
@ -20,9 +23,20 @@ public class WebcamScanDriver extends WebcamDefaultDriver {
|
||||||
scanDevices.add(new WebcamScanDevice(defaultDevice.getDeviceRef()));
|
scanDevices.add(new WebcamScanDevice(defaultDevice.getDeviceRef()));
|
||||||
}
|
}
|
||||||
|
|
||||||
foundScanDevices = scanDevices;
|
List<WebcamDevice> newDevices = new ArrayList<>(scanDevices);
|
||||||
|
newDevices.removeAll(webcamDevices);
|
||||||
|
webcamDevices.addAll(newDevices);
|
||||||
|
webcamDevices.removeIf(device -> !scanDevices.contains(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
return foundScanDevices;
|
return webcamDevices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObservableList<WebcamDevice> getFoundDevices() {
|
||||||
|
return webcamDevices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void rescan() {
|
||||||
|
rescan = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
package com.sparrowwallet.sparrow.control;
|
package com.sparrowwallet.sparrow.control;
|
||||||
|
|
||||||
import com.github.sarxos.webcam.Webcam;
|
import com.github.sarxos.webcam.*;
|
||||||
import com.github.sarxos.webcam.WebcamListener;
|
|
||||||
import com.github.sarxos.webcam.WebcamResolution;
|
|
||||||
import com.github.sarxos.webcam.WebcamUpdater;
|
|
||||||
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 com.google.zxing.qrcode.QRCodeReader;
|
import com.google.zxing.qrcode.QRCodeReader;
|
||||||
|
import com.sparrowwallet.sparrow.io.Config;
|
||||||
import javafx.beans.property.BooleanProperty;
|
import javafx.beans.property.BooleanProperty;
|
||||||
import javafx.beans.property.ObjectProperty;
|
import javafx.beans.property.ObjectProperty;
|
||||||
import javafx.beans.property.SimpleBooleanProperty;
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
|
@ -24,6 +22,7 @@ import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class WebcamService extends ScheduledService<Image> {
|
public class WebcamService extends ScheduledService<Image> {
|
||||||
private WebcamResolution resolution;
|
private WebcamResolution resolution;
|
||||||
|
private WebcamDevice device;
|
||||||
private final WebcamListener listener;
|
private final WebcamListener listener;
|
||||||
private final WebcamUpdater.DelayCalculator delayCalculator;
|
private final WebcamUpdater.DelayCalculator delayCalculator;
|
||||||
private final BooleanProperty opening = new SimpleBooleanProperty(false);
|
private final BooleanProperty opening = new SimpleBooleanProperty(false);
|
||||||
|
@ -40,8 +39,9 @@ public class WebcamService extends ScheduledService<Image> {
|
||||||
Webcam.setDriver(new WebcamScanDriver());
|
Webcam.setDriver(new WebcamScanDriver());
|
||||||
}
|
}
|
||||||
|
|
||||||
public WebcamService(WebcamResolution resolution, WebcamListener listener, WebcamUpdater.DelayCalculator delayCalculator) {
|
public WebcamService(WebcamResolution resolution, WebcamDevice device, WebcamListener listener, WebcamUpdater.DelayCalculator delayCalculator) {
|
||||||
this.resolution = resolution;
|
this.resolution = resolution;
|
||||||
|
this.device = device;
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
this.delayCalculator = delayCalculator;
|
this.delayCalculator = delayCalculator;
|
||||||
this.lastQrSampleTime = System.currentTimeMillis();
|
this.lastQrSampleTime = System.currentTimeMillis();
|
||||||
|
@ -61,6 +61,23 @@ public class WebcamService extends ScheduledService<Image> {
|
||||||
}
|
}
|
||||||
|
|
||||||
cam = webcams.get(0);
|
cam = webcams.get(0);
|
||||||
|
|
||||||
|
if(device != null) {
|
||||||
|
for(Webcam webcam : webcams) {
|
||||||
|
if(webcam.getDevice().getName().equals(device.getName())) {
|
||||||
|
cam = webcam;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(Config.get().getWebcamDevice() != null) {
|
||||||
|
for(Webcam webcam : webcams) {
|
||||||
|
if(webcam.getDevice().getName().equals(Config.get().getWebcamDevice())) {
|
||||||
|
cam = webcam;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
device = cam.getDevice();
|
||||||
|
|
||||||
cam.setCustomViewSizes(resolution.getSize());
|
cam.setCustomViewSizes(resolution.getSize());
|
||||||
cam.setViewSize(resolution.getSize());
|
cam.setViewSize(resolution.getSize());
|
||||||
if(!Arrays.asList(cam.getWebcamListeners()).contains(listener)) {
|
if(!Arrays.asList(cam.getWebcamListeners()).contains(listener)) {
|
||||||
|
@ -73,6 +90,10 @@ public class WebcamService extends ScheduledService<Image> {
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferedImage bimg = cam.getImage();
|
BufferedImage bimg = cam.getImage();
|
||||||
|
if(bimg == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
Image image = SwingFXUtils.toFXImage(bimg, null);
|
Image image = SwingFXUtils.toFXImage(bimg, null);
|
||||||
updateValue(image);
|
updateValue(image);
|
||||||
|
|
||||||
|
@ -136,6 +157,14 @@ public class WebcamService extends ScheduledService<Image> {
|
||||||
this.resolution = resolution;
|
this.resolution = resolution;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public WebcamDevice getDevice() {
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDevice(WebcamDevice device) {
|
||||||
|
this.device = device;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isOpening() {
|
public boolean isOpening() {
|
||||||
return opening.get();
|
return opening.get();
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ public class Config {
|
||||||
private Integer keyDerivationPeriod;
|
private Integer keyDerivationPeriod;
|
||||||
private File hwi;
|
private File hwi;
|
||||||
private Boolean hdCapture;
|
private Boolean hdCapture;
|
||||||
|
private String webcamDevice;
|
||||||
private ServerType serverType;
|
private ServerType serverType;
|
||||||
private String publicElectrumServer;
|
private String publicElectrumServer;
|
||||||
private String coreServer;
|
private String coreServer;
|
||||||
|
@ -307,6 +308,15 @@ public class Config {
|
||||||
flush();
|
flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getWebcamDevice() {
|
||||||
|
return webcamDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWebcamDevice(String webcamDevice) {
|
||||||
|
this.webcamDevice = webcamDevice;
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
|
||||||
public ServerType getServerType() {
|
public ServerType getServerType() {
|
||||||
return serverType;
|
return serverType;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue