From 94abeb42c4ccadb2344ca15ac45d3d3fe834f257 Mon Sep 17 00:00:00 2001 From: Sean Gilligan Date: Sat, 19 Oct 2019 11:45:59 -0700 Subject: [PATCH 01/54] Fix netwallet-fx mainClassName to match recent refactoring --- consensusj-netwallet-fx/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/consensusj-netwallet-fx/build.gradle b/consensusj-netwallet-fx/build.gradle index ddf16e9..267e576 100644 --- a/consensusj-netwallet-fx/build.gradle +++ b/consensusj-netwallet-fx/build.gradle @@ -59,8 +59,8 @@ javafx { modules = [ 'javafx.controls', 'javafx.graphics', 'javafx.fxml', 'javafx.swing'] } -//mainClassName = "$moduleName/airgapfxwallet.AirgapFxWalletApp" -mainClassName = "netwalletfx.AirgapFxWalletApp" +//mainClassName = "$moduleName/netwalletfx.NetWalletFxApp" +mainClassName = "netwalletfx.NetWalletFxApp" def appName = 'ConsensusJWallet' From 811f6ef4e9f294981e9d02b4842f13b15a7e6476 Mon Sep 17 00:00:00 2001 From: Sean Gilligan Date: Sun, 20 Oct 2019 05:07:06 -0700 Subject: [PATCH 02/54] Bump BA JLink Plugin to 2.16.1 --- consensusj-netwallet-fx/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/consensusj-netwallet-fx/build.gradle b/consensusj-netwallet-fx/build.gradle index 267e576..82c328b 100644 --- a/consensusj-netwallet-fx/build.gradle +++ b/consensusj-netwallet-fx/build.gradle @@ -2,7 +2,7 @@ plugins { id 'groovy' id 'application' id 'org.openjfx.javafxplugin' version '0.0.8' - id 'org.beryx.jlink' version '2.16.0' + id 'org.beryx.jlink' version '2.16.1' id 'org.javamodularity.moduleplugin' version "1.5.0" id "de.undercouch.download" version "4.0.0" } From 9ee85b173cc45869d03dcb605877ab3ed00a37d9 Mon Sep 17 00:00:00 2001 From: Sean Gilligan Date: Sat, 19 Oct 2019 22:16:51 -0700 Subject: [PATCH 03/54] Upgrade to Gradle 6.0-rc-1 and BA Jlink 2.16.2 This should allow building with JDK 13. --- build.gradle | 1 - consensusj-netwallet-fx/build.gradle | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 55616 -> 58702 bytes gradle/wrapper/gradle-wrapper.properties | 4 ++-- gradlew | 29 ++++++++++------------- settings.gradle | 4 ++++ 6 files changed, 19 insertions(+), 21 deletions(-) diff --git a/build.gradle b/build.gradle index 1dedb76..3a16555 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,6 @@ buildscript { } plugins { - id 'com.gradle.build-scan' version '2.3' id 'org.asciidoctor.jvm.convert' version '2.2.0' id 'com.jfrog.bintray' version '1.8.4' } diff --git a/consensusj-netwallet-fx/build.gradle b/consensusj-netwallet-fx/build.gradle index 267e576..c55f6b5 100644 --- a/consensusj-netwallet-fx/build.gradle +++ b/consensusj-netwallet-fx/build.gradle @@ -2,7 +2,7 @@ plugins { id 'groovy' id 'application' id 'org.openjfx.javafxplugin' version '0.0.8' - id 'org.beryx.jlink' version '2.16.0' + id 'org.beryx.jlink' version '2.16.2' id 'org.javamodularity.moduleplugin' version "1.5.0" id "de.undercouch.download" version "4.0.0" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 5c2d1cf016b3885f6930543d57b744ea8c220a1a..cc4fdc293d0e50b0ad9b65c16e7ddd1db2f6025b 100644 GIT binary patch delta 16535 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 Date: Sun, 20 Oct 2019 12:33:02 -0700 Subject: [PATCH 04/54] Bump BA Jlink Plugin to 2.16.2 --- consensusj-netwallet-fx/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/consensusj-netwallet-fx/build.gradle b/consensusj-netwallet-fx/build.gradle index 82c328b..c55f6b5 100644 --- a/consensusj-netwallet-fx/build.gradle +++ b/consensusj-netwallet-fx/build.gradle @@ -2,7 +2,7 @@ plugins { id 'groovy' id 'application' id 'org.openjfx.javafxplugin' version '0.0.8' - id 'org.beryx.jlink' version '2.16.1' + id 'org.beryx.jlink' version '2.16.2' id 'org.javamodularity.moduleplugin' version "1.5.0" id "de.undercouch.download" version "4.0.0" } From 7f801d5d101af6451ba12b836e36c61f84482951 Mon Sep 17 00:00:00 2001 From: Sean Gilligan Date: Sun, 20 Oct 2019 12:53:40 -0700 Subject: [PATCH 05/54] Github Actions: Add JDK 13 to the matrix --- .github/workflows/gradle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 201c943..4b881f1 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macOS-latest, windows-latest] - java: [ '11', '12' ] + java: [ '11', '12', '13' ] fail-fast: false name: ${{ matrix.os }} JDK ${{ matrix.java }} steps: From cf76cd5eff2d67c69d0757ca920be700aa1ce845 Mon Sep 17 00:00:00 2001 From: Sean Gilligan Date: Sun, 20 Oct 2019 15:16:15 -0700 Subject: [PATCH 06/54] Github Actions: Remove JDK 12 build now that 13 works --- .github/workflows/gradle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 4b881f1..edc9acf 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macOS-latest, windows-latest] - java: [ '11', '12', '13' ] + java: [ '11', '13' ] fail-fast: false name: ${{ matrix.os }} JDK ${{ matrix.java }} steps: From 28ca5ca3afdb5ead6094b12b8409632074334141 Mon Sep 17 00:00:00 2001 From: Sean Gilligan Date: Mon, 21 Oct 2019 16:52:32 -0700 Subject: [PATCH 07/54] Rough cut of QrSigningView/Controller Create a new FXML-based view and controller that displays unsigned tx QR code to the left and scanning window for signed tx QR on the right. This is basically working, but UI is extremely raw. --- .../airgap/fx/components/QrCaptureView.java | 30 ++++--- .../fx/demoapp/DemoQRScannerApplication.java | 10 ++- .../airgap/fx/AirgapSigningDialog.fxml | 11 --- .../main/java/netwalletfx/AirGapSigner.java | 85 ++++++++++++++++++- .../NetWalletFxMainWindowController.java | 58 +++---------- .../netwalletfx/QrSigningViewController.java | 58 +++++++++++++ .../resources/netwalletfx/QrSigningView.fxml | 19 +++++ 7 files changed, 196 insertions(+), 75 deletions(-) delete mode 100644 airgapfx/src/main/resources/org/consensusj/airgap/fx/AirgapSigningDialog.fxml create mode 100644 consensusj-netwallet-fx/src/main/java/netwalletfx/QrSigningViewController.java create mode 100644 consensusj-netwallet-fx/src/main/resources/netwalletfx/QrSigningView.fxml diff --git a/airgapfx/src/main/java/org/consensusj/airgap/fx/components/QrCaptureView.java b/airgapfx/src/main/java/org/consensusj/airgap/fx/components/QrCaptureView.java index c9168c3..47e23df 100644 --- a/airgapfx/src/main/java/org/consensusj/airgap/fx/components/QrCaptureView.java +++ b/airgapfx/src/main/java/org/consensusj/airgap/fx/components/QrCaptureView.java @@ -26,7 +26,6 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.Pane; import javafx.scene.layout.VBox; -import javafx.stage.Window; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,7 +36,8 @@ */ public class QrCaptureView extends BorderPane { private static final Logger log = LoggerFactory.getLogger(QrCaptureView.class); - private final Consumer listener; + private final Consumer scanListener; + private final Consumer closeListener; private final CameraView cameraView; private final CameraService service; private TextArea previewText; @@ -47,10 +47,11 @@ public class QrCaptureView extends BorderPane { private String previewResult; - public QrCaptureView(CameraService cameraService, Consumer listener) { + public QrCaptureView(CameraService cameraService, Consumer scanListener, Consumer closeListener) { service = cameraService; cameraView = new CameraView(cameraService); - this.listener = listener; + this.scanListener = scanListener; + this.closeListener = closeListener; setCenter(cameraView); @@ -94,15 +95,12 @@ private HBox buttonBox() { } private void acceptAction(ActionEvent actionEvent) { - listener.accept(previewResult); - closeParentWindow(); + scanListener.accept(previewResult); + closeParent(); } private void cancelAction(ActionEvent actionEvent) { - if (service.isRunning()) { - service.cancel(); - } - closeParentWindow(); + closeParent(); } private void rescanAction(ActionEvent e) { @@ -131,11 +129,15 @@ private void scan() { rescanButton.setDisable(true); } - private void closeParentWindow() { - Window stage = this.getScene().getWindow(); - if (stage != null) { - stage.hide(); + private void stopCameraService() { + if (service.isRunning()) { + service.cancel(); } } + private void closeParent() { + stopCameraService(); + closeListener.accept(null); + } + } diff --git a/airgapfx/src/main/java/org/consensusj/airgap/fx/demoapp/DemoQRScannerApplication.java b/airgapfx/src/main/java/org/consensusj/airgap/fx/demoapp/DemoQRScannerApplication.java index ef9ba9e..578bb4a 100644 --- a/airgapfx/src/main/java/org/consensusj/airgap/fx/demoapp/DemoQRScannerApplication.java +++ b/airgapfx/src/main/java/org/consensusj/airgap/fx/demoapp/DemoQRScannerApplication.java @@ -16,6 +16,7 @@ package org.consensusj.airgap.fx.demoapp; +import javafx.stage.Window; import org.consensusj.airgap.fx.camera.CameraService; import org.consensusj.airgap.fx.components.QrCaptureView; import com.github.sarxos.webcam.Webcam; @@ -32,6 +33,7 @@ public class DemoQRScannerApplication extends Application { private static final Logger log = LoggerFactory.getLogger(DemoQRScannerApplication.class); private CameraService cameraService; + private Stage primaryStage; @Override public void init() { @@ -42,7 +44,8 @@ public void init() { @Override public void start(Stage primaryStage) { - QrCaptureView captureView = new QrCaptureView(cameraService, this::scanListener); + this.primaryStage = primaryStage; + QrCaptureView captureView = new QrCaptureView(cameraService, this::scanListener, this::closeListener); Scene scene = new Scene(captureView); primaryStage.setScene(scene); @@ -53,6 +56,11 @@ private void scanListener(String result) { System.out.println("Result: " + result); } + private void closeListener(Object result) { + if (primaryStage != null) { + primaryStage.hide(); + } + } public static void main(String[] args) { launch(args); diff --git a/airgapfx/src/main/resources/org/consensusj/airgap/fx/AirgapSigningDialog.fxml b/airgapfx/src/main/resources/org/consensusj/airgap/fx/AirgapSigningDialog.fxml deleted file mode 100644 index 05f3a9b..0000000 --- a/airgapfx/src/main/resources/org/consensusj/airgap/fx/AirgapSigningDialog.fxml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/consensusj-netwallet-fx/src/main/java/netwalletfx/AirGapSigner.java b/consensusj-netwallet-fx/src/main/java/netwalletfx/AirGapSigner.java index 911baee..a2c2942 100644 --- a/consensusj-netwallet-fx/src/main/java/netwalletfx/AirGapSigner.java +++ b/consensusj-netwallet-fx/src/main/java/netwalletfx/AirGapSigner.java @@ -16,6 +16,15 @@ package netwalletfx; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.MoreExecutors; +import org.bitcoinj.core.SignatureDecodeException; +import org.bitcoinj.core.Transaction; +import org.bitcoinj.core.TransactionBroadcaster; +import org.bitcoinj.walletfx.WalletSettingsController; +import org.consensusj.airgap.SignedResponseHandler; +import org.consensusj.airgap.SignedResponseParser; import org.consensusj.airgap.UnsignedTxQrGenerator; import javafx.scene.effect.DropShadow; import javafx.scene.image.Image; @@ -27,17 +36,30 @@ import org.bitcoinj.walletfx.SendMoneyController; import org.bitcoinj.walletfx.utils.QRCodeImages; import org.bitcoinj.walletfx.HardwareSigner; +import org.consensusj.airgap.fx.components.QrCaptureView; +import org.consensusj.airgap.json.TransactionSignatureResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.URL; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; /** * Incomplete implementation of signing using the Airgap protocol * TODO: Get the signed transaction and pass it to the "Send" function */ public class AirGapSigner implements HardwareSigner { + private static final Logger log = LoggerFactory.getLogger(AirGapSigner.class); private final UnsignedTxQrGenerator qrJsonGenerator; - private final OverlayableWindowController windowController; + private final NetWalletFxMainWindowController windowController; + private final SignedResponseParser signedResponseParser = new SignedResponseParser(); + private final SignedResponseHandler signedResponseHandler = new SignedResponseHandler(); + private ExecutorService executorService = Executors.newFixedThreadPool(1); private SendRequest pendingSendRequest; - public AirGapSigner(Wallet wallet, OverlayableWindowController windowController) { + public AirGapSigner(Wallet wallet, NetWalletFxMainWindowController windowController) { qrJsonGenerator = new UnsignedTxQrGenerator(wallet.getParams(), wallet.getActiveKeyChain()); this.windowController = windowController; } @@ -47,6 +69,19 @@ public void displaySigningOverlay(SendRequest sendRequest, SendMoneyController s pendingSendRequest = sendRequest; String qrJson = qrJsonGenerator.createSigningRequestString(pendingSendRequest.tx); Image qrImage = QRCodeImages.imageFromString(qrJson, 600, 450); + + + URL location = AirGapSigner.class.getResource("QrSigningView.fxml"); + final OverlayableWindowController.OverlayUI signingViewOverlay = windowController.overlayUI(location); + signingViewOverlay.ui.setEffect(new DropShadow()); + signingViewOverlay.controller.setUnsignedQrImage(qrImage); + signingViewOverlay.controller.initCaptureView(windowController.app.cameraService, this::scanListener); + } + + public void oldDisplaySigningOverlay(SendRequest sendRequest, SendMoneyController sendMoneyController) { + pendingSendRequest = sendRequest; + String qrJson = qrJsonGenerator.createSigningRequestString(pendingSendRequest.tx); + Image qrImage = QRCodeImages.imageFromString(qrJson, 600, 450); ImageView view = new ImageView(qrImage); view.setEffect(new DropShadow()); // Embed the image in a pane to ensure the drop-shadow interacts with the fade nicely, otherwise it looks weird. @@ -63,6 +98,52 @@ public String getButtonText() { return "Airgap Sign"; } + public void scanListener(String result) { + log.info("QR Scan Result {}", result); + SendRequest sendRequest = getPendingTransaction(); + + TransactionSignatureResponse response = null; + try { + response = signedResponseParser.parse(result); + } catch (IOException e) { + // TODO: Handle exception properly + e.printStackTrace(); + throw new RuntimeException(e); + } + try { + signedResponseHandler.signWithResponse(sendRequest.tx, response); + } catch (SignatureDecodeException e) { + e.printStackTrace(); + } + + executorService.submit(() -> { + broadcastTransaction(sendRequest.tx); + }); + } + + private void broadcastTransaction(Transaction transaction) { + log.info("Preparing to broadcast tx: {{}", transaction); + TransactionBroadcaster broadcaster = windowController.app.getWalletAppKit().peerGroup(); + var broadcast = broadcaster.broadcastTransaction(transaction); + Futures.addCallback(broadcast.future(), new FutureCallback(){ + + @Override + public void onSuccess(Transaction transaction) { + log.info("Broadcast success, committing transaction: {}", transaction); + // Commit tx to wallet + boolean accepted = windowController.app.getWallet().maybeCommitTx(transaction); + if (!accepted) { + log.warn("Transaction already pending"); + } + } + + @Override + public void onFailure(Throwable t) { + log.error("Broadcast failure", t); + } + }, MoreExecutors.directExecutor()); + } + public SendRequest getPendingTransaction() { return pendingSendRequest; } diff --git a/consensusj-netwallet-fx/src/main/java/netwalletfx/NetWalletFxMainWindowController.java b/consensusj-netwallet-fx/src/main/java/netwalletfx/NetWalletFxMainWindowController.java index 3b89a2d..871bd55 100644 --- a/consensusj-netwallet-fx/src/main/java/netwalletfx/NetWalletFxMainWindowController.java +++ b/consensusj-netwallet-fx/src/main/java/netwalletfx/NetWalletFxMainWindowController.java @@ -39,7 +39,6 @@ import org.bitcoinj.core.Coin; import org.bitcoinj.core.SignatureDecodeException; import org.bitcoinj.core.Transaction; -import org.bitcoinj.core.TransactionBroadcaster; import org.bitcoinj.wallet.SendRequest; import org.bitcoinj.walletfx.OverlayableWindowController; import org.bitcoinj.walletfx.SendMoneyController; @@ -77,10 +76,8 @@ public class NetWalletFxMainWindowController extends WalletMainWindowController protected final NetWalletFxApp app; private AirGapSigner airGapHardwareSigner; - private final SignedResponseParser signedResponseParser = new SignedResponseParser(); - private final SignedResponseHandler signedResponseHandler = new SignedResponseHandler(); + private Stage standaloneQrScanStage; - private ExecutorService executorService = Executors.newFixedThreadPool(1); public NetWalletFxMainWindowController(NetWalletFxApp app) { super(app); @@ -133,12 +130,12 @@ private void settingsClicked(ActionEvent event) { public void scanClicked(ActionEvent actionEvent) { log.info("scanClicked"); - QrCaptureView captureView = new QrCaptureView(app.cameraService, this::scanListener); + QrCaptureView captureView = new QrCaptureView(app.cameraService, this::scanListener, this::closeListener); Scene scene = new Scene(captureView); - final Stage stage = new Stage(); - stage.setScene(scene); - stage.show(); + standaloneQrScanStage = new Stage(); + standaloneQrScanStage.setScene(scene); + standaloneQrScanStage.show(); } @Override @@ -164,46 +161,13 @@ protected void readyToGoAnimation() { } private void scanListener(String result) { - log.info("QR Scan Result {}", result); - SendRequest sendRequest = airGapHardwareSigner.getPendingTransaction(); - - TransactionSignatureResponse response = null; - try { - response = signedResponseParser.parse(result); - } catch (IOException e) { - e.printStackTrace(); - } - try { - signedResponseHandler.signWithResponse(sendRequest.tx, response); - } catch (SignatureDecodeException e) { - e.printStackTrace(); - } - - executorService.submit(() -> { - broadcastTransaction(sendRequest.tx); - }); + airGapHardwareSigner.scanListener(result); } - private void broadcastTransaction(Transaction transaction) { - log.info("Preparing to broadcast tx: {{}", transaction); - TransactionBroadcaster broadcaster = app.getWalletAppKit().peerGroup(); - var broadcast = broadcaster.broadcastTransaction(transaction); - Futures.addCallback(broadcast.future(), new FutureCallback(){ - - @Override - public void onSuccess(Transaction transaction) { - log.info("Broadcast success, committing transaction: {}", transaction); - // Commit tx to wallet - boolean accepted = app.getWallet().maybeCommitTx(transaction); - if (!accepted) { - log.warn("Transaction already pending"); - } - } - - @Override - public void onFailure(Throwable t) { - log.error("Broadcast failure", t); - } - }, MoreExecutors.directExecutor()); + private void closeListener(Object unused) { + if (standaloneQrScanStage != null) { + standaloneQrScanStage.hide(); + } } + } diff --git a/consensusj-netwallet-fx/src/main/java/netwalletfx/QrSigningViewController.java b/consensusj-netwallet-fx/src/main/java/netwalletfx/QrSigningViewController.java new file mode 100644 index 0000000..b0a50af --- /dev/null +++ b/consensusj-netwallet-fx/src/main/java/netwalletfx/QrSigningViewController.java @@ -0,0 +1,58 @@ +package netwalletfx; + +import javafx.fxml.FXML; +import javafx.scene.effect.DropShadow; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.VBox; +import org.bitcoinj.walletfx.OverlayWindowController; +import org.bitcoinj.walletfx.OverlayableWindowController; +import org.consensusj.airgap.fx.camera.CameraService; +import org.consensusj.airgap.fx.components.QrCaptureView; + +import javax.inject.Singleton; +import java.util.function.Consumer; + +/** + * + */ +@Singleton +public class QrSigningViewController implements OverlayWindowController { + private OverlayableWindowController.OverlayUI overlayUI; + @FXML private ImageView unsignedQrImage; + @FXML private VBox captureBox; + + private QrCaptureView captureView; + + public void setUnsignedQrImage(Image image) { + if (unsignedQrImage != null) { + unsignedQrImage.setImage(image); + unsignedQrImage.setEffect(new DropShadow()); + } + } + + public void initCaptureView(CameraService cameraService, Consumer scanListener) { + captureView = new QrCaptureView(cameraService, scanListener, this::closeListener); + if (captureBox != null) { + captureBox.getChildren().add(captureView); + } + } + + @Override + public OverlayableWindowController.OverlayUI getOverlayUI() { + return overlayUI; + } + + @Override + public void setOverlayUI(OverlayableWindowController.OverlayUI ui) { + overlayUI = ui; + } + + private void closeListener(Object result) { + closeOverlay(); + } + + void closeOverlay() { + overlayUI.done(); + } +} diff --git a/consensusj-netwallet-fx/src/main/resources/netwalletfx/QrSigningView.fxml b/consensusj-netwallet-fx/src/main/resources/netwalletfx/QrSigningView.fxml new file mode 100644 index 0000000..5f0353f --- /dev/null +++ b/consensusj-netwallet-fx/src/main/resources/netwalletfx/QrSigningView.fxml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + From 6c95da490546cac61f6bd37635be7f002515c8e3 Mon Sep 17 00:00:00 2001 From: Sean Gilligan Date: Tue, 22 Oct 2019 10:23:01 -0700 Subject: [PATCH 08/54] Bump to JavaFX 13.0.1 --- consensusj-netwallet-fx/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/consensusj-netwallet-fx/build.gradle b/consensusj-netwallet-fx/build.gradle index c55f6b5..248861c 100644 --- a/consensusj-netwallet-fx/build.gradle +++ b/consensusj-netwallet-fx/build.gradle @@ -55,7 +55,7 @@ patchModules.config = [ ] javafx { - version = 13 + version = '13.0.1' modules = [ 'javafx.controls', 'javafx.graphics', 'javafx.fxml', 'javafx.swing'] } From bfaa169083ec950d6f440c2152ce18a1d5350429 Mon Sep 17 00:00:00 2001 From: Sean Gilligan Date: Tue, 22 Oct 2019 10:24:04 -0700 Subject: [PATCH 09/54] Bump SLF4J to 1.7.28 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 2df9190..7b3413f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,7 +12,7 @@ supernautVersion = 0.0.4 micronautVersion = 1.2.0 groovyVersion = 2.5.8 spockVersion = 1.3-groovy-2.5 -slf4jVersion = 1.7.27 +slf4jVersion = 1.7.28 jacksonVersion = 2.9.8 # Note: Asciidoctor Gradle Plugin version is set in plugins block in main build.gradle asciidoctorjVersion = 2.0.0 From 508293078de968339b4fdf45fe544fc15bde0b23 Mon Sep 17 00:00:00 2001 From: Sean Gilligan Date: Tue, 22 Oct 2019 11:04:51 -0700 Subject: [PATCH 10/54] Global JavaFX version string in gradle.properties --- airgapfx/build.gradle | 1 + consensusj-netwallet-fx/build.gradle | 2 +- gradle.properties | 1 + omnij-wallet/build.gradle | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/airgapfx/build.gradle b/airgapfx/build.gradle index edab0b9..4b864b7 100644 --- a/airgapfx/build.gradle +++ b/airgapfx/build.gradle @@ -26,6 +26,7 @@ dependencies { } javafx { + version = javaFxVersion modules = [ 'javafx.controls', 'javafx.fxml', 'javafx.swing' ] } diff --git a/consensusj-netwallet-fx/build.gradle b/consensusj-netwallet-fx/build.gradle index 248861c..767c803 100644 --- a/consensusj-netwallet-fx/build.gradle +++ b/consensusj-netwallet-fx/build.gradle @@ -55,7 +55,7 @@ patchModules.config = [ ] javafx { - version = '13.0.1' + version = javaFxVersion modules = [ 'javafx.controls', 'javafx.graphics', 'javafx.fxml', 'javafx.swing'] } diff --git a/gradle.properties b/gradle.properties index 7b3413f..0c66d3a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,6 +8,7 @@ bitcoinjWalletFxArtifact = bitcoinj-walletfx #Use Jitpack.io bitcoinjGroup = com.github.ConsensusJ.bitcoinj bitcoinjVersion = consensusj-master-SNAPSHOT +javaFxVersion = 13.0.1 supernautVersion = 0.0.4 micronautVersion = 1.2.0 groovyVersion = 2.5.8 diff --git a/omnij-wallet/build.gradle b/omnij-wallet/build.gradle index 60b3d0d..26b4f18 100644 --- a/omnij-wallet/build.gradle +++ b/omnij-wallet/build.gradle @@ -55,6 +55,7 @@ patchModules.config = [ ] javafx { + version = javaFxVersion modules = [ 'javafx.graphics', 'javafx.controls', 'javafx.fxml' ] } From e7ab9724bbb8578119ec27dc2424e045d4399536 Mon Sep 17 00:00:00 2001 From: Sean Gilligan Date: Tue, 22 Oct 2019 11:22:56 -0700 Subject: [PATCH 11/54] Bump BA Jlink to 2.16.2 in omnij-wallet --- omnij-wallet/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/omnij-wallet/build.gradle b/omnij-wallet/build.gradle index 26b4f18..e23baaa 100644 --- a/omnij-wallet/build.gradle +++ b/omnij-wallet/build.gradle @@ -2,8 +2,8 @@ plugins { id 'groovy' id 'application' id 'org.openjfx.javafxplugin' version '0.0.8' - id 'org.beryx.jlink' version '2.14.1' id 'org.javamodularity.moduleplugin' version "1.5.0" + id 'org.beryx.jlink' version '2.16.2' } sourceCompatibility = 11 From 001e9e2fdcdd1b7e4300eb05c0c486a48b871538 Mon Sep 17 00:00:00 2001 From: Sean Gilligan Date: Wed, 23 Oct 2019 10:52:22 -0700 Subject: [PATCH 12/54] Improve appearance of QR Signing View MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also disable separate “Scan” button (Still needs a lot more work) --- .../netwalletfx/NetWalletFxMainWindowController.java | 9 ++++----- .../main/java/netwalletfx/QrSigningViewController.java | 1 - .../src/main/resources/netwalletfx/QrSigningView.fxml | 10 +++++----- .../src/main/resources/netwalletfx/main.fxml | 6 +++--- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/consensusj-netwallet-fx/src/main/java/netwalletfx/NetWalletFxMainWindowController.java b/consensusj-netwallet-fx/src/main/java/netwalletfx/NetWalletFxMainWindowController.java index 871bd55..8a29c2c 100644 --- a/consensusj-netwallet-fx/src/main/java/netwalletfx/NetWalletFxMainWindowController.java +++ b/consensusj-netwallet-fx/src/main/java/netwalletfx/NetWalletFxMainWindowController.java @@ -70,7 +70,6 @@ public class NetWalletFxMainWindowController extends WalletMainWindowController @FXML private HBox controlsBox; @FXML private Label balance; @FXML private Button sendMoneyOutBtn; - @FXML private Button scanBtn; @FXML private ClickableBitcoinAddress addressControl; @FXML private ListView transactionListView; @@ -126,10 +125,10 @@ private void settingsClicked(ActionEvent event) { screen.controller.initialize(null); } - @FXML - public void scanClicked(ActionEvent actionEvent) { - log.info("scanClicked"); - + /** + * Display old standalone QR capture window + */ + public void displayCaptureWindow() { QrCaptureView captureView = new QrCaptureView(app.cameraService, this::scanListener, this::closeListener); Scene scene = new Scene(captureView); diff --git a/consensusj-netwallet-fx/src/main/java/netwalletfx/QrSigningViewController.java b/consensusj-netwallet-fx/src/main/java/netwalletfx/QrSigningViewController.java index b0a50af..a8201a8 100644 --- a/consensusj-netwallet-fx/src/main/java/netwalletfx/QrSigningViewController.java +++ b/consensusj-netwallet-fx/src/main/java/netwalletfx/QrSigningViewController.java @@ -27,7 +27,6 @@ public class QrSigningViewController implements OverlayWindowController { public void setUnsignedQrImage(Image image) { if (unsignedQrImage != null) { unsignedQrImage.setImage(image); - unsignedQrImage.setEffect(new DropShadow()); } } diff --git a/consensusj-netwallet-fx/src/main/resources/netwalletfx/QrSigningView.fxml b/consensusj-netwallet-fx/src/main/resources/netwalletfx/QrSigningView.fxml index 5f0353f..29e05a4 100644 --- a/consensusj-netwallet-fx/src/main/resources/netwalletfx/QrSigningView.fxml +++ b/consensusj-netwallet-fx/src/main/resources/netwalletfx/QrSigningView.fxml @@ -5,15 +5,15 @@ - + - + - + - + - + diff --git a/consensusj-netwallet-fx/src/main/resources/netwalletfx/main.fxml b/consensusj-netwallet-fx/src/main/resources/netwalletfx/main.fxml index bcc3287..7084339 100644 --- a/consensusj-netwallet-fx/src/main/resources/netwalletfx/main.fxml +++ b/consensusj-netwallet-fx/src/main/resources/netwalletfx/main.fxml @@ -14,7 +14,7 @@ - +