From 1c3c8b9d21bf78d5fc2e29138a337eb4f77acb7e Mon Sep 17 00:00:00 2001 From: Manfred Karrer Date: Tue, 26 Aug 2014 16:57:31 +0200 Subject: [PATCH] merged with cbeams formatting changes. use MVP pattern for create offer screen --- pom.xml | 13 + .../java/io/bitsquare/di/BitSquareModule.java | 4 +- .../java/io/bitsquare/gui/MainController.java | 8 +- .../profile/ArbitratorProfileController.java | 10 +- .../ArbitratorRegistrationController.java | 66 ++-- .../gui/components/btc/AddressTextField.java | 17 +- .../gui/components/btc/BalanceTextField.java | 2 +- .../transactions/TransactionsListItem.java | 10 +- .../withdrawal/WithdrawalController.java | 16 +- .../funds/withdrawal/WithdrawalListItem.java | 2 +- .../gui/orders/offer/OfferListItem.java | 12 +- .../pending/PendingTradeController.java | 26 +- .../bitsquare/gui/trade/TradeController.java | 16 +- .../createoffer/CreateOfferCodeBehind.java | 284 ++++++++++++++ .../createoffer/CreateOfferController.java | 352 ------------------ .../trade/createoffer/CreateOfferModel.java | 148 ++++++++ .../createoffer/CreateOfferPresenter.java | 307 +++++++++++++++ .../trade/createoffer/CreateOfferView.fxml | 4 +- .../trade/orderbook/OrderBookController.java | 54 +-- .../trade/orderbook/OrderBookListItem.java | 10 +- .../trade/takeoffer/TakerOfferController.java | 54 +-- ...tSquareFormatter.java => BSFormatter.java} | 253 +++++++++---- .../io/bitsquare/locale/Localisation.java | 3 + .../java/io/bitsquare/settings/Settings.java | 12 +- src/main/java/io/bitsquare/trade/Offer.java | 6 +- src/main/java/io/bitsquare/user/User.java | 7 + .../java/io/bitsquare/BitSquareTestSuite.java | 4 +- .../createoffer/CreateOfferPresenterTest.java | 107 ++++++ .../gui/util/BitSquareConverterTest.java | 26 +- 29 files changed, 1232 insertions(+), 601 deletions(-) create mode 100644 src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferCodeBehind.java delete mode 100644 src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferController.java create mode 100644 src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferModel.java create mode 100644 src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferPresenter.java rename src/main/java/io/bitsquare/gui/util/{BitSquareFormatter.java => BSFormatter.java} (50%) create mode 100644 src/test/java/io/bitsquare/gui/trade/createoffer/CreateOfferPresenterTest.java diff --git a/pom.xml b/pom.xml index 55f47feacd..1167a7a106 100644 --- a/pom.xml +++ b/pom.xml @@ -238,6 +238,19 @@ annotations 13.0 + + + net.glxn + qrgen + 1.3 + + + + org.mockito + mockito-all + 1.9.5 + test + diff --git a/src/main/java/io/bitsquare/di/BitSquareModule.java b/src/main/java/io/bitsquare/di/BitSquareModule.java index 875a4bd384..8608a67ed0 100644 --- a/src/main/java/io/bitsquare/di/BitSquareModule.java +++ b/src/main/java/io/bitsquare/di/BitSquareModule.java @@ -22,7 +22,7 @@ import io.bitsquare.btc.BlockChainFacade; import io.bitsquare.btc.FeePolicy; import io.bitsquare.btc.WalletFacade; import io.bitsquare.crypto.CryptoFacade; -import io.bitsquare.gui.util.BitSquareFormatter; +import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.msg.BootstrappedPeerFactory; import io.bitsquare.msg.MessageFacade; import io.bitsquare.msg.P2PNode; @@ -64,7 +64,7 @@ public class BitSquareModule extends AbstractModule { bind(BootstrappedPeerFactory.class).asEagerSingleton(); bind(TradeManager.class).asEagerSingleton(); - bind(BitSquareFormatter.class).asEagerSingleton(); + bind(BSFormatter.class).asEagerSingleton(); //bind(String.class).annotatedWith(Names.named("networkType")).toInstance(WalletFacade.MAIN_NET); diff --git a/src/main/java/io/bitsquare/gui/MainController.java b/src/main/java/io/bitsquare/gui/MainController.java index 03bdb4106d..e7eddc2cae 100644 --- a/src/main/java/io/bitsquare/gui/MainController.java +++ b/src/main/java/io/bitsquare/gui/MainController.java @@ -23,7 +23,7 @@ import io.bitsquare.btc.listeners.BalanceListener; import io.bitsquare.di.GuiceFXMLLoader; import io.bitsquare.gui.components.NetworkSyncPane; import io.bitsquare.gui.orders.OrdersController; -import io.bitsquare.gui.util.BitSquareFormatter; +import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.ImageUtil; import io.bitsquare.gui.util.Profiler; import io.bitsquare.gui.util.Transitions; @@ -365,11 +365,11 @@ public class MainController extends ViewController { balanceTextField.setEditable(false); balanceTextField.setPrefWidth(110); balanceTextField.setId("nav-balance-label"); - balanceTextField.setText(BitSquareFormatter.formatCoinWithCode(walletFacade.getWalletBalance())); + balanceTextField.setText(BSFormatter.formatCoinWithCode(walletFacade.getWalletBalance())); walletFacade.addBalanceListener(new BalanceListener() { @Override public void onBalanceChanged(Coin balance) { - balanceTextField.setText(BitSquareFormatter.formatCoinWithCode(walletFacade.getWalletBalance())); + balanceTextField.setText(BSFormatter.formatCoinWithCode(walletFacade.getWalletBalance())); } }); @@ -406,7 +406,7 @@ public class MainController extends ViewController { }); user.getSelectedBankAccountIndexProperty().addListener(observable -> - accountComboBox.getSelectionModel().select(user.getCurrentBankAccount())); + accountComboBox.getSelectionModel().select(user.getCurrentBankAccount())); user.getBankAccountsSizeProperty().addListener(observable -> { accountComboBox.setItems(FXCollections.observableArrayList(user.getBankAccounts())); // need to delay it a bit otherwise it will not be set diff --git a/src/main/java/io/bitsquare/gui/arbitrators/profile/ArbitratorProfileController.java b/src/main/java/io/bitsquare/gui/arbitrators/profile/ArbitratorProfileController.java index 265d96d9f1..f2b12f5adb 100644 --- a/src/main/java/io/bitsquare/gui/arbitrators/profile/ArbitratorProfileController.java +++ b/src/main/java/io/bitsquare/gui/arbitrators/profile/ArbitratorProfileController.java @@ -20,7 +20,7 @@ package io.bitsquare.gui.arbitrators.profile; import io.bitsquare.gui.CachedViewController; import io.bitsquare.gui.NavigationItem; import io.bitsquare.gui.ViewController; -import io.bitsquare.gui.util.BitSquareFormatter; +import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.settings.Settings; import io.bitsquare.storage.Persistence; import io.bitsquare.user.Arbitrator; @@ -124,16 +124,16 @@ public class ArbitratorProfileController extends CachedViewController { nameLabel.setText(name); nameTextField.setText(arbitrator.getName()); - languagesTextField.setText(BitSquareFormatter.languageLocalesToString(arbitrator.getLanguages())); + languagesTextField.setText(BSFormatter.languageLocalesToString(arbitrator.getLanguages())); reputationTextField.setText(arbitrator.getReputation().toString()); maxTradeVolumeTextField.setText(String.valueOf(arbitrator.getMaxTradeVolume()) + " BTC"); passiveServiceFeeTextField.setText(String.valueOf(arbitrator.getPassiveServiceFee()) + " % (Min. " + - String.valueOf(arbitrator.getMinPassiveServiceFee()) + " BTC)"); + String.valueOf(arbitrator.getMinPassiveServiceFee()) + " BTC)"); arbitrationFeeTextField.setText(String.valueOf(arbitrator.getArbitrationFee()) + " % (Min. " + String .valueOf(arbitrator.getMinArbitrationFee()) + " BTC)"); - methodsTextField.setText(BitSquareFormatter.arbitrationMethodsToString(arbitrator.getArbitrationMethods())); + methodsTextField.setText(BSFormatter.arbitrationMethodsToString(arbitrator.getArbitrationMethods())); idVerificationsTextField.setText( - BitSquareFormatter.arbitrationIDVerificationsToString(arbitrator.getIdVerifications())); + BSFormatter.arbitrationIDVerificationsToString(arbitrator.getIdVerifications())); webPageTextField.setText(arbitrator.getWebUrl()); descriptionTextArea.setText(arbitrator.getDescription()); } diff --git a/src/main/java/io/bitsquare/gui/arbitrators/registration/ArbitratorRegistrationController.java b/src/main/java/io/bitsquare/gui/arbitrators/registration/ArbitratorRegistrationController.java index 344704db20..dc2136422f 100644 --- a/src/main/java/io/bitsquare/gui/arbitrators/registration/ArbitratorRegistrationController.java +++ b/src/main/java/io/bitsquare/gui/arbitrators/registration/ArbitratorRegistrationController.java @@ -23,7 +23,7 @@ import io.bitsquare.gui.NavigationItem; import io.bitsquare.gui.ViewController; import io.bitsquare.gui.arbitrators.profile.ArbitratorProfileController; import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator; -import io.bitsquare.gui.util.BitSquareFormatter; +import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.BitSquareValidator; import io.bitsquare.gui.util.ConfidenceDisplay; import io.bitsquare.locale.LanguageUtil; @@ -132,7 +132,7 @@ public class ArbitratorRegistrationController extends CachedViewController { } else { languageList.add(LanguageUtil.getDefaultLanguageLocale()); - languagesTextField.setText(BitSquareFormatter.languageLocalesToString(languageList)); + languagesTextField.setText(BSFormatter.languageLocalesToString(languageList)); } languageComboBox.setItems(FXCollections.observableArrayList(LanguageUtil.getAllLanguageLocales())); @@ -166,7 +166,7 @@ public class ArbitratorRegistrationController extends CachedViewController { }); methodsComboBox.setItems(FXCollections.observableArrayList(new ArrayList<>(EnumSet.allOf(Arbitrator.METHOD - .class)))); + .class)))); methodsComboBox.setConverter(new StringConverter() { @Override @@ -277,7 +277,7 @@ public class ArbitratorRegistrationController extends CachedViewController { Locale item = languageComboBox.getSelectionModel().getSelectedItem(); if (!languageList.contains(item) && item != null) { languageList.add(item); - languagesTextField.setText(BitSquareFormatter.languageLocalesToString(languageList)); + languagesTextField.setText(BSFormatter.languageLocalesToString(languageList)); languageComboBox.getSelectionModel().clearSelection(); } } @@ -293,7 +293,7 @@ public class ArbitratorRegistrationController extends CachedViewController { Arbitrator.METHOD item = methodsComboBox.getSelectionModel().getSelectedItem(); if (!methodList.contains(item) && item != null) { methodList.add(item); - methodsTextField.setText(BitSquareFormatter.arbitrationMethodsToString(methodList)); + methodsTextField.setText(BSFormatter.arbitrationMethodsToString(methodList)); methodsComboBox.getSelectionModel().clearSelection(); } } @@ -312,7 +312,7 @@ public class ArbitratorRegistrationController extends CachedViewController { if (!idVerificationList.contains(idVerification)) { idVerificationList.add(idVerification); idVerificationsTextField.setText( - BitSquareFormatter.arbitrationIDVerificationsToString(idVerificationList)); + BSFormatter.arbitrationIDVerificationsToString(idVerificationList)); } } @@ -355,11 +355,11 @@ public class ArbitratorRegistrationController extends CachedViewController { private void setupPayCollateralScreen() { infoLabel.setText("You need to pay 10 x the max. trading volume as collateral.\n\nThat payment will be " + - "locked into a MultiSig fund and be refunded when you leave the arbitration pool.\nIn case of fraud " + - "(collusion, not fulfilling the min. dispute quality requirements) you will lose your collateral.\n" + - "If you have a negative feedback from your clients you will lose a part of the collateral,\n" + - "depending on the overall relation of negative to positive ratings you received after a dispute " + - "resolution.\n\nPlease pay in " + arbitrator.getMaxTradeVolume() * 10 + " BTC"); + "locked into a MultiSig fund and be refunded when you leave the arbitration pool.\nIn case of fraud " + + "(collusion, not fulfilling the min. dispute quality requirements) you will lose your collateral.\n" + + "If you have a negative feedback from your clients you will lose a part of the collateral,\n" + + "depending on the overall relation of negative to positive ratings you received after a dispute " + + "resolution.\n\nPlease pay in " + arbitrator.getMaxTradeVolume() * 10 + " BTC"); String collateralAddress = walletFacade.getRegistrationAddressEntry() != null ? @@ -434,15 +434,15 @@ public class ArbitratorRegistrationController extends CachedViewController { nameTextField.setText(arbitrator.getName()); idTypeTextField.setText(Localisation.get(arbitrator.getIdType().toString())); - languagesTextField.setText(BitSquareFormatter.languageLocalesToString(arbitrator.getLanguages())); + languagesTextField.setText(BSFormatter.languageLocalesToString(arbitrator.getLanguages())); maxTradeVolumeTextField.setText(String.valueOf(arbitrator.getMaxTradeVolume())); passiveServiceFeeTextField.setText(String.valueOf(arbitrator.getPassiveServiceFee())); minPassiveServiceFeeTextField.setText(String.valueOf(arbitrator.getMinPassiveServiceFee())); arbitrationFeeTextField.setText(String.valueOf(arbitrator.getArbitrationFee())); minArbitrationFeeTextField.setText(String.valueOf(arbitrator.getMinArbitrationFee())); - methodsTextField.setText(BitSquareFormatter.arbitrationMethodsToString(arbitrator.getArbitrationMethods())); + methodsTextField.setText(BSFormatter.arbitrationMethodsToString(arbitrator.getArbitrationMethods())); idVerificationsTextField.setText( - BitSquareFormatter.arbitrationIDVerificationsToString(arbitrator.getIdVerifications())); + BSFormatter.arbitrationIDVerificationsToString(arbitrator.getIdVerifications())); webPageTextField.setText(arbitrator.getWebUrl()); descriptionTextArea.setText(arbitrator.getDescription()); @@ -466,30 +466,30 @@ public class ArbitratorRegistrationController extends CachedViewController { String messagePubKeyAsHex = DSAKeyUtil.getHexStringFromPublicKey(user.getMessagePublicKey()); String name = nameTextField.getText(); - double maxTradeVolume = BitSquareFormatter.parseToDouble(maxTradeVolumeTextField.getText()); - double passiveServiceFee = BitSquareFormatter.parseToDouble(passiveServiceFeeTextField.getText()); - double minPassiveServiceFee = BitSquareFormatter.parseToDouble(minPassiveServiceFeeTextField.getText()); - double arbitrationFee = BitSquareFormatter.parseToDouble(arbitrationFeeTextField.getText()); - double minArbitrationFee = BitSquareFormatter.parseToDouble(minArbitrationFeeTextField.getText()); + double maxTradeVolume = BSFormatter.parseToDouble(maxTradeVolumeTextField.getText()); + double passiveServiceFee = BSFormatter.parseToDouble(passiveServiceFeeTextField.getText()); + double minPassiveServiceFee = BSFormatter.parseToDouble(minPassiveServiceFeeTextField.getText()); + double arbitrationFee = BSFormatter.parseToDouble(arbitrationFeeTextField.getText()); + double minArbitrationFee = BSFormatter.parseToDouble(minArbitrationFeeTextField.getText()); String webUrl = webPageTextField.getText(); String description = descriptionTextArea.getText(); return new Arbitrator(pubKeyAsHex, - messagePubKeyAsHex, - name, - idType, - languageList, - new Reputation(), - maxTradeVolume, - passiveServiceFee, - minPassiveServiceFee, - arbitrationFee, - minArbitrationFee, - methodList, - idVerificationList, - webUrl, - description); + messagePubKeyAsHex, + name, + idType, + languageList, + new Reputation(), + maxTradeVolume, + passiveServiceFee, + minPassiveServiceFee, + arbitrationFee, + minArbitrationFee, + methodList, + idVerificationList, + webUrl, + description); } catch (BitSquareValidator.ValidationException e) { return null; } 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 c52109af1d..15c8e0ed1e 100644 --- a/src/main/java/io/bitsquare/gui/components/btc/AddressTextField.java +++ b/src/main/java/io/bitsquare/gui/components/btc/AddressTextField.java @@ -17,9 +17,7 @@ package io.bitsquare.gui.components.btc; -import io.bitsquare.BitSquare; import io.bitsquare.gui.components.Popups; -import io.bitsquare.gui.util.BitSquareFormatter; import com.google.bitcoin.core.Coin; import com.google.bitcoin.uri.BitcoinURI; @@ -57,7 +55,8 @@ public class AddressTextField extends AnchorPane { private final Label addressLabel; private final Label qrCode; private String address; - private String amountToPay; + private Coin amountToPay; + private String paymentLabel; /////////////////////////////////////////////////////////////////////////////////////////// // Constructor @@ -142,19 +141,21 @@ public class AddressTextField extends AnchorPane { addressLabel.setText(address); } - public void setAmountToPay(String amountToPay) { + public void setAmountToPay(Coin amountToPay) { this.amountToPay = amountToPay; } + public void setPaymentLabel(String paymentLabel) { + this.paymentLabel = paymentLabel; + } + + /////////////////////////////////////////////////////////////////////////////////////////// // Private /////////////////////////////////////////////////////////////////////////////////////////// private String getBitcoinURI() { - Coin d = BitSquareFormatter.parseToCoin(amountToPay); - return BitcoinURI.convertToBitcoinURI( - address, BitSquareFormatter.parseToCoin(amountToPay), BitSquare.getAppName(), null); + return BitcoinURI.convertToBitcoinURI(address, amountToPay, paymentLabel, null); } - } 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 4df8c3772f..ea1e09091d 100644 --- a/src/main/java/io/bitsquare/gui/components/btc/BalanceTextField.java +++ b/src/main/java/io/bitsquare/gui/components/btc/BalanceTextField.java @@ -154,7 +154,7 @@ public class BalanceTextField extends AnchorPane { private void updateBalance(Coin balance) { this.balance = balance; if (balance != null) { - //TODO use BitSquareFormatter + //TODO use BSFormatter balanceTextField.setText(balance.toFriendlyString()); } } diff --git a/src/main/java/io/bitsquare/gui/funds/transactions/TransactionsListItem.java b/src/main/java/io/bitsquare/gui/funds/transactions/TransactionsListItem.java index 7153a57d7e..92a97d3ca7 100644 --- a/src/main/java/io/bitsquare/gui/funds/transactions/TransactionsListItem.java +++ b/src/main/java/io/bitsquare/gui/funds/transactions/TransactionsListItem.java @@ -20,7 +20,7 @@ package io.bitsquare.gui.funds.transactions; import io.bitsquare.btc.WalletFacade; import io.bitsquare.btc.listeners.ConfidenceListener; import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator; -import io.bitsquare.gui.util.BitSquareFormatter; +import io.bitsquare.gui.util.BSFormatter; import com.google.bitcoin.core.Address; import com.google.bitcoin.core.Coin; @@ -56,7 +56,7 @@ public class TransactionsListItem { Coin valueSentFromMe = transaction.getValueSentFromMe(walletFacade.getWallet()); Address address = null; if (valueSentToMe.isZero()) { - //TODO use BitSquareFormatter + //TODO use BSFormatter amount.set("-" + valueSentFromMe.toFriendlyString()); for (TransactionOutput transactionOutput : transaction.getOutputs()) { @@ -76,7 +76,7 @@ public class TransactionsListItem { } } else if (valueSentFromMe.isZero()) { - //TODO use BitSquareFormatter + //TODO use BSFormatter amount.set(valueSentToMe.toFriendlyString()); type.set("Received with"); @@ -95,7 +95,7 @@ public class TransactionsListItem { } } else { - //TODO use BitSquareFormatter + //TODO use BSFormatter amount.set(valueSentToMe.subtract(valueSentFromMe).toFriendlyString()); boolean outgoing = false; @@ -123,7 +123,7 @@ public class TransactionsListItem { } } - date.set(BitSquareFormatter.formatDateTime(transaction.getUpdateTime())); + date.set(BSFormatter.formatDateTime(transaction.getUpdateTime())); // confidence progressIndicator = new ConfidenceProgressIndicator(); diff --git a/src/main/java/io/bitsquare/gui/funds/withdrawal/WithdrawalController.java b/src/main/java/io/bitsquare/gui/funds/withdrawal/WithdrawalController.java index 29f135dd11..ffbee583a5 100644 --- a/src/main/java/io/bitsquare/gui/funds/withdrawal/WithdrawalController.java +++ b/src/main/java/io/bitsquare/gui/funds/withdrawal/WithdrawalController.java @@ -23,7 +23,7 @@ import io.bitsquare.btc.FeePolicy; import io.bitsquare.btc.WalletFacade; import io.bitsquare.gui.CachedViewController; import io.bitsquare.gui.components.Popups; -import io.bitsquare.gui.util.BitSquareFormatter; +import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.BitSquareValidator; import com.google.bitcoin.core.AddressFormatException; @@ -131,7 +131,7 @@ public class WithdrawalController extends CachedViewController { List addressEntryList = walletFacade.getAddressEntryList(); addressList = FXCollections.observableArrayList(); addressList.addAll(addressEntryList.stream().map(anAddressEntryList -> - new WithdrawalListItem(anAddressEntryList, walletFacade)).collect(Collectors.toList())); + new WithdrawalListItem(anAddressEntryList, walletFacade)).collect(Collectors.toList())); tableView.setItems(addressList); } @@ -148,7 +148,7 @@ public class WithdrawalController extends CachedViewController { amountTextField, withdrawFromTextField, withdrawToTextField, changeAddressTextField); BitSquareValidator.textFieldsHasDoubleValueWithReset(amountTextField); - Coin amount = BitSquareFormatter.parseToCoin(amountTextField.getText()); + Coin amount = BSFormatter.parseToCoin(amountTextField.getText()); if (BtcValidator.isMinSpendableAmount(amount)) { FutureCallback callback = new FutureCallback() { @Override @@ -171,9 +171,9 @@ public class WithdrawalController extends CachedViewController { "Your withdrawal request:\n\n" + "Amount: " + amountTextField.getText() + " BTC\n" + "Sending" + " address: " + withdrawFromTextField.getText() + "\n" + "Receiving address: " + withdrawToTextField.getText() + "\n" + "Transaction fee: " + - BitSquareFormatter.formatCoinWithCode(FeePolicy.TX_FEE) + "\n" + + BSFormatter.formatCoinWithCode(FeePolicy.TX_FEE) + "\n" + "You receive in total: " + - BitSquareFormatter.formatCoinWithCode(amount.subtract(FeePolicy.TX_FEE)) + " BTC\n\n" + + BSFormatter.formatCoinWithCode(amount.subtract(FeePolicy.TX_FEE)) + " BTC\n\n" + "Are you sure you withdraw that amount?"); if (response == Dialog.Actions.OK) { try { @@ -182,7 +182,7 @@ public class WithdrawalController extends CachedViewController { changeAddressTextField.getText(), amount, callback); } catch (AddressFormatException e) { Popups.openErrorPopup("Address invalid", - "The address is not correct. Please check the address format."); + "The address is not correct. Please check the address format."); } catch (InsufficientMoneyException e) { Popups.openInsufficientMoneyPopup(); @@ -194,7 +194,7 @@ public class WithdrawalController extends CachedViewController { } else { Popups.openErrorPopup("Insufficient amount", - "The amount to transfer is lower the the transaction fee and the min. possible tx value."); + "The amount to transfer is lower the the transaction fee and the min. possible tx value."); } } catch (BitSquareValidator.ValidationException e) { @@ -308,7 +308,7 @@ public class WithdrawalController extends CachedViewController { private void setConfidenceColumnCellFactory() { confidenceColumn.setCellValueFactory((addressListItem) -> - new ReadOnlyObjectWrapper(addressListItem.getValue())); + new ReadOnlyObjectWrapper(addressListItem.getValue())); confidenceColumn.setCellFactory( new Callback, TableCell>() { diff --git a/src/main/java/io/bitsquare/gui/funds/withdrawal/WithdrawalListItem.java b/src/main/java/io/bitsquare/gui/funds/withdrawal/WithdrawalListItem.java index 681a10e545..71c585bafa 100644 --- a/src/main/java/io/bitsquare/gui/funds/withdrawal/WithdrawalListItem.java +++ b/src/main/java/io/bitsquare/gui/funds/withdrawal/WithdrawalListItem.java @@ -93,7 +93,7 @@ public class WithdrawalListItem { private void updateBalance(Coin balance) { this.balance = balance; if (balance != null) { - //TODO use BitSquareFormatter + //TODO use BSFormatter balanceLabel.setText(balance.toFriendlyString()); } } diff --git a/src/main/java/io/bitsquare/gui/orders/offer/OfferListItem.java b/src/main/java/io/bitsquare/gui/orders/offer/OfferListItem.java index 1129900d05..81aa2fcbb1 100644 --- a/src/main/java/io/bitsquare/gui/orders/offer/OfferListItem.java +++ b/src/main/java/io/bitsquare/gui/orders/offer/OfferListItem.java @@ -17,7 +17,7 @@ package io.bitsquare.gui.orders.offer; -import io.bitsquare.gui.util.BitSquareFormatter; +import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.trade.Offer; import javafx.beans.property.SimpleStringProperty; @@ -35,12 +35,12 @@ public class OfferListItem { public OfferListItem(Offer offer) { this.offer = offer; - this.date.set(BitSquareFormatter.formatDateTime(offer.getCreationDate())); - this.price.set(BitSquareFormatter.formatPrice(offer.getPrice())); + this.date.set(BSFormatter.formatDateTime(offer.getCreationDate())); + this.price.set(BSFormatter.formatPrice(offer.getPrice())); - this.amount.set(BitSquareFormatter.formatCoin( - offer.getAmount()) + " (" + BitSquareFormatter.formatCoin(offer.getMinAmount()) + ")"); - this.volume.set(BitSquareFormatter.formatVolumeWithMinVolume( + this.amount.set(BSFormatter.formatCoin( + offer.getAmount()) + " (" + BSFormatter.formatCoin(offer.getMinAmount()) + ")"); + this.volume.set(BSFormatter.formatVolumeWithMinVolume( offer.getOfferVolume(), offer.getMinOfferVolume())); this.offerId = offer.getId(); } diff --git a/src/main/java/io/bitsquare/gui/orders/pending/PendingTradeController.java b/src/main/java/io/bitsquare/gui/orders/pending/PendingTradeController.java index f7e8543efa..3f599b3e92 100644 --- a/src/main/java/io/bitsquare/gui/orders/pending/PendingTradeController.java +++ b/src/main/java/io/bitsquare/gui/orders/pending/PendingTradeController.java @@ -23,7 +23,7 @@ import io.bitsquare.btc.FeePolicy; import io.bitsquare.btc.WalletFacade; import io.bitsquare.gui.CachedViewController; import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator; -import io.bitsquare.gui.util.BitSquareFormatter; +import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.ConfidenceDisplay; import io.bitsquare.gui.util.ImageUtil; import io.bitsquare.locale.Country; @@ -157,8 +157,8 @@ public class PendingTradeController extends CachedViewController { // select Optional currentTradeItemOptional = tradeItems.stream().filter((e) -> - tradeManager.getPendingTrade() != null && - e.getTrade().getId().equals(tradeManager.getPendingTrade().getId())).findFirst(); + tradeManager.getPendingTrade() != null && + e.getTrade().getId().equals(tradeManager.getPendingTrade().getId())).findFirst(); if (currentTradeItemOptional.isPresent()) { openTradesTable.getSelectionModel().select(currentTradeItemOptional.get()); } @@ -241,7 +241,7 @@ public class PendingTradeController extends CachedViewController { Transaction transaction = trade.getDepositTransaction(); if (transaction == null) { trade.depositTxChangedProperty().addListener((observableValue, aBoolean, aBoolean2) -> - updateTx(trade.getDepositTransaction())); + updateTx(trade.getDepositTransaction())); } else { updateTx(trade.getDepositTransaction()); @@ -278,11 +278,11 @@ public class PendingTradeController extends CachedViewController { primaryBankAccountIDTitleLabel.setText("Total fees (offer fee + tx fee):"); secondaryBankAccountIDTitleLabel.setText("Refunded collateral:"); - bankAccountTypeTextField.setText(BitSquareFormatter.formatCoinWithCode(trade.getTradeAmount())); - holderNameTextField.setText(BitSquareFormatter.formatVolume(trade.getTradeVolume())); + bankAccountTypeTextField.setText(BSFormatter.formatCoinWithCode(trade.getTradeAmount())); + holderNameTextField.setText(BSFormatter.formatVolume(trade.getTradeVolume())); primaryBankAccountIDTextField.setText( - BitSquareFormatter.formatCoinWithCode(FeePolicy.CREATE_OFFER_FEE.add(FeePolicy.TX_FEE))); - secondaryBankAccountIDTextField.setText(BitSquareFormatter.formatCoinWithCode(trade.getCollateralAmount())); + BSFormatter.formatCoinWithCode(FeePolicy.CREATE_OFFER_FEE.add(FeePolicy.TX_FEE))); + secondaryBankAccountIDTextField.setText(BSFormatter.formatCoinWithCode(trade.getCollateralAmount())); holderNameCopyIcon.setVisible(false); primaryBankAccountIDCopyIcon.setVisible(false); @@ -370,8 +370,8 @@ public class PendingTradeController extends CachedViewController { } catch (Exception e) { log.warn("Country icon not found: /images/countries/" + - country.getCode().toLowerCase() + ".png country name: " + - country.getName()); + country.getCode().toLowerCase() + ".png country name: " + + country.getName()); } Tooltip.install(this, new Tooltip(country.getName())); } @@ -395,7 +395,7 @@ public class PendingTradeController extends CachedViewController { if (tradesTableItem != null) { BankAccountType bankAccountType = tradesTableItem.getTrade().getOffer() - .getBankAccountType(); + .getBankAccountType(); setText(Localisation.get(bankAccountType.toString())); } else { @@ -434,11 +434,11 @@ public class PendingTradeController extends CachedViewController { if (offer.getDirection() == Direction.SELL) { icon = buyIcon; - title = BitSquareFormatter.formatDirection(Direction.BUY, true); + title = BSFormatter.formatDirection(Direction.BUY, true); } else { icon = sellIcon; - title = BitSquareFormatter.formatDirection(Direction.SELL, true); + title = BSFormatter.formatDirection(Direction.SELL, true); } button.setDisable(true); iconView.setImage(icon); diff --git a/src/main/java/io/bitsquare/gui/trade/TradeController.java b/src/main/java/io/bitsquare/gui/trade/TradeController.java index 62d333db0b..0eaad7b7b1 100644 --- a/src/main/java/io/bitsquare/gui/trade/TradeController.java +++ b/src/main/java/io/bitsquare/gui/trade/TradeController.java @@ -22,7 +22,7 @@ import io.bitsquare.gui.CachedViewController; import io.bitsquare.gui.NavigationItem; import io.bitsquare.gui.ViewController; import io.bitsquare.gui.components.ValidatingTextField; -import io.bitsquare.gui.trade.createoffer.CreateOfferController; +import io.bitsquare.gui.trade.createoffer.CreateOfferCodeBehind; import io.bitsquare.gui.trade.orderbook.OrderBookController; import io.bitsquare.gui.trade.takeoffer.TakerOfferController; import io.bitsquare.trade.Direction; @@ -46,7 +46,7 @@ public class TradeController extends CachedViewController { private static final Logger log = LoggerFactory.getLogger(TradeController.class); protected OrderBookController orderBookController; - protected CreateOfferController createOfferController; + protected CreateOfferCodeBehind createOfferCodeBehind; protected TakerOfferController takerOfferController; protected GuiceFXMLLoader orderBookLoader; @@ -76,7 +76,7 @@ public class TradeController extends CachedViewController { // TODO find better solution // Textfield focus out triggers validation, use runLater as quick fix... ((TabPane) root).getSelectionModel().selectedIndexProperty().addListener((observableValue) -> - Platform.runLater(() -> ValidatingTextField.hidePopover())); + Platform.runLater(() -> ValidatingTextField.hidePopover())); } @@ -106,20 +106,20 @@ public class TradeController extends CachedViewController { return orderBookController; } else if (navigationItem == NavigationItem.CREATE_OFFER) { - checkArgument(createOfferController == null); + checkArgument(createOfferCodeBehind == null); // CreateOffer and TakeOffer must not be cached by GuiceFXMLLoader as we cannot use a view multiple times // in different graphs GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()), false); try { final Parent view = loader.load(); - createOfferController = loader.getController(); - createOfferController.setParentController(this); + createOfferCodeBehind = loader.getController(); + createOfferCodeBehind.setParentController(this); final Tab tab = new Tab("Create offer"); tab.setContent(view); tabPane.getTabs().add(tab); tabPane.getSelectionModel().select(tabPane.getTabs().size() - 1); - return createOfferController; + return createOfferCodeBehind; } catch (IOException e) { log.error(e.getMessage()); } @@ -157,7 +157,7 @@ public class TradeController extends CachedViewController { /////////////////////////////////////////////////////////////////////////////////////////// public void onCreateOfferViewRemoved() { - createOfferController = null; + createOfferCodeBehind = null; orderBookController.onCreateOfferViewRemoved(); } diff --git a/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferCodeBehind.java b/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferCodeBehind.java new file mode 100644 index 0000000000..29cbab5e04 --- /dev/null +++ b/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferCodeBehind.java @@ -0,0 +1,284 @@ +package io.bitsquare.gui.trade.createoffer; + +import io.bitsquare.gui.CachedViewController; +import io.bitsquare.gui.components.Popups; +import io.bitsquare.gui.components.ValidatingTextField; +import io.bitsquare.gui.components.btc.AddressTextField; +import io.bitsquare.gui.components.btc.BalanceTextField; +import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator; +import io.bitsquare.gui.trade.TradeController; +import io.bitsquare.trade.orderbook.OrderBookFilter; + +import java.net.URL; + +import java.util.ResourceBundle; + +import javax.inject.Inject; + +import javafx.fxml.FXML; +import javafx.scene.control.*; +import javafx.scene.layout.*; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +//TODO check DI + +/** + * Code behind (FXML Controller is part of View, not a classical controller from MVC): + *

+ * Creates Presenter and passes Model from DI to Presenter. Does not hold a reference to Model + *

+ * - Setup binding from Presenter to View elements (also bidirectional - Inputs). Binding are only to presenters properties, not logical bindings or cross-view element bindings. + * - Listen to UI events (Action) from View and call method in Presenter. + * - Is entry node for hierarchical view graphs. Passes method calls to Presenter. Calls methods on sub views. + * - Handle lifecycle and self removal from scene graph. + * - Non declarative (dynamic) view definitions (if it gets larger, then user a ViewBuilder) + *

+ * View: + * - Mostly declared in FXML. Dynamic parts are declared in Controller. If more view elements need to be defined in code then use ViewBuilder. + *

+ * Optional ViewBuilder: + * - Replacement for FXML view definitions. + */ +public class CreateOfferCodeBehind extends CachedViewController +{ + private static final Logger log = LoggerFactory.getLogger(CreateOfferCodeBehind.class); + + private final CreateOfferPresenter presenter; + + @FXML private AnchorPane rootContainer; + @FXML private Label buyLabel, confirmationLabel, txTitleLabel, collateralLabel; + + @FXML private ValidatingTextField amountTextField, minAmountTextField, priceTextField, volumeTextField; + @FXML private Button placeOfferButton, closeButton; + @FXML private TextField totalToPayTextField, collateralTextField, bankAccountTypeTextField, bankAccountCurrencyTextField, bankAccountCountyTextField, acceptedCountriesTextField, acceptedLanguagesTextField, + feeLabel, transactionIdTextField; + @FXML private ConfidenceProgressIndicator progressIndicator; + @FXML private AddressTextField addressTextField; + @FXML private BalanceTextField balanceTextField; + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor + /////////////////////////////////////////////////////////////////////////////////////////// + + @Inject + public CreateOfferCodeBehind(CreateOfferModel model) + { + presenter = new CreateOfferPresenter(model); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Lifecycle + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public void initialize(URL url, ResourceBundle rb) + { + super.initialize(url, rb); + presenter.onViewInitialized(); + } + + @Override + public void deactivate() + { + super.deactivate(); + presenter.deactivate(); + ((TradeController) parentController).onCreateOfferViewRemoved(); + } + + @Override + public void activate() + { + super.activate(); + presenter.activate(); + + setupBindings(); + setupListeners(); + setupTextFieldValidators(); + + + //addressTextField.setAddress(addressEntry.getAddress().toString()); + //addressTextField.setPaymentLabel("Bitsquare trade (" + offerId + ")"); + + // balanceTextField.setAddress(addressEntry.getAddress()); + //TODO balanceTextField.setWalletFacade(walletFacade); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Public methods + /////////////////////////////////////////////////////////////////////////////////////////// + + public void setOrderBookFilter(OrderBookFilter orderBookFilter) + { + presenter.setOrderBookFilter(orderBookFilter); + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // UI Handlers + /////////////////////////////////////////////////////////////////////////////////////////// + + @FXML + public void onPlaceOffer() + { + presenter.placeOffer(); + } + + @FXML + public void onClose() + { + presenter.close(); + + TabPane tabPane = ((TabPane) (rootContainer.getParent().getParent())); + tabPane.getTabs().remove(tabPane.getSelectionModel().getSelectedItem()); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Private Methods + /////////////////////////////////////////////////////////////////////////////////////////// + + private void setupListeners() + { + volumeTextField.focusedProperty().addListener((observableValue, oldValue, newValue) -> presenter.checkVolumeOnFocusOut(oldValue, newValue, volumeTextField.getText())); + amountTextField.focusedProperty().addListener((observableValue, oldValue, newValue) -> presenter.onFocusOutAmountTextField(oldValue, newValue)); + priceTextField.focusedProperty().addListener((observableValue, oldValue, newValue) -> presenter.onFocusOutPriceTextField(oldValue, newValue)); + + presenter.validateInput.addListener((o, oldValue, newValue) -> { + if (newValue) + { + amountTextField.reValidate(); + minAmountTextField.reValidate(); + volumeTextField.reValidate(); + priceTextField.reValidate(); + } + }); + + presenter.showVolumeAdjustedWarning.addListener((o, oldValue, newValue) -> { + if (newValue) + { + Popups.openWarningPopup("Warning", "The total volume you have entered leads to invalid fractional Bitcoin amounts.\nThe amount has been adjusted and a new total volume be calculated from it."); + volumeTextField.setText(presenter.volume.get()); + } + }); + } + + private void setupBindings() + { + buyLabel.textProperty().bind(presenter.directionLabel); + amountTextField.textProperty().bindBidirectional(presenter.amount); + priceTextField.textProperty().bindBidirectional(presenter.price); + volumeTextField.textProperty().bindBidirectional(presenter.volume); + + minAmountTextField.textProperty().bindBidirectional(presenter.minAmount); + collateralLabel.textProperty().bind(presenter.collateralLabel); + collateralTextField.textProperty().bind(presenter.collateral); + totalToPayTextField.textProperty().bind(presenter.totalToPay); + + bankAccountTypeTextField.textProperty().bind(presenter.bankAccountType); + bankAccountCurrencyTextField.textProperty().bind(presenter.bankAccountCurrency); + bankAccountCountyTextField.textProperty().bind(presenter.bankAccountCounty); + + acceptedCountriesTextField.textProperty().bind(presenter.acceptedCountries); + acceptedLanguagesTextField.textProperty().bind(presenter.acceptedLanguages); + feeLabel.textProperty().bind(presenter.totalFeesLabel); + transactionIdTextField.textProperty().bind(presenter.transactionId); + + placeOfferButton.visibleProperty().bind(presenter.placeOfferButtonVisible); + closeButton.visibleProperty().bind(presenter.isOfferPlacedScreen); + + //TODO + /* progressIndicator.visibleProperty().bind(viewModel.isOfferPlacedScreen); + confirmationLabel.visibleProperty().bind(viewModel.isOfferPlacedScreen); + txTitleLabel.visibleProperty().bind(viewModel.isOfferPlacedScreen); + transactionIdTextField.visibleProperty().bind(viewModel.isOfferPlacedScreen); + */ + + // TODO + /* placeOfferButton.disableProperty().bind(amountTextField.isValidProperty() + .and(minAmountTextField.isValidProperty()) + .and(volumeTextField.isValidProperty()) + .and(priceTextField.isValidProperty()).not());*/ + } + + private void setupTextFieldValidators() + { + /* BtcValidator amountValidator = new BtcValidator(); + amountTextField.setNumberValidator(amountValidator); + amountTextField.setErrorPopupLayoutReference((Region) amountTextField.getParent()); + + priceTextField.setNumberValidator(new FiatValidator()); + priceTextField.setErrorPopupLayoutReference((Region) amountTextField.getParent()); + + BtcValidator volumeValidator = new BtcValidator(); + volumeTextField.setNumberValidator(volumeValidator); + volumeTextField.setErrorPopupLayoutReference((Region) volumeTextField.getParent()); + + BtcValidator minAmountValidator = new BtcValidator(); + minAmountTextField.setNumberValidator(minAmountValidator); + + ValidationHelper.setupMinAmountInRangeOfAmountValidation(amountTextField, + minAmountTextField, + presenter.amount, + presenter.minAmount, + amountValidator, + minAmountValidator);*/ + } + /* + private void setVolume() + { + amountAsCoin = parseToCoin(presenter.amount.get()); + priceAsFiat = parseToFiat(presenter.price.get()); + + if (priceAsFiat != null && amountAsCoin != null) + { + tradeVolumeAsFiat = new ExchangeRate(priceAsFiat).coinToFiat(amountAsCoin); + presenter.volume.set(formatFiat(tradeVolumeAsFiat)); + } + } + + private void setAmount() + { + tradeVolumeAsFiat = parseToFiat(presenter.volume.get()); + priceAsFiat = parseToFiat(presenter.price.get()); + + if (tradeVolumeAsFiat != null && priceAsFiat != null && !priceAsFiat.isZero()) + { + amountAsCoin = new ExchangeRate(priceAsFiat).fiatToCoin(tradeVolumeAsFiat); + + // If we got a btc value with more then 4 decimals we convert it to max 4 decimals + amountAsCoin = parseToCoin(formatBtc(amountAsCoin)); + + presenter.amount.set(formatBtc(amountAsCoin)); + setTotalToPay(); + setCollateral(); + } + } + + private void setTotalToPay() + { + setCollateral(); + + totalFeesAsCoin = FeePolicy.CREATE_OFFER_FEE.add(FeePolicy.TX_FEE); + + if (collateralAsCoin != null) + { + totalToPayAsCoin = collateralAsCoin.add(totalFeesAsCoin); + presenter.totalToPay.set(formatBtcWithCode(totalToPayAsCoin)); + } + } + + private void setCollateral() + { + if (amountAsCoin != null) + { + collateralAsCoin = amountAsCoin.multiply(collateralAsLong).divide(1000); + presenter.collateral.set(BSFormatter.formatBtcWithCode(collateralAsCoin)); + } + }*/ +} + + \ No newline at end of file diff --git a/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferController.java b/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferController.java deleted file mode 100644 index 6877296152..0000000000 --- a/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferController.java +++ /dev/null @@ -1,352 +0,0 @@ -/* - * This file is part of Bitsquare. - * - * Bitsquare is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bitsquare is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bitsquare. If not, see . - */ - -package io.bitsquare.gui.trade.createoffer; - -import io.bitsquare.BitSquare; -import io.bitsquare.bank.BankAccount; -import io.bitsquare.btc.AddressEntry; -import io.bitsquare.btc.FeePolicy; -import io.bitsquare.btc.WalletFacade; -import io.bitsquare.gui.CachedViewController; -import io.bitsquare.gui.components.Popups; -import io.bitsquare.gui.components.ValidatingTextField; -import io.bitsquare.gui.components.btc.AddressTextField; -import io.bitsquare.gui.components.btc.BalanceTextField; -import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator; -import io.bitsquare.gui.trade.TradeController; -import io.bitsquare.gui.util.BitSquareFormatter; -import io.bitsquare.gui.util.BtcValidator; -import io.bitsquare.gui.util.FiatValidator; -import io.bitsquare.gui.util.ValidationHelper; -import io.bitsquare.locale.Localisation; -import io.bitsquare.settings.Settings; -import io.bitsquare.trade.Direction; -import io.bitsquare.trade.TradeManager; -import io.bitsquare.trade.orderbook.OrderBookFilter; -import io.bitsquare.user.User; - -import java.net.URL; - -import java.util.Random; -import java.util.ResourceBundle; -import java.util.UUID; - -import javax.inject.Inject; - -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; -import javafx.fxml.FXML; -import javafx.scene.control.*; -import javafx.scene.layout.*; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class CreateOfferController extends CachedViewController { - private static final Logger log = LoggerFactory.getLogger(CreateOfferController.class); - - - private final TradeManager tradeManager; - private final WalletFacade walletFacade; - final ViewModel viewModel = new ViewModel(); - private final double collateral; - private final String offerId; - private Direction direction; - private AddressEntry addressEntry; - - @FXML private AnchorPane rootContainer; - @FXML private Label buyLabel, confirmationLabel, txTitleLabel, collateralLabel; - - @FXML private ValidatingTextField amountTextField, minAmountTextField, priceTextField, volumeTextField; - @FXML private Button placeOfferButton, closeButton; - @FXML private TextField totalsTextField, collateralTextField, bankAccountTypeTextField, - bankAccountCurrencyTextField, bankAccountCountyTextField, acceptedCountriesTextField, - acceptedLanguagesTextField, - feeLabel, transactionIdTextField; - @FXML private ConfidenceProgressIndicator progressIndicator; - @FXML private AddressTextField addressTextField; - @FXML private BalanceTextField balanceTextField; - - - /////////////////////////////////////////////////////////////////////////////////////////// - // Constructor - /////////////////////////////////////////////////////////////////////////////////////////// - - @Inject - CreateOfferController(TradeManager tradeManager, WalletFacade walletFacade, Settings settings, User user) { - this.tradeManager = tradeManager; - this.walletFacade = walletFacade; - - this.collateral = settings.getCollateral(); - - viewModel.collateralLabel.set("Collateral (" + BitSquareFormatter.formatCollateralPercent(collateral) + "):"); - BankAccount bankAccount = user.getCurrentBankAccount(); - if (bankAccount != null) { - viewModel.bankAccountType.set(Localisation.get(bankAccount.getBankAccountType().toString())); - viewModel.bankAccountCurrency.set(bankAccount.getCurrency().getCurrencyCode()); - viewModel.bankAccountCounty.set(bankAccount.getCountry().getName()); - } - viewModel.acceptedCountries.set(BitSquareFormatter.countryLocalesToString(settings.getAcceptedCountries())); - viewModel.acceptedLanguages.set( - BitSquareFormatter.languageLocalesToString(settings.getAcceptedLanguageLocales())); - viewModel.feeLabel.set(BitSquareFormatter.formatCoinWithCode(FeePolicy.CREATE_OFFER_FEE.add(FeePolicy.TX_FEE))); - - offerId = UUID.randomUUID().toString(); - } - - - /////////////////////////////////////////////////////////////////////////////////////////// - // Lifecycle - /////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void initialize(URL url, ResourceBundle rb) { - super.initialize(url, rb); - - setupBindings(); - setupValidation(); - - //TODO just for dev testing - if (BitSquare.fillFormsWithDummyData) { - amountTextField.setText("1.0"); - minAmountTextField.setText("0.1"); - priceTextField.setText("" + (int) (499 - new Random().nextDouble() * 1000 / 100)); - } - - - //TODO - if (walletFacade.getWallet() != null) { - addressEntry = walletFacade.getAddressInfoByTradeID(offerId); - addressTextField.setAddress(addressEntry.getAddress().toString()); - - balanceTextField.setAddress(addressEntry.getAddress()); - balanceTextField.setWalletFacade(walletFacade); - } - } - - @Override - public void deactivate() { - super.deactivate(); - ((TradeController) parentController).onCreateOfferViewRemoved(); - } - - @Override - public void activate() { - super.activate(); - } - - - /////////////////////////////////////////////////////////////////////////////////////////// - // Public methods - /////////////////////////////////////////////////////////////////////////////////////////// - - public void setOrderBookFilter(OrderBookFilter orderBookFilter) { - direction = orderBookFilter.getDirection(); - - viewModel.directionLabel.set(BitSquareFormatter.formatDirection(direction, false) + ":"); - viewModel.amount.set(BitSquareFormatter.formatCoin(orderBookFilter.getAmount())); - viewModel.minAmount.set(BitSquareFormatter.formatCoin(orderBookFilter.getAmount())); - viewModel.price.set(BitSquareFormatter.formatPrice(orderBookFilter.getPrice())); - } - - /////////////////////////////////////////////////////////////////////////////////////////// - // UI Handlers - /////////////////////////////////////////////////////////////////////////////////////////// - - @FXML - public void onPlaceOffer() { - amountTextField.reValidate(); - minAmountTextField.reValidate(); - volumeTextField.reValidate(); - priceTextField.reValidate(); - - //balanceTextField.getBalance() - - if (amountTextField.getIsValid() && minAmountTextField.getIsValid() && volumeTextField.getIsValid() && - amountTextField.getIsValid()) { - viewModel.isPlaceOfferButtonDisabled.set(true); - - tradeManager.requestPlaceOffer(offerId, - direction, - BitSquareFormatter.parseToDouble(viewModel.price.get()), - BitSquareFormatter.parseToCoin(viewModel.amount.get()), - BitSquareFormatter.parseToCoin(viewModel.minAmount.get()), - (transaction) -> { - viewModel.isOfferPlacedScreen.set(true); - viewModel.transactionId.set(transaction.getHashAsString()); - }, - errorMessage -> { - Popups.openErrorPopup("An error occurred", errorMessage); - viewModel.isPlaceOfferButtonDisabled.set(false); - }); - } - } - - @FXML - public void onClose() { - TabPane tabPane = ((TabPane) (rootContainer.getParent().getParent())); - tabPane.getTabs().remove(tabPane.getSelectionModel().getSelectedItem()); - } - - - /////////////////////////////////////////////////////////////////////////////////////////// - // Private Methods - /////////////////////////////////////////////////////////////////////////////////////////// - - private void setupBindings() { - // TODO check that entered decimal places are nto exceeded supported - - viewModel.amount.addListener((ov, oldValue, newValue) -> { - double amount = BitSquareFormatter.parseToDouble(newValue); - double price = BitSquareFormatter.parseToDouble(viewModel.price.get()); - double volume = amount * price; - viewModel.volume.set(BitSquareFormatter.formatVolume(volume)); - viewModel.totals.set(BitSquareFormatter.formatTotalsAsBtc( - viewModel.amount.get(), collateral, FeePolicy.CREATE_OFFER_FEE.add(FeePolicy.TX_FEE))); - viewModel.collateral.set(BitSquareFormatter.formatCollateralAsBtc(viewModel.amount.get(), collateral)); - }); - - viewModel.price.addListener((ov, oldValue, newValue) -> { - double price = BitSquareFormatter.parseToDouble(newValue); - double amount = BitSquareFormatter.parseToDouble(viewModel.amount.get()); - double volume = amount * price; - viewModel.volume.set(BitSquareFormatter.formatVolume(volume)); - }); - - viewModel.volume.addListener((ov, oldValue, newValue) -> { - double volume = BitSquareFormatter.parseToDouble(newValue); - double price = BitSquareFormatter.parseToDouble(viewModel.price.get()); - if (price != 0) { - double amount = volume / price; - viewModel.amount.set(BitSquareFormatter.formatVolume(amount)); - viewModel.totals.set(BitSquareFormatter.formatTotalsAsBtc(viewModel.amount.get(), collateral, - FeePolicy.CREATE_OFFER_FEE.add(FeePolicy.TX_FEE))); - viewModel.collateral.set(BitSquareFormatter.formatCollateralAsBtc(viewModel.amount.get(), collateral)); - } - }); - - volumeTextField.focusedProperty().addListener((observableValue, oldValue, newValue) -> { - if (oldValue && !newValue) { - if (!volumeTextField.getText().equals(viewModel.volume.get())) { - Popups.openWarningPopup("Warning", "The total volume you have entered leads to invalid fractional" + - " Bitcoin amounts.\nThe amount has been adjusted and a new total volume be calculated " + - "from it."); - volumeTextField.setText(viewModel.volume.get()); - } - } - }); - - buyLabel.textProperty().bind(viewModel.directionLabel); - amountTextField.textProperty().bindBidirectional(viewModel.amount); - priceTextField.textProperty().bindBidirectional(viewModel.price); - volumeTextField.textProperty().bindBidirectional(viewModel.volume); - - minAmountTextField.textProperty().bindBidirectional(viewModel.minAmount); - collateralLabel.textProperty().bind(viewModel.collateralLabel); - collateralTextField.textProperty().bind(viewModel.collateral); - totalsTextField.textProperty().bind(viewModel.totals); - - bankAccountTypeTextField.textProperty().bind(viewModel.bankAccountType); - bankAccountCurrencyTextField.textProperty().bind(viewModel.bankAccountCurrency); - bankAccountCountyTextField.textProperty().bind(viewModel.bankAccountCounty); - - acceptedCountriesTextField.textProperty().bind(viewModel.acceptedCountries); - acceptedLanguagesTextField.textProperty().bind(viewModel.acceptedLanguages); - feeLabel.textProperty().bind(viewModel.feeLabel); - transactionIdTextField.textProperty().bind(viewModel.transactionId); - - placeOfferButton.visibleProperty().bind(viewModel.isOfferPlacedScreen.not()); - closeButton.visibleProperty().bind(viewModel.isOfferPlacedScreen); - - //TODO - /* progressIndicator.visibleProperty().bind(viewModel.isOfferPlacedScreen); - confirmationLabel.visibleProperty().bind(viewModel.isOfferPlacedScreen); - txTitleLabel.visibleProperty().bind(viewModel.isOfferPlacedScreen); - transactionIdTextField.visibleProperty().bind(viewModel.isOfferPlacedScreen); - */ - - placeOfferButton.disableProperty().bind(amountTextField.isValidProperty() - .and(minAmountTextField.isValidProperty()) - .and(volumeTextField.isValidProperty()) - .and(priceTextField.isValidProperty()).not()); - } - - private void setupValidation() { - BtcValidator amountValidator = new BtcValidator(); - amountTextField.setNumberValidator(amountValidator); - amountTextField.setErrorPopupLayoutReference((Region) amountTextField.getParent()); - - priceTextField.setNumberValidator(new FiatValidator()); - priceTextField.setErrorPopupLayoutReference((Region) amountTextField.getParent()); - - BtcValidator volumeValidator = new BtcValidator(); - volumeTextField.setNumberValidator(volumeValidator); - volumeTextField.setErrorPopupLayoutReference((Region) volumeTextField.getParent()); - - BtcValidator minAmountValidator = new BtcValidator(); - minAmountTextField.setNumberValidator(minAmountValidator); - - ValidationHelper.setupMinAmountInRangeOfAmountValidation(amountTextField, - minAmountTextField, - viewModel.amount, - viewModel.minAmount, - amountValidator, - minAmountValidator); - - amountTextField.focusedProperty().addListener((ov, oldValue, newValue) -> { - // only on focus out and ignore focus loss from window - if (!newValue && amountTextField.getScene() != null && amountTextField.getScene().getWindow().isFocused()) - volumeTextField.reValidate(); - }); - volumeTextField.focusedProperty().addListener((ov, oldValue, newValue) -> { - // only on focus out and ignore focus loss from window - if (!newValue && volumeTextField.getScene() != null && volumeTextField.getScene().getWindow().isFocused()) - amountTextField.reValidate(); - }); - priceTextField.focusedProperty().addListener((ov, oldValue, newValue) -> { - // only on focus out and ignore focus loss from window - if (!newValue && priceTextField.getScene() != null && priceTextField.getScene().getWindow().isFocused()) - volumeTextField.reValidate(); - }); - } -} - -/** - * Represents the visible state of the view - */ -class ViewModel { - final StringProperty amount = new SimpleStringProperty(); - final StringProperty minAmount = new SimpleStringProperty(); - final StringProperty price = new SimpleStringProperty(); - final StringProperty volume = new SimpleStringProperty(); - final StringProperty collateral = new SimpleStringProperty(); - final StringProperty totals = new SimpleStringProperty(); - final StringProperty directionLabel = new SimpleStringProperty(); - final StringProperty collateralLabel = new SimpleStringProperty(); - final StringProperty feeLabel = new SimpleStringProperty(); - final StringProperty bankAccountType = new SimpleStringProperty(); - final StringProperty bankAccountCurrency = new SimpleStringProperty(); - final StringProperty bankAccountCounty = new SimpleStringProperty(); - final StringProperty acceptedCountries = new SimpleStringProperty(); - final StringProperty acceptedLanguages = new SimpleStringProperty(); - final StringProperty transactionId = new SimpleStringProperty(); - final BooleanProperty isOfferPlacedScreen = new SimpleBooleanProperty(); - final BooleanProperty isPlaceOfferButtonDisabled = new SimpleBooleanProperty(false); -} \ No newline at end of file diff --git a/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferModel.java b/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferModel.java new file mode 100644 index 0000000000..86f38afda5 --- /dev/null +++ b/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferModel.java @@ -0,0 +1,148 @@ +package io.bitsquare.gui.trade.createoffer; + +import com.google.bitcoin.core.Coin; +import com.google.bitcoin.utils.Fiat; +import com.google.inject.Inject; +import io.bitsquare.bank.BankAccount; +import io.bitsquare.btc.AddressEntry; +import io.bitsquare.btc.FeePolicy; +import io.bitsquare.btc.WalletFacade; +import io.bitsquare.locale.Country; +import io.bitsquare.settings.Settings; +import io.bitsquare.trade.Direction; +import io.bitsquare.trade.TradeManager; +import io.bitsquare.user.User; +import java.util.Locale; +import java.util.UUID; +import javafx.beans.property.*; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Model: + * Does not know the Presenter and View (CodeBehind) + * Use Guice for DI + *

+ * - Holds domain data + * - Use Properties for bindable data + */ +class CreateOfferModel +{ + private static final Logger log = LoggerFactory.getLogger(CreateOfferModel.class); + + private final TradeManager tradeManager; + private final WalletFacade walletFacade; + private final Settings settings; + private final User user; + + String getOfferId() + { + return offerId; + } + + private final String offerId; + + final Coin totalFeesAsCoin; + + + private Direction direction = null; + + Coin amountAsCoin; + Coin minAmountAsCoin; + Coin collateralAsCoin; + Fiat priceAsFiat; + Fiat tradeVolumeAsFiat; + + AddressEntry addressEntry; + + final ObjectProperty totalToPayAsCoin = new SimpleObjectProperty<>(); + final LongProperty collateralAsLong = new SimpleLongProperty(); + final BooleanProperty requestPlaceOfferSuccess = new SimpleBooleanProperty(false); + final BooleanProperty requestPlaceOfferFailed = new SimpleBooleanProperty(false); + final StringProperty requestPlaceOfferErrorMessage = new SimpleStringProperty(); + final StringProperty transactionId = new SimpleStringProperty(); + + final StringProperty bankAccountCurrency = new SimpleStringProperty(); + final StringProperty bankAccountCounty = new SimpleStringProperty(); + final StringProperty bankAccountType = new SimpleStringProperty(); + ObservableList acceptedCountries = FXCollections.observableArrayList(); + ObservableList acceptedLanguages = FXCollections.observableArrayList(); + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor + /////////////////////////////////////////////////////////////////////////////////////////// + + @Inject + CreateOfferModel(TradeManager tradeManager, WalletFacade walletFacade, Settings settings, User user) + { + this.tradeManager = tradeManager; + this.walletFacade = walletFacade; + this.settings = settings; + this.user = user; + + offerId = UUID.randomUUID().toString(); + totalFeesAsCoin = FeePolicy.CREATE_OFFER_FEE.add(FeePolicy.TX_FEE); + if (walletFacade != null && walletFacade.getWallet() != null) addressEntry = walletFacade.getAddressInfoByTradeID(offerId); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Methods + /////////////////////////////////////////////////////////////////////////////////////////// + + void activate() + { + collateralAsLong.set(settings.getCollateral()); + + BankAccount bankAccount = user.getCurrentBankAccount(); + if (bankAccount != null) + { + bankAccountType.set(bankAccount.getBankAccountType().toString()); + bankAccountCurrency.set(bankAccount.getCurrency().getCurrencyCode()); + bankAccountCounty.set(bankAccount.getCountry().getName()); + } + acceptedCountries.setAll(settings.getAcceptedCountries()); + acceptedLanguages.setAll(settings.getAcceptedLanguageLocales()); + } + + void placeOffer() + { + tradeManager.requestPlaceOffer(offerId, + direction, + priceAsFiat.value, + amountAsCoin, + minAmountAsCoin, + (transaction) -> { + requestPlaceOfferSuccess.set(true); + transactionId.set(transaction.getHashAsString()); + }, + (errorMessage) -> { + requestPlaceOfferFailed.set(true); + requestPlaceOfferErrorMessage.set(errorMessage); + } + ); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Setter/Getter + /////////////////////////////////////////////////////////////////////////////////////////// + + Direction getDirection() + { + return direction; + } + + void setDirection(Direction direction) + { + // direction must not be changed once it is initially set + checkArgument(this.direction == null); + this.direction = direction; + } + + +} diff --git a/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferPresenter.java b/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferPresenter.java new file mode 100644 index 0000000000..a858ecae17 --- /dev/null +++ b/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferPresenter.java @@ -0,0 +1,307 @@ +package io.bitsquare.gui.trade.createoffer; + +import io.bitsquare.gui.util.BSFormatter; +import io.bitsquare.locale.Localisation; +import io.bitsquare.trade.Direction; +import io.bitsquare.trade.orderbook.OrderBookFilter; + +import com.google.bitcoin.core.Coin; +import com.google.bitcoin.utils.ExchangeRate; + +import javafx.beans.Observable; +import javafx.beans.binding.Bindings; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static io.bitsquare.gui.util.BSFormatter.*; +import static javafx.beans.binding.Bindings.createStringBinding; + +/** + * Presenter: + * Knows Model, does not know the View (CodeBehind) + *

+ * - Holds data and state of the View (formatted) + * - Receive view input from Controller. Validates input, apply business logic, format to Presenter properties and convert input to Model. + * - Listen to updates from Model, apply business logic and format it to Presenter properties. Model update handling can be done via Binding. + */ +class CreateOfferPresenter +{ + private static final Logger log = LoggerFactory.getLogger(CreateOfferPresenter.class); + + private CreateOfferModel model; + + final StringProperty amount = new SimpleStringProperty(); + final StringProperty minAmount = new SimpleStringProperty(); + final StringProperty price = new SimpleStringProperty(); + final StringProperty volume = new SimpleStringProperty(); + final StringProperty collateral = new SimpleStringProperty(); + final StringProperty totalToPay = new SimpleStringProperty(); + final StringProperty directionLabel = new SimpleStringProperty(); + final StringProperty collateralLabel = new SimpleStringProperty(); + final StringProperty totalFeesLabel = new SimpleStringProperty(); + final StringProperty bankAccountType = new SimpleStringProperty(); + final StringProperty bankAccountCurrency = new SimpleStringProperty(); + final StringProperty bankAccountCounty = new SimpleStringProperty(); + final StringProperty acceptedCountries = new SimpleStringProperty(); + final StringProperty acceptedLanguages = new SimpleStringProperty(); + final StringProperty address = new SimpleStringProperty(); + final StringProperty paymentLabel = new SimpleStringProperty(); + final StringProperty transactionId = new SimpleStringProperty(); + final BooleanProperty isOfferPlacedScreen = new SimpleBooleanProperty(); + final BooleanProperty placeOfferButtonVisible = new SimpleBooleanProperty(true); + final BooleanProperty isPlaceOfferButtonDisabled = new SimpleBooleanProperty(); + final BooleanProperty validateInput = new SimpleBooleanProperty(); + final BooleanProperty showVolumeAdjustedWarning = new SimpleBooleanProperty(); + final ObjectProperty totalToPayAsCoin = new SimpleObjectProperty<>(); + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor + /////////////////////////////////////////////////////////////////////////////////////////// + + CreateOfferPresenter(CreateOfferModel model) + { + this.model = model; + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Lifecycle + /////////////////////////////////////////////////////////////////////////////////////////// + + void onViewInitialized() + { + totalFeesLabel.set(BSFormatter.formatBtc(model.totalFeesAsCoin)); + paymentLabel.set("Bitsquare trade (" + model.getOfferId() + ")"); + // address.set(model.addressEntry.getAddress().toString()); + + setupInputListeners(); + + collateralLabel.bind(Bindings.createStringBinding(() -> "Collateral (" + BSFormatter.formatCollateralPercent(model.collateralAsLong.get()) + "):", model.collateralAsLong)); + bankAccountType.bind(Bindings.createStringBinding(() -> Localisation.get(model.bankAccountType.get()), model.bankAccountType)); + bankAccountCurrency.bind(model.bankAccountCurrency); + bankAccountCounty.bind(model.bankAccountCounty); + totalToPayAsCoin.bind(model.totalToPayAsCoin); + + model.acceptedCountries.addListener((Observable o) -> acceptedCountries.set(BSFormatter.countryLocalesToString(model.acceptedCountries))); + model.acceptedLanguages.addListener((Observable o) -> acceptedLanguages.set(BSFormatter.languageLocalesToString(model.acceptedLanguages))); + + } + + void deactivate() + { + } + + void activate() + { + model.activate(); + + + + // totalToPay.addListener((ov) -> addressTextField.setAmountToPay(model.totalToPayAsCoin)); + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // Public methods + /////////////////////////////////////////////////////////////////////////////////////////// + + + void setOrderBookFilter(OrderBookFilter orderBookFilter) + { + // model + model.setDirection(orderBookFilter.getDirection()); + model.amountAsCoin = orderBookFilter.getAmount(); + model.minAmountAsCoin = orderBookFilter.getAmount(); + //TODO + model.priceAsFiat = parseToFiat(String.valueOf(orderBookFilter.getPrice())); + + // view props + directionLabel.set(model.getDirection() == Direction.BUY ? "Buy:" : "Sell:"); + amount.set(formatBtc(model.amountAsCoin)); + minAmount.set(formatBtc(model.minAmountAsCoin)); + price.set(formatFiat(model.priceAsFiat)); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // View Events + /////////////////////////////////////////////////////////////////////////////////////////// + + void placeOffer() + { + model.amountAsCoin = parseToCoin(amount.get()); + model.minAmountAsCoin = parseToCoin(minAmount.get()); + model.priceAsFiat = parseToFiat(price.get()); + model.minAmountAsCoin = parseToCoin(minAmount.get()); + + validateInput.set(true); + + //balanceTextField.getBalance() + + if (inputValid()) + { + model.placeOffer(); + isPlaceOfferButtonDisabled.set(true); + placeOfferButtonVisible.set(true); + + } + + /* + { + isOfferPlacedScreen.set(true); + transactionId.set(transaction.getHashAsString()); + } + errorMessage -> { + Popups.openErrorPopup("An error occurred", errorMessage); + isPlaceOfferButtonDisabled.set(false); + } + */ + } + + + void close() + { + + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // + /////////////////////////////////////////////////////////////////////////////////////////// + + private boolean inputValid() + { + //TODO + return true; + } + + void setupInputListeners() + { + + // bindBidirectional for amount, price, volume and minAmount + amount.addListener(ov -> { + model.amountAsCoin = parseToCoin(amount.get()); + setVolume(); + setTotalToPay(); + setCollateral(); + }); + + price.addListener(ov -> { + model.priceAsFiat = parseToFiat(price.get()); + setVolume(); + setTotalToPay(); + setCollateral(); + }); + + volume.addListener(ov -> { + model.tradeVolumeAsFiat = parseToFiat(volume.get()); + setAmount(); + setTotalToPay(); + setCollateral(); + }); + } + + + private void setVolume() + { + model.amountAsCoin = parseToCoin(amount.get()); + model.priceAsFiat = parseToFiat(price.get()); + + if (model.priceAsFiat != null && model.amountAsCoin != null && !model.amountAsCoin.isZero()) + { + model.tradeVolumeAsFiat = new ExchangeRate(model.priceAsFiat).coinToFiat(model.amountAsCoin); + volume.set(formatFiat(model.tradeVolumeAsFiat)); + } + } + + private void setAmount() + { + model.tradeVolumeAsFiat = parseToFiat(volume.get()); + model.priceAsFiat = parseToFiat(price.get()); + + if (model.tradeVolumeAsFiat != null && model.priceAsFiat != null && !model.priceAsFiat.isZero()) + { + model.amountAsCoin = new ExchangeRate(model.priceAsFiat).fiatToCoin(model.tradeVolumeAsFiat); + + // If we got a btc value with more then 4 decimals we convert it to max 4 decimals + model.amountAsCoin = applyFormatRules(model.amountAsCoin); + amount.set(formatBtc(model.amountAsCoin)); + setTotalToPay(); + setCollateral(); + } + } + + private void setTotalToPay() + { + setCollateral(); + + if (model.collateralAsCoin != null) + { + model.totalToPayAsCoin.set(model.collateralAsCoin.add(model.totalFeesAsCoin)); + totalToPay.bind(createStringBinding(() -> formatBtcWithCode(model.totalToPayAsCoin.get()), model.totalToPayAsCoin)); + } + } + + private void setCollateral() + { + if (model.amountAsCoin != null) + { + model.collateralAsCoin = model.amountAsCoin.multiply(model.collateralAsLong.get()).divide(1000); + collateral.set(BSFormatter.formatBtcWithCode(model.collateralAsCoin)); + } + } + + // We adjust the volume if fractional coins result from volume/price division on focus out + void checkVolumeOnFocusOut(Boolean oldValue, Boolean newValue, String volumeTextFieldText) + { + if (oldValue && !newValue) + { + setVolume(); + if (!formatFiat(parseToFiat(volumeTextFieldText)).equals(volume.get())) + showVolumeAdjustedWarning.set(true); + } + + + // + // only on focus out and ignore focus loss from window + /* if (!newValue && volumeTextField.getScene() != null && volumeTextField.getScene().getWindow().isFocused()) + amountTextField.reValidate();*/ + } + + void onFocusOutAmountTextField(Boolean oldValue, Boolean newValue) + { + // only on focus out and ignore focus loss from window + /* if (!newValue && amountTextField.getScene() != null && amountTextField.getScene().getWindow().isFocused()) + volumeTextField.reValidate();*/ + } + + void onFocusOutPriceTextField(Boolean oldValue, Boolean newValue) + { + // only on focus out and ignore focus loss from window + /* if (!newValue && priceTextField.getScene() != null && priceTextField.getScene().getWindow().isFocused()) + volumeTextField.reValidate();*/ + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Getters + /////////////////////////////////////////////////////////////////////////////////////////// + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Setters + /////////////////////////////////////////////////////////////////////////////////////////// + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Private methods + /////////////////////////////////////////////////////////////////////////////////////////// + + +} diff --git a/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferView.fxml b/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferView.fxml index 6d1fe0789d..55f4b13480 100644 --- a/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferView.fxml +++ b/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferView.fxml @@ -25,7 +25,7 @@ - @@ -74,7 +74,7 @@