diff --git a/pom.xml b/pom.xml index 55f47feacd..13f73c0244 100644 --- a/pom.xml +++ b/pom.xml @@ -240,6 +240,12 @@ + + net.glxn + qrgen + 1.3 + + UTF-8 diff --git a/src/main/java/io/bitsquare/BitSquare.java b/src/main/java/io/bitsquare/BitSquare.java index 6badf0c95e..67823ed10e 100644 --- a/src/main/java/io/bitsquare/BitSquare.java +++ b/src/main/java/io/bitsquare/BitSquare.java @@ -35,7 +35,7 @@ public class BitSquare extends Application public static boolean fillFormsWithDummyData = true; - private static String APP_NAME = "bitsquare"; + private static String APP_NAME = "Bitsquare"; private static Stage primaryStage; private WalletFacade walletFacade; private MessageFacade messageFacade; diff --git a/src/main/java/io/bitsquare/gui/bitsquare.css b/src/main/java/io/bitsquare/gui/bitsquare.css index 136a5647fa..7ddb32ce5b 100644 --- a/src/main/java/io/bitsquare/gui/bitsquare.css +++ b/src/main/java/io/bitsquare/gui/bitsquare.css @@ -32,6 +32,7 @@ -fx-fill: red; } + /* main nav */ #nav-button { -fx-cursor: hand; @@ -78,14 +79,19 @@ -fx-background-color: transparent; } +#qr-code-icon { + -fx-fill: #0096c9; + -fx-cursor: hand; +} + #copy-icon { - -fx-fill: black; - -fx-cursor: hand; + -fx-fill: #0096c9; + -fx-cursor: hand; } #copy-icon .hover{ - -fx-fill: #0096c9; - -fx-cursor: hand; + -fx-fill: #0096c9; + -fx-cursor: hand; } .copy-icon { @@ -97,6 +103,22 @@ -fx-fill: black; } +/* Same stlye like non editable textfield. But textfield spans a whole column in a grid, so we use generally textfield */ +#label-with-background { + -fx-background-color: #FAFAFA; + -fx-border-radius: 4; + -fx-padding: 4 4 4 4; +} + +#address-label { + -fx-cursor: hand; + -fx-text-fill: #0096c9; + -fx-underline: true; + -fx-background-color: #FAFAFA; + -fx-border-radius: 4; + -fx-padding: 4 4 4 4; +} + #funds-confidence { -fx-progress-color: dimgrey; } diff --git a/src/main/java/io/bitsquare/gui/components/btc/AddressTextField.java b/src/main/java/io/bitsquare/gui/components/btc/AddressTextField.java index 238f997837..39806bd121 100644 --- a/src/main/java/io/bitsquare/gui/components/btc/AddressTextField.java +++ b/src/main/java/io/bitsquare/gui/components/btc/AddressTextField.java @@ -1,18 +1,36 @@ package io.bitsquare.gui.components.btc; +import com.google.bitcoin.uri.BitcoinURI; import de.jensd.fx.fontawesome.AwesomeDude; import de.jensd.fx.fontawesome.AwesomeIcon; +import io.bitsquare.BitSquare; +import io.bitsquare.gui.components.Popups; +import java.awt.Desktop; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.URI; import javafx.scene.control.Label; -import javafx.scene.control.TextField; import javafx.scene.control.Tooltip; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; import javafx.scene.input.Clipboard; import javafx.scene.input.ClipboardContent; import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.Pane; +import javafx.stage.Window; +import net.glxn.qrgen.QRCode; +import net.glxn.qrgen.image.ImageType; +import org.controlsfx.control.PopOver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class AddressTextField extends AnchorPane { + private static final Logger log = LoggerFactory.getLogger(AddressTextField.class); + private final Label copyIcon; - private final TextField addressTextField; + private final Label addressLabel; + private final Label qrCode; private String address; /////////////////////////////////////////////////////////////////////////////////////////// @@ -21,12 +39,15 @@ public class AddressTextField extends AnchorPane public AddressTextField() { - addressTextField = new TextField(); - addressTextField.setFocusTraversable(false); - addressTextField.setEditable(false); + addressLabel = new Label(); + addressLabel.setFocusTraversable(false); + addressLabel.setId("address-label"); copyIcon = new Label(); copyIcon.setLayoutY(3); + copyIcon.setId("copy-icon"); + Tooltip.install(copyIcon, new Tooltip("Copy address to clipboard")); + AwesomeDude.setIcon(copyIcon, AwesomeIcon.COPY); copyIcon.setOnMouseClicked(e -> { if (address != null && address.length() > 0) { @@ -37,30 +58,72 @@ public class AddressTextField extends AnchorPane } }); - Tooltip copyIconTooltip = new Tooltip("Copy address to clipboard"); - Tooltip.install(copyIcon, copyIconTooltip); + qrCode = new Label(); + qrCode.setId("qr-code-icon"); + qrCode.setLayoutY(3); + AwesomeDude.setIcon(qrCode, AwesomeIcon.QRCODE); + Tooltip.install(qrCode, new Tooltip("Show QR code for this address")); + qrCode.setOnMouseClicked(e -> { + if (address != null && address.length() > 0) + { + final byte[] imageBytes = QRCode + .from(getBitcoinURI()) + .withSize(300, 220) + .to(ImageType.PNG) + .stream() + .toByteArray(); + Image qrImage = new Image(new ByteArrayInputStream(imageBytes)); + ImageView view = new ImageView(qrImage); - AwesomeDude.setIcon(copyIcon, AwesomeIcon.COPY); - copyIcon.setId("copy-icon"); + Pane pane = new Pane(view); + pane.setPrefSize(320, 240); + view.relocate(10, 10); - AnchorPane.setRightAnchor(copyIcon, 5.0); - AnchorPane.setRightAnchor(addressTextField, 35.0); - AnchorPane.setLeftAnchor(addressTextField, 0.0); + PopOver popOver = new PopOver(pane); + popOver.setDetachedTitle("Scan QR code for this address"); + popOver.setDetached(true); - getChildren().addAll(addressTextField, copyIcon); + Window window = getScene().getWindow(); + double x = Math.round(window.getX() + (window.getWidth() - 320) / 2); + double y = Math.round(window.getY() + (window.getHeight() - 240) / 2); + popOver.show(getScene().getWindow(), x, y); + } + }); + + AnchorPane.setRightAnchor(qrCode, 5.0); + AnchorPane.setRightAnchor(copyIcon, 30.0); + AnchorPane.setRightAnchor(addressLabel, 55.0); + AnchorPane.setLeftAnchor(addressLabel, 0.0); + + getChildren().addAll(addressLabel, copyIcon, qrCode); + + addressLabel.setOnMouseClicked(mouseEvent -> { + try + { + if (address != null) + Desktop.getDesktop().browse(URI.create(getBitcoinURI())); + } catch (IOException e) + { + log.warn(e.getMessage()); + Popups.openWarningPopup("Opening wallet app failed", "Perhaps you don't have one installed?"); + } + }); } + private String getBitcoinURI() + { + return BitcoinURI.convertToBitcoinURI(address, null, BitSquare.getAppName(), null); + } /////////////////////////////////////////////////////////////////////////////////////////// // Setters /////////////////////////////////////////////////////////////////////////////////////////// - public void setAddress(String address) { this.address = address; - addressTextField.setText(address); + addressLabel.setText(address); } } diff --git a/src/main/java/io/bitsquare/gui/components/btc/BalanceTextField.java b/src/main/java/io/bitsquare/gui/components/btc/BalanceTextField.java index 878b6a575f..71530aef22 100644 --- a/src/main/java/io/bitsquare/gui/components/btc/BalanceTextField.java +++ b/src/main/java/io/bitsquare/gui/components/btc/BalanceTextField.java @@ -49,7 +49,7 @@ public class BalanceTextField extends AnchorPane Tooltip.install(progressIndicator, progressIndicatorTooltip); AnchorPane.setRightAnchor(progressIndicator, 0.0); - AnchorPane.setRightAnchor(balanceTextField, 35.0); + AnchorPane.setRightAnchor(balanceTextField, 55.0); AnchorPane.setLeftAnchor(balanceTextField, 0.0); getChildren().addAll(balanceTextField, progressIndicator); diff --git a/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferController.java b/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferController.java index ce4b096866..be877d842d 100644 --- a/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferController.java +++ b/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferController.java @@ -105,7 +105,7 @@ public class CreateOfferController extends CachedViewController setupBindings(); setupValidation(); - + //TODO just for dev testing if (BitSquare.fillFormsWithDummyData) { @@ -171,7 +171,7 @@ public class CreateOfferController extends CachedViewController if (amountTextField.getIsValid() && minAmountTextField.getIsValid() && volumeTextField.getIsValid() && amountTextField.getIsValid()) { viewModel.isPlaceOfferButtonDisabled.set(true); - + tradeManager.requestPlaceOffer(offerId, direction, BitSquareFormatter.parseToDouble(viewModel.price.get()),