handle missing webcam dependency on windows showing error alert with link to resolve

This commit is contained in:
Craig Raw 2021-05-05 14:31:28 +02:00
parent dd56e2b42e
commit 19637fd706
5 changed files with 68 additions and 5 deletions

View file

@ -9,6 +9,7 @@ import com.sparrowwallet.drongo.psbt.PSBT;
import com.sparrowwallet.drongo.uri.BitcoinURI; import com.sparrowwallet.drongo.uri.BitcoinURI;
import com.sparrowwallet.drongo.wallet.KeystoreSource; import com.sparrowwallet.drongo.wallet.KeystoreSource;
import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.control.TextUtils;
import com.sparrowwallet.sparrow.control.TrayManager; import com.sparrowwallet.sparrow.control.TrayManager;
import com.sparrowwallet.sparrow.event.*; import com.sparrowwallet.sparrow.event.*;
import com.sparrowwallet.sparrow.io.Config; import com.sparrowwallet.sparrow.io.Config;
@ -27,10 +28,7 @@ import javafx.fxml.FXMLLoader;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.Parent; import javafx.scene.Parent;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.scene.control.Alert; import javafx.scene.control.*;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.control.DialogPane;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.text.Font; import javafx.scene.text.Font;
import javafx.stage.Screen; import javafx.stage.Screen;
@ -38,6 +36,7 @@ import javafx.stage.Stage;
import javafx.stage.Window; import javafx.stage.Window;
import javafx.util.Duration; import javafx.util.Duration;
import org.berndpruenster.netlayer.tor.Tor; import org.berndpruenster.netlayer.tor.Tor;
import org.controlsfx.control.HyperlinkLabel;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -49,6 +48,8 @@ import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.*; import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class AppServices { public class AppServices {
@ -514,6 +515,23 @@ public class AppServices {
alert.getDialogPane().getScene().getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm()); alert.getDialogPane().getScene().getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
alert.setTitle(title); alert.setTitle(title);
alert.setHeaderText(title); alert.setHeaderText(title);
Pattern linkPattern = Pattern.compile("\\[(http.+)]");
Matcher matcher = linkPattern.matcher(content);
if(matcher.find()) {
String link = matcher.group(1);
HyperlinkLabel hyperlinkLabel = new HyperlinkLabel(content);
hyperlinkLabel.setMaxWidth(Double.MAX_VALUE);
hyperlinkLabel.setMaxHeight(Double.MAX_VALUE);
hyperlinkLabel.getStyleClass().add("content");
Label label = new Label();
hyperlinkLabel.setPrefWidth(Math.max(360, TextUtils.computeTextWidth(label.getFont(), link, 0.0D) + 50));
hyperlinkLabel.setOnAction(event -> {
get().getApplication().getHostServices().showDocument(link);
});
alert.getDialogPane().setContent(hyperlinkLabel);
}
moveToActiveWindowScreen(alert); moveToActiveWindowScreen(alert);
return alert.showAndWait(); return alert.showAndWait();
} }

View file

@ -113,7 +113,19 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
webcamService.resultProperty().addListener(new QRResultListener()); webcamService.resultProperty().addListener(new QRResultListener());
webcamService.setOnFailed(failedEvent -> { webcamService.setOnFailed(failedEvent -> {
Platform.runLater(() -> setResult(new Result(failedEvent.getSource().getException()))); Throwable exception = failedEvent.getSource().getException();
Throwable nested = exception;
while(nested.getCause() != null) {
nested = nested.getCause();
}
if(org.controlsfx.tools.Platform.getCurrent() == org.controlsfx.tools.Platform.WINDOWS &&
nested.getMessage().startsWith("Library 'OpenIMAJGrabber' was not loaded successfully from file")) {
exception = new WebcamDependencyException("Your system is missing a dependency required for the webcam. Follow the link below for more details.\n\n[https://sparrowwallet.com/docs/faq.html#your-system-is-missing-a-dependency-for-the-webcam]", exception);
}
final Throwable result = exception;
Platform.runLater(() -> setResult(new Result(result)));
}); });
webcamService.start(); webcamService.start();
webcamResolutionProperty.addListener((observable, oldValue, newResolution) -> { webcamResolutionProperty.addListener((observable, oldValue, newResolution) -> {
@ -715,6 +727,24 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
} }
} }
public static class WebcamDependencyException extends ScanException {
public WebcamDependencyException() {
super();
}
public WebcamDependencyException(String message) {
super(message);
}
public WebcamDependencyException(Throwable cause) {
super(cause);
}
public WebcamDependencyException(String message, Throwable cause) {
super(message, cause);
}
}
public static class ScanDelayCalculator implements WebcamUpdater.DelayCalculator { public static class ScanDelayCalculator implements WebcamUpdater.DelayCalculator {
public long calculateDelay(long snapshotDuration, double deviceFps) { public long calculateDelay(long snapshotDuration, double deviceFps) {
return Math.max(SCAN_PERIOD_MILLIS - snapshotDuration, 0L); return Math.max(SCAN_PERIOD_MILLIS - snapshotDuration, 0L);

View file

@ -12,10 +12,14 @@ import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority; import javafx.scene.layout.Priority;
import org.controlsfx.glyphfont.Glyph; import org.controlsfx.glyphfont.Glyph;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Optional; import java.util.Optional;
public class TextAreaDialog extends Dialog<String> { public class TextAreaDialog extends Dialog<String> {
private static final Logger log = LoggerFactory.getLogger(TextAreaDialog.class);
private final TextArea textArea; private final TextArea textArea;
private final String defaultValue; private final String defaultValue;
@ -99,6 +103,7 @@ public class TextAreaDialog extends Dialog<String> {
} else if(result.outputDescriptor != null) { } else if(result.outputDescriptor != null) {
textArea.setText(result.outputDescriptor.toString(true)); textArea.setText(result.outputDescriptor.toString(true));
} else if(result.exception != null) { } else if(result.exception != null) {
log.error("Error scanning QR", result.exception);
AppServices.showErrorDialog("Error scanning QR", result.exception.getMessage()); AppServices.showErrorDialog("Error scanning QR", result.exception.getMessage());
} }
} }

View file

@ -30,13 +30,19 @@ import javafx.scene.control.*;
import org.controlsfx.validation.ValidationResult; import org.controlsfx.validation.ValidationResult;
import org.controlsfx.validation.ValidationSupport; import org.controlsfx.validation.ValidationSupport;
import org.controlsfx.validation.Validator; import org.controlsfx.validation.Validator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URL; import java.net.URL;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols; import java.text.DecimalFormatSymbols;
import java.util.*; import java.util.*;
import static com.sparrowwallet.sparrow.AppServices.showErrorDialog;
public class PaymentController extends WalletFormController implements Initializable { public class PaymentController extends WalletFormController implements Initializable {
private static final Logger log = LoggerFactory.getLogger(PaymentController.class);
private SendController sendController; private SendController sendController;
private ValidationSupport validationSupport; private ValidationSupport validationSupport;
@ -327,6 +333,9 @@ public class PaymentController extends WalletFormController implements Initializ
QRScanDialog.Result result = optionalResult.get(); QRScanDialog.Result result = optionalResult.get();
if(result.uri != null) { if(result.uri != null) {
updateFromURI(result.uri); updateFromURI(result.uri);
} else if(result.exception != null) {
log.error("Error scanning QR", result.exception);
showErrorDialog("Error scanning QR", result.exception.getMessage());
} }
} }
} }

View file

@ -289,6 +289,7 @@ public class SettingsController extends WalletFormController implements Initiali
} else if(result.payload != null && !result.payload.isEmpty()) { } else if(result.payload != null && !result.payload.isEmpty()) {
setDescriptorText(result.payload); setDescriptorText(result.payload);
} else if(result.exception != null) { } else if(result.exception != null) {
log.error("Error scanning QR", result.exception);
AppServices.showErrorDialog("Error scanning QR", result.exception.getMessage()); AppServices.showErrorDialog("Error scanning QR", result.exception.getMessage());
} }
} }