merged with cbeams formatting changes. use MVP pattern for create offer screen

This commit is contained in:
Manfred Karrer 2014-08-26 16:57:31 +02:00
parent 7f67d5545d
commit 1c3c8b9d21
29 changed files with 1232 additions and 601 deletions

13
pom.xml
View file

@ -238,6 +238,19 @@
<artifactId>annotations</artifactId> <artifactId>annotations</artifactId>
<version>13.0</version> <version>13.0</version>
</dependency> </dependency>
<dependency>
<groupId>net.glxn</groupId>
<artifactId>qrgen</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
<properties> <properties>

View file

@ -22,7 +22,7 @@ import io.bitsquare.btc.BlockChainFacade;
import io.bitsquare.btc.FeePolicy; import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.WalletFacade; import io.bitsquare.btc.WalletFacade;
import io.bitsquare.crypto.CryptoFacade; 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.BootstrappedPeerFactory;
import io.bitsquare.msg.MessageFacade; import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.P2PNode; import io.bitsquare.msg.P2PNode;
@ -64,7 +64,7 @@ public class BitSquareModule extends AbstractModule {
bind(BootstrappedPeerFactory.class).asEagerSingleton(); bind(BootstrappedPeerFactory.class).asEagerSingleton();
bind(TradeManager.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); //bind(String.class).annotatedWith(Names.named("networkType")).toInstance(WalletFacade.MAIN_NET);

View file

@ -23,7 +23,7 @@ import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.di.GuiceFXMLLoader; import io.bitsquare.di.GuiceFXMLLoader;
import io.bitsquare.gui.components.NetworkSyncPane; import io.bitsquare.gui.components.NetworkSyncPane;
import io.bitsquare.gui.orders.OrdersController; 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.ImageUtil;
import io.bitsquare.gui.util.Profiler; import io.bitsquare.gui.util.Profiler;
import io.bitsquare.gui.util.Transitions; import io.bitsquare.gui.util.Transitions;
@ -365,11 +365,11 @@ public class MainController extends ViewController {
balanceTextField.setEditable(false); balanceTextField.setEditable(false);
balanceTextField.setPrefWidth(110); balanceTextField.setPrefWidth(110);
balanceTextField.setId("nav-balance-label"); balanceTextField.setId("nav-balance-label");
balanceTextField.setText(BitSquareFormatter.formatCoinWithCode(walletFacade.getWalletBalance())); balanceTextField.setText(BSFormatter.formatCoinWithCode(walletFacade.getWalletBalance()));
walletFacade.addBalanceListener(new BalanceListener() { walletFacade.addBalanceListener(new BalanceListener() {
@Override @Override
public void onBalanceChanged(Coin balance) { 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 -> user.getSelectedBankAccountIndexProperty().addListener(observable ->
accountComboBox.getSelectionModel().select(user.getCurrentBankAccount())); accountComboBox.getSelectionModel().select(user.getCurrentBankAccount()));
user.getBankAccountsSizeProperty().addListener(observable -> { user.getBankAccountsSizeProperty().addListener(observable -> {
accountComboBox.setItems(FXCollections.observableArrayList(user.getBankAccounts())); accountComboBox.setItems(FXCollections.observableArrayList(user.getBankAccounts()));
// need to delay it a bit otherwise it will not be set // need to delay it a bit otherwise it will not be set

View file

@ -20,7 +20,7 @@ package io.bitsquare.gui.arbitrators.profile;
import io.bitsquare.gui.CachedViewController; import io.bitsquare.gui.CachedViewController;
import io.bitsquare.gui.NavigationItem; import io.bitsquare.gui.NavigationItem;
import io.bitsquare.gui.ViewController; 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.settings.Settings;
import io.bitsquare.storage.Persistence; import io.bitsquare.storage.Persistence;
import io.bitsquare.user.Arbitrator; import io.bitsquare.user.Arbitrator;
@ -124,16 +124,16 @@ public class ArbitratorProfileController extends CachedViewController {
nameLabel.setText(name); nameLabel.setText(name);
nameTextField.setText(arbitrator.getName()); nameTextField.setText(arbitrator.getName());
languagesTextField.setText(BitSquareFormatter.languageLocalesToString(arbitrator.getLanguages())); languagesTextField.setText(BSFormatter.languageLocalesToString(arbitrator.getLanguages()));
reputationTextField.setText(arbitrator.getReputation().toString()); reputationTextField.setText(arbitrator.getReputation().toString());
maxTradeVolumeTextField.setText(String.valueOf(arbitrator.getMaxTradeVolume()) + " BTC"); maxTradeVolumeTextField.setText(String.valueOf(arbitrator.getMaxTradeVolume()) + " BTC");
passiveServiceFeeTextField.setText(String.valueOf(arbitrator.getPassiveServiceFee()) + " % (Min. " + 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 arbitrationFeeTextField.setText(String.valueOf(arbitrator.getArbitrationFee()) + " % (Min. " + String
.valueOf(arbitrator.getMinArbitrationFee()) + " BTC)"); .valueOf(arbitrator.getMinArbitrationFee()) + " BTC)");
methodsTextField.setText(BitSquareFormatter.arbitrationMethodsToString(arbitrator.getArbitrationMethods())); methodsTextField.setText(BSFormatter.arbitrationMethodsToString(arbitrator.getArbitrationMethods()));
idVerificationsTextField.setText( idVerificationsTextField.setText(
BitSquareFormatter.arbitrationIDVerificationsToString(arbitrator.getIdVerifications())); BSFormatter.arbitrationIDVerificationsToString(arbitrator.getIdVerifications()));
webPageTextField.setText(arbitrator.getWebUrl()); webPageTextField.setText(arbitrator.getWebUrl());
descriptionTextArea.setText(arbitrator.getDescription()); descriptionTextArea.setText(arbitrator.getDescription());
} }

View file

@ -23,7 +23,7 @@ import io.bitsquare.gui.NavigationItem;
import io.bitsquare.gui.ViewController; import io.bitsquare.gui.ViewController;
import io.bitsquare.gui.arbitrators.profile.ArbitratorProfileController; import io.bitsquare.gui.arbitrators.profile.ArbitratorProfileController;
import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator; 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.BitSquareValidator;
import io.bitsquare.gui.util.ConfidenceDisplay; import io.bitsquare.gui.util.ConfidenceDisplay;
import io.bitsquare.locale.LanguageUtil; import io.bitsquare.locale.LanguageUtil;
@ -132,7 +132,7 @@ public class ArbitratorRegistrationController extends CachedViewController {
} }
else { else {
languageList.add(LanguageUtil.getDefaultLanguageLocale()); languageList.add(LanguageUtil.getDefaultLanguageLocale());
languagesTextField.setText(BitSquareFormatter.languageLocalesToString(languageList)); languagesTextField.setText(BSFormatter.languageLocalesToString(languageList));
} }
languageComboBox.setItems(FXCollections.observableArrayList(LanguageUtil.getAllLanguageLocales())); 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 methodsComboBox.setItems(FXCollections.observableArrayList(new ArrayList<>(EnumSet.allOf(Arbitrator.METHOD
.class)))); .class))));
methodsComboBox.setConverter(new StringConverter<Arbitrator.METHOD>() { methodsComboBox.setConverter(new StringConverter<Arbitrator.METHOD>() {
@Override @Override
@ -277,7 +277,7 @@ public class ArbitratorRegistrationController extends CachedViewController {
Locale item = languageComboBox.getSelectionModel().getSelectedItem(); Locale item = languageComboBox.getSelectionModel().getSelectedItem();
if (!languageList.contains(item) && item != null) { if (!languageList.contains(item) && item != null) {
languageList.add(item); languageList.add(item);
languagesTextField.setText(BitSquareFormatter.languageLocalesToString(languageList)); languagesTextField.setText(BSFormatter.languageLocalesToString(languageList));
languageComboBox.getSelectionModel().clearSelection(); languageComboBox.getSelectionModel().clearSelection();
} }
} }
@ -293,7 +293,7 @@ public class ArbitratorRegistrationController extends CachedViewController {
Arbitrator.METHOD item = methodsComboBox.getSelectionModel().getSelectedItem(); Arbitrator.METHOD item = methodsComboBox.getSelectionModel().getSelectedItem();
if (!methodList.contains(item) && item != null) { if (!methodList.contains(item) && item != null) {
methodList.add(item); methodList.add(item);
methodsTextField.setText(BitSquareFormatter.arbitrationMethodsToString(methodList)); methodsTextField.setText(BSFormatter.arbitrationMethodsToString(methodList));
methodsComboBox.getSelectionModel().clearSelection(); methodsComboBox.getSelectionModel().clearSelection();
} }
} }
@ -312,7 +312,7 @@ public class ArbitratorRegistrationController extends CachedViewController {
if (!idVerificationList.contains(idVerification)) { if (!idVerificationList.contains(idVerification)) {
idVerificationList.add(idVerification); idVerificationList.add(idVerification);
idVerificationsTextField.setText( idVerificationsTextField.setText(
BitSquareFormatter.arbitrationIDVerificationsToString(idVerificationList)); BSFormatter.arbitrationIDVerificationsToString(idVerificationList));
} }
} }
@ -355,11 +355,11 @@ public class ArbitratorRegistrationController extends CachedViewController {
private void setupPayCollateralScreen() { private void setupPayCollateralScreen() {
infoLabel.setText("You need to pay 10 x the max. trading volume as collateral.\n\nThat payment will be " + 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 " + "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" + "(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" + "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 " + "depending on the overall relation of negative to positive ratings you received after a dispute " +
"resolution.\n\nPlease pay in " + arbitrator.getMaxTradeVolume() * 10 + " BTC"); "resolution.\n\nPlease pay in " + arbitrator.getMaxTradeVolume() * 10 + " BTC");
String collateralAddress = walletFacade.getRegistrationAddressEntry() != null ? String collateralAddress = walletFacade.getRegistrationAddressEntry() != null ?
@ -434,15 +434,15 @@ public class ArbitratorRegistrationController extends CachedViewController {
nameTextField.setText(arbitrator.getName()); nameTextField.setText(arbitrator.getName());
idTypeTextField.setText(Localisation.get(arbitrator.getIdType().toString())); 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())); maxTradeVolumeTextField.setText(String.valueOf(arbitrator.getMaxTradeVolume()));
passiveServiceFeeTextField.setText(String.valueOf(arbitrator.getPassiveServiceFee())); passiveServiceFeeTextField.setText(String.valueOf(arbitrator.getPassiveServiceFee()));
minPassiveServiceFeeTextField.setText(String.valueOf(arbitrator.getMinPassiveServiceFee())); minPassiveServiceFeeTextField.setText(String.valueOf(arbitrator.getMinPassiveServiceFee()));
arbitrationFeeTextField.setText(String.valueOf(arbitrator.getArbitrationFee())); arbitrationFeeTextField.setText(String.valueOf(arbitrator.getArbitrationFee()));
minArbitrationFeeTextField.setText(String.valueOf(arbitrator.getMinArbitrationFee())); minArbitrationFeeTextField.setText(String.valueOf(arbitrator.getMinArbitrationFee()));
methodsTextField.setText(BitSquareFormatter.arbitrationMethodsToString(arbitrator.getArbitrationMethods())); methodsTextField.setText(BSFormatter.arbitrationMethodsToString(arbitrator.getArbitrationMethods()));
idVerificationsTextField.setText( idVerificationsTextField.setText(
BitSquareFormatter.arbitrationIDVerificationsToString(arbitrator.getIdVerifications())); BSFormatter.arbitrationIDVerificationsToString(arbitrator.getIdVerifications()));
webPageTextField.setText(arbitrator.getWebUrl()); webPageTextField.setText(arbitrator.getWebUrl());
descriptionTextArea.setText(arbitrator.getDescription()); descriptionTextArea.setText(arbitrator.getDescription());
@ -466,30 +466,30 @@ public class ArbitratorRegistrationController extends CachedViewController {
String messagePubKeyAsHex = DSAKeyUtil.getHexStringFromPublicKey(user.getMessagePublicKey()); String messagePubKeyAsHex = DSAKeyUtil.getHexStringFromPublicKey(user.getMessagePublicKey());
String name = nameTextField.getText(); String name = nameTextField.getText();
double maxTradeVolume = BitSquareFormatter.parseToDouble(maxTradeVolumeTextField.getText()); double maxTradeVolume = BSFormatter.parseToDouble(maxTradeVolumeTextField.getText());
double passiveServiceFee = BitSquareFormatter.parseToDouble(passiveServiceFeeTextField.getText()); double passiveServiceFee = BSFormatter.parseToDouble(passiveServiceFeeTextField.getText());
double minPassiveServiceFee = BitSquareFormatter.parseToDouble(minPassiveServiceFeeTextField.getText()); double minPassiveServiceFee = BSFormatter.parseToDouble(minPassiveServiceFeeTextField.getText());
double arbitrationFee = BitSquareFormatter.parseToDouble(arbitrationFeeTextField.getText()); double arbitrationFee = BSFormatter.parseToDouble(arbitrationFeeTextField.getText());
double minArbitrationFee = BitSquareFormatter.parseToDouble(minArbitrationFeeTextField.getText()); double minArbitrationFee = BSFormatter.parseToDouble(minArbitrationFeeTextField.getText());
String webUrl = webPageTextField.getText(); String webUrl = webPageTextField.getText();
String description = descriptionTextArea.getText(); String description = descriptionTextArea.getText();
return new Arbitrator(pubKeyAsHex, return new Arbitrator(pubKeyAsHex,
messagePubKeyAsHex, messagePubKeyAsHex,
name, name,
idType, idType,
languageList, languageList,
new Reputation(), new Reputation(),
maxTradeVolume, maxTradeVolume,
passiveServiceFee, passiveServiceFee,
minPassiveServiceFee, minPassiveServiceFee,
arbitrationFee, arbitrationFee,
minArbitrationFee, minArbitrationFee,
methodList, methodList,
idVerificationList, idVerificationList,
webUrl, webUrl,
description); description);
} catch (BitSquareValidator.ValidationException e) { } catch (BitSquareValidator.ValidationException e) {
return null; return null;
} }

View file

@ -17,9 +17,7 @@
package io.bitsquare.gui.components.btc; package io.bitsquare.gui.components.btc;
import io.bitsquare.BitSquare;
import io.bitsquare.gui.components.Popups; import io.bitsquare.gui.components.Popups;
import io.bitsquare.gui.util.BitSquareFormatter;
import com.google.bitcoin.core.Coin; import com.google.bitcoin.core.Coin;
import com.google.bitcoin.uri.BitcoinURI; import com.google.bitcoin.uri.BitcoinURI;
@ -57,7 +55,8 @@ public class AddressTextField extends AnchorPane {
private final Label addressLabel; private final Label addressLabel;
private final Label qrCode; private final Label qrCode;
private String address; private String address;
private String amountToPay; private Coin amountToPay;
private String paymentLabel;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor // Constructor
@ -142,19 +141,21 @@ public class AddressTextField extends AnchorPane {
addressLabel.setText(address); addressLabel.setText(address);
} }
public void setAmountToPay(String amountToPay) { public void setAmountToPay(Coin amountToPay) {
this.amountToPay = amountToPay; this.amountToPay = amountToPay;
} }
public void setPaymentLabel(String paymentLabel) {
this.paymentLabel = paymentLabel;
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Private // Private
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private String getBitcoinURI() { private String getBitcoinURI() {
Coin d = BitSquareFormatter.parseToCoin(amountToPay); return BitcoinURI.convertToBitcoinURI(address, amountToPay, paymentLabel, null);
return BitcoinURI.convertToBitcoinURI(
address, BitSquareFormatter.parseToCoin(amountToPay), BitSquare.getAppName(), null);
} }
} }

View file

@ -154,7 +154,7 @@ public class BalanceTextField extends AnchorPane {
private void updateBalance(Coin balance) { private void updateBalance(Coin balance) {
this.balance = balance; this.balance = balance;
if (balance != null) { if (balance != null) {
//TODO use BitSquareFormatter //TODO use BSFormatter
balanceTextField.setText(balance.toFriendlyString()); balanceTextField.setText(balance.toFriendlyString());
} }
} }

View file

@ -20,7 +20,7 @@ package io.bitsquare.gui.funds.transactions;
import io.bitsquare.btc.WalletFacade; import io.bitsquare.btc.WalletFacade;
import io.bitsquare.btc.listeners.ConfidenceListener; import io.bitsquare.btc.listeners.ConfidenceListener;
import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator; 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.Address;
import com.google.bitcoin.core.Coin; import com.google.bitcoin.core.Coin;
@ -56,7 +56,7 @@ public class TransactionsListItem {
Coin valueSentFromMe = transaction.getValueSentFromMe(walletFacade.getWallet()); Coin valueSentFromMe = transaction.getValueSentFromMe(walletFacade.getWallet());
Address address = null; Address address = null;
if (valueSentToMe.isZero()) { if (valueSentToMe.isZero()) {
//TODO use BitSquareFormatter //TODO use BSFormatter
amount.set("-" + valueSentFromMe.toFriendlyString()); amount.set("-" + valueSentFromMe.toFriendlyString());
for (TransactionOutput transactionOutput : transaction.getOutputs()) { for (TransactionOutput transactionOutput : transaction.getOutputs()) {
@ -76,7 +76,7 @@ public class TransactionsListItem {
} }
} }
else if (valueSentFromMe.isZero()) { else if (valueSentFromMe.isZero()) {
//TODO use BitSquareFormatter //TODO use BSFormatter
amount.set(valueSentToMe.toFriendlyString()); amount.set(valueSentToMe.toFriendlyString());
type.set("Received with"); type.set("Received with");
@ -95,7 +95,7 @@ public class TransactionsListItem {
} }
} }
else { else {
//TODO use BitSquareFormatter //TODO use BSFormatter
amount.set(valueSentToMe.subtract(valueSentFromMe).toFriendlyString()); amount.set(valueSentToMe.subtract(valueSentFromMe).toFriendlyString());
boolean outgoing = false; boolean outgoing = false;
@ -123,7 +123,7 @@ public class TransactionsListItem {
} }
} }
date.set(BitSquareFormatter.formatDateTime(transaction.getUpdateTime())); date.set(BSFormatter.formatDateTime(transaction.getUpdateTime()));
// confidence // confidence
progressIndicator = new ConfidenceProgressIndicator(); progressIndicator = new ConfidenceProgressIndicator();

View file

@ -23,7 +23,7 @@ import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.WalletFacade; import io.bitsquare.btc.WalletFacade;
import io.bitsquare.gui.CachedViewController; import io.bitsquare.gui.CachedViewController;
import io.bitsquare.gui.components.Popups; 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 io.bitsquare.gui.util.BitSquareValidator;
import com.google.bitcoin.core.AddressFormatException; import com.google.bitcoin.core.AddressFormatException;
@ -131,7 +131,7 @@ public class WithdrawalController extends CachedViewController {
List<AddressEntry> addressEntryList = walletFacade.getAddressEntryList(); List<AddressEntry> addressEntryList = walletFacade.getAddressEntryList();
addressList = FXCollections.observableArrayList(); addressList = FXCollections.observableArrayList();
addressList.addAll(addressEntryList.stream().map(anAddressEntryList -> addressList.addAll(addressEntryList.stream().map(anAddressEntryList ->
new WithdrawalListItem(anAddressEntryList, walletFacade)).collect(Collectors.toList())); new WithdrawalListItem(anAddressEntryList, walletFacade)).collect(Collectors.toList()));
tableView.setItems(addressList); tableView.setItems(addressList);
} }
@ -148,7 +148,7 @@ public class WithdrawalController extends CachedViewController {
amountTextField, withdrawFromTextField, withdrawToTextField, changeAddressTextField); amountTextField, withdrawFromTextField, withdrawToTextField, changeAddressTextField);
BitSquareValidator.textFieldsHasDoubleValueWithReset(amountTextField); BitSquareValidator.textFieldsHasDoubleValueWithReset(amountTextField);
Coin amount = BitSquareFormatter.parseToCoin(amountTextField.getText()); Coin amount = BSFormatter.parseToCoin(amountTextField.getText());
if (BtcValidator.isMinSpendableAmount(amount)) { if (BtcValidator.isMinSpendableAmount(amount)) {
FutureCallback<Transaction> callback = new FutureCallback<Transaction>() { FutureCallback<Transaction> callback = new FutureCallback<Transaction>() {
@Override @Override
@ -171,9 +171,9 @@ public class WithdrawalController extends CachedViewController {
"Your withdrawal request:\n\n" + "Amount: " + amountTextField.getText() + " BTC\n" + "Sending" + "Your withdrawal request:\n\n" + "Amount: " + amountTextField.getText() + " BTC\n" + "Sending" +
" address: " + withdrawFromTextField.getText() + "\n" + "Receiving address: " + " address: " + withdrawFromTextField.getText() + "\n" + "Receiving address: " +
withdrawToTextField.getText() + "\n" + "Transaction fee: " + withdrawToTextField.getText() + "\n" + "Transaction fee: " +
BitSquareFormatter.formatCoinWithCode(FeePolicy.TX_FEE) + "\n" + BSFormatter.formatCoinWithCode(FeePolicy.TX_FEE) + "\n" +
"You receive in total: " + "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?"); "Are you sure you withdraw that amount?");
if (response == Dialog.Actions.OK) { if (response == Dialog.Actions.OK) {
try { try {
@ -182,7 +182,7 @@ public class WithdrawalController extends CachedViewController {
changeAddressTextField.getText(), amount, callback); changeAddressTextField.getText(), amount, callback);
} catch (AddressFormatException e) { } catch (AddressFormatException e) {
Popups.openErrorPopup("Address invalid", 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) { } catch (InsufficientMoneyException e) {
Popups.openInsufficientMoneyPopup(); Popups.openInsufficientMoneyPopup();
@ -194,7 +194,7 @@ public class WithdrawalController extends CachedViewController {
} }
else { else {
Popups.openErrorPopup("Insufficient amount", 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) { } catch (BitSquareValidator.ValidationException e) {
@ -308,7 +308,7 @@ public class WithdrawalController extends CachedViewController {
private void setConfidenceColumnCellFactory() { private void setConfidenceColumnCellFactory() {
confidenceColumn.setCellValueFactory((addressListItem) -> confidenceColumn.setCellValueFactory((addressListItem) ->
new ReadOnlyObjectWrapper(addressListItem.getValue())); new ReadOnlyObjectWrapper(addressListItem.getValue()));
confidenceColumn.setCellFactory( confidenceColumn.setCellFactory(
new Callback<TableColumn<String, WithdrawalListItem>, TableCell<String, WithdrawalListItem>>() { new Callback<TableColumn<String, WithdrawalListItem>, TableCell<String, WithdrawalListItem>>() {

View file

@ -93,7 +93,7 @@ public class WithdrawalListItem {
private void updateBalance(Coin balance) { private void updateBalance(Coin balance) {
this.balance = balance; this.balance = balance;
if (balance != null) { if (balance != null) {
//TODO use BitSquareFormatter //TODO use BSFormatter
balanceLabel.setText(balance.toFriendlyString()); balanceLabel.setText(balance.toFriendlyString());
} }
} }

View file

@ -17,7 +17,7 @@
package io.bitsquare.gui.orders.offer; package io.bitsquare.gui.orders.offer;
import io.bitsquare.gui.util.BitSquareFormatter; import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.trade.Offer; import io.bitsquare.trade.Offer;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
@ -35,12 +35,12 @@ public class OfferListItem {
public OfferListItem(Offer offer) { public OfferListItem(Offer offer) {
this.offer = offer; this.offer = offer;
this.date.set(BitSquareFormatter.formatDateTime(offer.getCreationDate())); this.date.set(BSFormatter.formatDateTime(offer.getCreationDate()));
this.price.set(BitSquareFormatter.formatPrice(offer.getPrice())); this.price.set(BSFormatter.formatPrice(offer.getPrice()));
this.amount.set(BitSquareFormatter.formatCoin( this.amount.set(BSFormatter.formatCoin(
offer.getAmount()) + " (" + BitSquareFormatter.formatCoin(offer.getMinAmount()) + ")"); offer.getAmount()) + " (" + BSFormatter.formatCoin(offer.getMinAmount()) + ")");
this.volume.set(BitSquareFormatter.formatVolumeWithMinVolume( this.volume.set(BSFormatter.formatVolumeWithMinVolume(
offer.getOfferVolume(), offer.getMinOfferVolume())); offer.getOfferVolume(), offer.getMinOfferVolume()));
this.offerId = offer.getId(); this.offerId = offer.getId();
} }

View file

@ -23,7 +23,7 @@ import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.WalletFacade; import io.bitsquare.btc.WalletFacade;
import io.bitsquare.gui.CachedViewController; import io.bitsquare.gui.CachedViewController;
import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator; 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.ConfidenceDisplay;
import io.bitsquare.gui.util.ImageUtil; import io.bitsquare.gui.util.ImageUtil;
import io.bitsquare.locale.Country; import io.bitsquare.locale.Country;
@ -157,8 +157,8 @@ public class PendingTradeController extends CachedViewController {
// select // select
Optional<PendingTradesListItem> currentTradeItemOptional = tradeItems.stream().filter((e) -> Optional<PendingTradesListItem> currentTradeItemOptional = tradeItems.stream().filter((e) ->
tradeManager.getPendingTrade() != null && tradeManager.getPendingTrade() != null &&
e.getTrade().getId().equals(tradeManager.getPendingTrade().getId())).findFirst(); e.getTrade().getId().equals(tradeManager.getPendingTrade().getId())).findFirst();
if (currentTradeItemOptional.isPresent()) { if (currentTradeItemOptional.isPresent()) {
openTradesTable.getSelectionModel().select(currentTradeItemOptional.get()); openTradesTable.getSelectionModel().select(currentTradeItemOptional.get());
} }
@ -241,7 +241,7 @@ public class PendingTradeController extends CachedViewController {
Transaction transaction = trade.getDepositTransaction(); Transaction transaction = trade.getDepositTransaction();
if (transaction == null) { if (transaction == null) {
trade.depositTxChangedProperty().addListener((observableValue, aBoolean, aBoolean2) -> trade.depositTxChangedProperty().addListener((observableValue, aBoolean, aBoolean2) ->
updateTx(trade.getDepositTransaction())); updateTx(trade.getDepositTransaction()));
} }
else { else {
updateTx(trade.getDepositTransaction()); updateTx(trade.getDepositTransaction());
@ -278,11 +278,11 @@ public class PendingTradeController extends CachedViewController {
primaryBankAccountIDTitleLabel.setText("Total fees (offer fee + tx fee):"); primaryBankAccountIDTitleLabel.setText("Total fees (offer fee + tx fee):");
secondaryBankAccountIDTitleLabel.setText("Refunded collateral:"); secondaryBankAccountIDTitleLabel.setText("Refunded collateral:");
bankAccountTypeTextField.setText(BitSquareFormatter.formatCoinWithCode(trade.getTradeAmount())); bankAccountTypeTextField.setText(BSFormatter.formatCoinWithCode(trade.getTradeAmount()));
holderNameTextField.setText(BitSquareFormatter.formatVolume(trade.getTradeVolume())); holderNameTextField.setText(BSFormatter.formatVolume(trade.getTradeVolume()));
primaryBankAccountIDTextField.setText( primaryBankAccountIDTextField.setText(
BitSquareFormatter.formatCoinWithCode(FeePolicy.CREATE_OFFER_FEE.add(FeePolicy.TX_FEE))); BSFormatter.formatCoinWithCode(FeePolicy.CREATE_OFFER_FEE.add(FeePolicy.TX_FEE)));
secondaryBankAccountIDTextField.setText(BitSquareFormatter.formatCoinWithCode(trade.getCollateralAmount())); secondaryBankAccountIDTextField.setText(BSFormatter.formatCoinWithCode(trade.getCollateralAmount()));
holderNameCopyIcon.setVisible(false); holderNameCopyIcon.setVisible(false);
primaryBankAccountIDCopyIcon.setVisible(false); primaryBankAccountIDCopyIcon.setVisible(false);
@ -370,8 +370,8 @@ public class PendingTradeController extends CachedViewController {
} catch (Exception e) { } catch (Exception e) {
log.warn("Country icon not found: /images/countries/" + log.warn("Country icon not found: /images/countries/" +
country.getCode().toLowerCase() + ".png country name: " + country.getCode().toLowerCase() + ".png country name: " +
country.getName()); country.getName());
} }
Tooltip.install(this, new Tooltip(country.getName())); Tooltip.install(this, new Tooltip(country.getName()));
} }
@ -395,7 +395,7 @@ public class PendingTradeController extends CachedViewController {
if (tradesTableItem != null) { if (tradesTableItem != null) {
BankAccountType bankAccountType = tradesTableItem.getTrade().getOffer() BankAccountType bankAccountType = tradesTableItem.getTrade().getOffer()
.getBankAccountType(); .getBankAccountType();
setText(Localisation.get(bankAccountType.toString())); setText(Localisation.get(bankAccountType.toString()));
} }
else { else {
@ -434,11 +434,11 @@ public class PendingTradeController extends CachedViewController {
if (offer.getDirection() == Direction.SELL) { if (offer.getDirection() == Direction.SELL) {
icon = buyIcon; icon = buyIcon;
title = BitSquareFormatter.formatDirection(Direction.BUY, true); title = BSFormatter.formatDirection(Direction.BUY, true);
} }
else { else {
icon = sellIcon; icon = sellIcon;
title = BitSquareFormatter.formatDirection(Direction.SELL, true); title = BSFormatter.formatDirection(Direction.SELL, true);
} }
button.setDisable(true); button.setDisable(true);
iconView.setImage(icon); iconView.setImage(icon);

View file

@ -22,7 +22,7 @@ import io.bitsquare.gui.CachedViewController;
import io.bitsquare.gui.NavigationItem; import io.bitsquare.gui.NavigationItem;
import io.bitsquare.gui.ViewController; import io.bitsquare.gui.ViewController;
import io.bitsquare.gui.components.ValidatingTextField; 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.orderbook.OrderBookController;
import io.bitsquare.gui.trade.takeoffer.TakerOfferController; import io.bitsquare.gui.trade.takeoffer.TakerOfferController;
import io.bitsquare.trade.Direction; import io.bitsquare.trade.Direction;
@ -46,7 +46,7 @@ public class TradeController extends CachedViewController {
private static final Logger log = LoggerFactory.getLogger(TradeController.class); private static final Logger log = LoggerFactory.getLogger(TradeController.class);
protected OrderBookController orderBookController; protected OrderBookController orderBookController;
protected CreateOfferController createOfferController; protected CreateOfferCodeBehind createOfferCodeBehind;
protected TakerOfferController takerOfferController; protected TakerOfferController takerOfferController;
protected GuiceFXMLLoader orderBookLoader; protected GuiceFXMLLoader orderBookLoader;
@ -76,7 +76,7 @@ public class TradeController extends CachedViewController {
// TODO find better solution // TODO find better solution
// Textfield focus out triggers validation, use runLater as quick fix... // Textfield focus out triggers validation, use runLater as quick fix...
((TabPane) root).getSelectionModel().selectedIndexProperty().addListener((observableValue) -> ((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; return orderBookController;
} }
else if (navigationItem == NavigationItem.CREATE_OFFER) { 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 // CreateOffer and TakeOffer must not be cached by GuiceFXMLLoader as we cannot use a view multiple times
// in different graphs // in different graphs
GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()), false); GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()), false);
try { try {
final Parent view = loader.load(); final Parent view = loader.load();
createOfferController = loader.getController(); createOfferCodeBehind = loader.getController();
createOfferController.setParentController(this); createOfferCodeBehind.setParentController(this);
final Tab tab = new Tab("Create offer"); final Tab tab = new Tab("Create offer");
tab.setContent(view); tab.setContent(view);
tabPane.getTabs().add(tab); tabPane.getTabs().add(tab);
tabPane.getSelectionModel().select(tabPane.getTabs().size() - 1); tabPane.getSelectionModel().select(tabPane.getTabs().size() - 1);
return createOfferController; return createOfferCodeBehind;
} catch (IOException e) { } catch (IOException e) {
log.error(e.getMessage()); log.error(e.getMessage());
} }
@ -157,7 +157,7 @@ public class TradeController extends CachedViewController {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void onCreateOfferViewRemoved() { public void onCreateOfferViewRemoved() {
createOfferController = null; createOfferCodeBehind = null;
orderBookController.onCreateOfferViewRemoved(); orderBookController.onCreateOfferViewRemoved();
} }

View file

@ -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):
* <p>
* Creates Presenter and passes Model from DI to Presenter. Does not hold a reference to Model
* <p>
* - 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)
* <p>
* View:
* - Mostly declared in FXML. Dynamic parts are declared in Controller. If more view elements need to be defined in code then use ViewBuilder.
* <p>
* 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));
}
}*/
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
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);
}

View file

@ -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
* <p>
* - 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<Coin> 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<Country> acceptedCountries = FXCollections.observableArrayList();
ObservableList<Locale> 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;
}
}

View file

@ -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)
* <p>
* - 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<Coin> 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
///////////////////////////////////////////////////////////////////////////////////////////
}

View file

@ -25,7 +25,7 @@
<?import javafx.scene.control.*?> <?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<AnchorPane fx:id="root" fx:controller="io.bitsquare.gui.trade.createoffer.CreateOfferController" <AnchorPane fx:id="root" fx:controller="io.bitsquare.gui.trade.createoffer.CreateOfferCodeBehind"
prefHeight="500" prefWidth="800" AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="10.0" prefHeight="500" prefWidth="800" AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="10.0"
AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="10.0" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="10.0"
xmlns:fx="http://javafx.com/fxml"> xmlns:fx="http://javafx.com/fxml">
@ -74,7 +74,7 @@
</Pane> </Pane>
<Label GridPane.rowIndex="4" text="Funds needed for that trade:"/> <Label GridPane.rowIndex="4" text="Funds needed for that trade:"/>
<TextField GridPane.rowIndex="4" GridPane.columnIndex="1" fx:id="totalsTextField" editable="false" <TextField GridPane.rowIndex="4" GridPane.columnIndex="1" fx:id="totalToPayTextField" editable="false"
focusTraversable="false"/> focusTraversable="false"/>
<Label GridPane.rowIndex="5" text="BTC address for funding:"/> <Label GridPane.rowIndex="5" text="BTC address for funding:"/>

View file

@ -25,9 +25,9 @@ import io.bitsquare.gui.MainController;
import io.bitsquare.gui.NavigationItem; import io.bitsquare.gui.NavigationItem;
import io.bitsquare.gui.ViewController; import io.bitsquare.gui.ViewController;
import io.bitsquare.gui.components.Popups; import io.bitsquare.gui.components.Popups;
import io.bitsquare.gui.trade.createoffer.CreateOfferController; import io.bitsquare.gui.trade.createoffer.CreateOfferCodeBehind;
import io.bitsquare.gui.trade.takeoffer.TakerOfferController; import io.bitsquare.gui.trade.takeoffer.TakerOfferController;
import io.bitsquare.gui.util.BitSquareFormatter; import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.gui.util.ImageUtil; import io.bitsquare.gui.util.ImageUtil;
import io.bitsquare.locale.Country; import io.bitsquare.locale.Country;
import io.bitsquare.locale.CurrencyUtil; import io.bitsquare.locale.CurrencyUtil;
@ -187,7 +187,7 @@ public class OrderBookController extends CachedViewController {
// handlers // handlers
amount.textProperty().addListener((observable, oldValue, newValue) -> { amount.textProperty().addListener((observable, oldValue, newValue) -> {
orderBookFilter.setAmount(BitSquareFormatter.parseToCoin(newValue)); orderBookFilter.setAmount(BSFormatter.parseToCoin(newValue));
updateVolume(); updateVolume();
}); });
@ -229,7 +229,7 @@ public class OrderBookController extends CachedViewController {
createOfferButton.setDisable(true); createOfferButton.setDisable(true);
ViewController nextController = parentController.loadViewAndGetChildController(NavigationItem.CREATE_OFFER); ViewController nextController = parentController.loadViewAndGetChildController(NavigationItem.CREATE_OFFER);
if (nextController != null) if (nextController != null)
((CreateOfferController) nextController).setOrderBookFilter(orderBookFilter); ((CreateOfferCodeBehind) nextController).setOrderBookFilter(orderBookFilter);
} }
else { else {
showRegistrationDialog(); showRegistrationDialog();
@ -261,8 +261,8 @@ public class OrderBookController extends CachedViewController {
} }
else { else {
Action response = Popups.openErrorPopup("Registration fee not confirmed yet", Action response = Popups.openErrorPopup("Registration fee not confirmed yet",
"The registration fee transaction has not been confirmed yet in the blockchain. " + "The registration fee transaction has not been confirmed yet in the blockchain. " +
"Please wait until it has at least 1 confirmation."); "Please wait until it has at least 1 confirmation.");
if (response == Dialog.Actions.OK) { if (response == Dialog.Actions.OK) {
MainController.GET_INSTANCE().loadViewAndGetChildController(NavigationItem.FUNDS); MainController.GET_INSTANCE().loadViewAndGetChildController(NavigationItem.FUNDS);
} }
@ -270,8 +270,8 @@ public class OrderBookController extends CachedViewController {
} }
else { else {
Action response = Popups.openErrorPopup("Missing registration fee", Action response = Popups.openErrorPopup("Missing registration fee",
"You have not funded the full registration fee of " + BitSquareFormatter "You have not funded the full registration fee of " + BSFormatter
.formatCoinWithCode(FeePolicy.ACCOUNT_REGISTRATION_FEE) + " BTC."); .formatCoinWithCode(FeePolicy.ACCOUNT_REGISTRATION_FEE) + " BTC.");
if (response == Dialog.Actions.OK) { if (response == Dialog.Actions.OK) {
MainController.GET_INSTANCE().loadViewAndGetChildController(NavigationItem.FUNDS); MainController.GET_INSTANCE().loadViewAndGetChildController(NavigationItem.FUNDS);
} }
@ -287,21 +287,21 @@ public class OrderBookController extends CachedViewController {
if (selectedIndex >= 0) { if (selectedIndex >= 0) {
Dialogs.CommandLink settingsCommandLink = new Dialogs.CommandLink("Open settings", Dialogs.CommandLink settingsCommandLink = new Dialogs.CommandLink("Open settings",
"You need to configure your settings before you can actively trade."); "You need to configure your settings before you can actively trade.");
Dialogs.CommandLink depositFeeCommandLink = new Dialogs.CommandLink("Deposit funds", Dialogs.CommandLink depositFeeCommandLink = new Dialogs.CommandLink("Deposit funds",
"You need to pay the registration fee before you can actively trade. That is needed as prevention" + "You need to pay the registration fee before you can actively trade. That is needed as prevention" +
" against fraud."); " against fraud.");
Dialogs.CommandLink sendRegistrationCommandLink = new Dialogs.CommandLink("Publish registration", Dialogs.CommandLink sendRegistrationCommandLink = new Dialogs.CommandLink("Publish registration",
"When settings are configured and the fee deposit is done your registration transaction will be " + "When settings are configured and the fee deposit is done your registration transaction will be " +
"published to " "published to "
+ "the Bitcoin \nnetwork."); + "the Bitcoin \nnetwork.");
List<Dialogs.CommandLink> commandLinks = Arrays.asList(settingsCommandLink, depositFeeCommandLink, List<Dialogs.CommandLink> commandLinks = Arrays.asList(settingsCommandLink, depositFeeCommandLink,
sendRegistrationCommandLink); sendRegistrationCommandLink);
Action registrationMissingAction = Popups.openRegistrationMissingPopup("Not registered yet", Action registrationMissingAction = Popups.openRegistrationMissingPopup("Not registered yet",
"Please follow these steps:", "Please follow these steps:",
"You need to register before you can place an offer.", "You need to register before you can place an offer.",
commandLinks, commandLinks,
selectedIndex); selectedIndex);
if (registrationMissingAction == settingsCommandLink) { if (registrationMissingAction == settingsCommandLink) {
MainController.GET_INSTANCE().loadViewAndGetChildController(NavigationItem.SETTINGS); MainController.GET_INSTANCE().loadViewAndGetChildController(NavigationItem.SETTINGS);
} }
@ -348,7 +348,7 @@ public class OrderBookController extends CachedViewController {
Coin requestedAmount; Coin requestedAmount;
if (!"".equals(amount.getText())) { if (!"".equals(amount.getText())) {
requestedAmount = BitSquareFormatter.parseToCoin(amount.getText()); requestedAmount = BSFormatter.parseToCoin(amount.getText());
} }
else { else {
requestedAmount = offer.getAmount(); requestedAmount = offer.getAmount();
@ -371,7 +371,7 @@ public class OrderBookController extends CachedViewController {
orderBook.applyFilter(orderBookFilter); orderBook.applyFilter(orderBookFilter);
priceColumn.setSortType((orderBookFilter.getDirection() == Direction.BUY) ? priceColumn.setSortType((orderBookFilter.getDirection() == Direction.BUY) ?
TableColumn.SortType.ASCENDING : TableColumn.SortType.DESCENDING); TableColumn.SortType.ASCENDING : TableColumn.SortType.DESCENDING);
orderBookTable.sort(); orderBookTable.sort();
if (orderBookTable.getItems() != null) { if (orderBookTable.getItems() != null) {
@ -432,11 +432,11 @@ public class OrderBookController extends CachedViewController {
else { else {
if (offer.getDirection() == Direction.SELL) { if (offer.getDirection() == Direction.SELL) {
icon = buyIcon; icon = buyIcon;
title = BitSquareFormatter.formatDirection(Direction.BUY, true); title = BSFormatter.formatDirection(Direction.BUY, true);
} }
else { else {
icon = sellIcon; icon = sellIcon;
title = BitSquareFormatter.formatDirection(Direction.SELL, true); title = BSFormatter.formatDirection(Direction.SELL, true);
} }
button.setDefaultButton(getIndex() == 0); button.setDefaultButton(getIndex() == 0);
@ -487,8 +487,8 @@ public class OrderBookController extends CachedViewController {
} catch (Exception e) { } catch (Exception e) {
log.warn("Country icon not found: /images/countries/" + log.warn("Country icon not found: /images/countries/" +
country.getCode().toLowerCase() + ".png country name: " + country.getCode().toLowerCase() + ".png country name: " +
country.getName()); country.getName());
} }
Tooltip.install(this, new Tooltip(country.getName())); Tooltip.install(this, new Tooltip(country.getName()));
} }
@ -539,7 +539,7 @@ public class OrderBookController extends CachedViewController {
d = decimalFormat.parse(newValue).doubleValue(); d = decimalFormat.parse(newValue).doubleValue();
} catch (ParseException e) { } catch (ParseException e) {
amount.setText(oldValue); amount.setText(oldValue);
d = BitSquareFormatter.parseToDouble(oldValue); d = BSFormatter.parseToDouble(oldValue);
} }
} }
return d; return d;
@ -548,7 +548,7 @@ public class OrderBookController extends CachedViewController {
private void updateVolume() { private void updateVolume() {
double a = textInputToNumber(amount.getText(), amount.getText()); double a = textInputToNumber(amount.getText(), amount.getText());
double p = textInputToNumber(price.getText(), price.getText()); double p = textInputToNumber(price.getText(), price.getText());
volume.setText(BitSquareFormatter.formatPrice(a * p)); volume.setText(BSFormatter.formatPrice(a * p));
} }

View file

@ -17,7 +17,7 @@
package io.bitsquare.gui.trade.orderbook; package io.bitsquare.gui.trade.orderbook;
import io.bitsquare.gui.util.BitSquareFormatter; import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.trade.Offer; import io.bitsquare.trade.Offer;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
@ -34,10 +34,10 @@ public class OrderBookListItem {
public OrderBookListItem(Offer offer) { public OrderBookListItem(Offer offer) {
this.offer = offer; this.offer = offer;
this.price.set(BitSquareFormatter.formatPrice(offer.getPrice())); this.price.set(BSFormatter.formatPrice(offer.getPrice()));
this.amount.set(BitSquareFormatter.formatCoin( this.amount.set(BSFormatter.formatCoin(
offer.getAmount()) + " (" + BitSquareFormatter.formatCoin(offer.getMinAmount()) + ")"); offer.getAmount()) + " (" + BSFormatter.formatCoin(offer.getMinAmount()) + ")");
this.volume.set(BitSquareFormatter.formatVolumeWithMinVolume( this.volume.set(BSFormatter.formatVolumeWithMinVolume(
offer.getOfferVolume(), offer.getMinOfferVolume())); offer.getOfferVolume(), offer.getMinOfferVolume()));
} }

View file

@ -24,7 +24,7 @@ import io.bitsquare.gui.CachedViewController;
import io.bitsquare.gui.components.Popups; import io.bitsquare.gui.components.Popups;
import io.bitsquare.gui.components.ValidatedTextField; import io.bitsquare.gui.components.ValidatedTextField;
import io.bitsquare.gui.trade.TradeController; import io.bitsquare.gui.trade.TradeController;
import io.bitsquare.gui.util.BitSquareFormatter; import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.gui.util.BitSquareValidator; import io.bitsquare.gui.util.BitSquareValidator;
import io.bitsquare.trade.Offer; import io.bitsquare.trade.Offer;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
@ -118,14 +118,14 @@ public class TakerOfferController extends CachedViewController {
public void applyData() { public void applyData() {
amountTextField.setText(requestedAmount.toPlainString()); amountTextField.setText(requestedAmount.toPlainString());
amountTextField.setPromptText(BitSquareFormatter.formatCoinWithCode( amountTextField.setPromptText(BSFormatter.formatCoinWithCode(
offer.getMinAmount()) + " - " + BitSquareFormatter.formatCoinWithCode(offer.getAmount())); offer.getMinAmount()) + " - " + BSFormatter.formatCoinWithCode(offer.getAmount()));
priceTextField.setText(BitSquareFormatter.formatPrice(offer.getPrice())); priceTextField.setText(BSFormatter.formatPrice(offer.getPrice()));
applyVolume(); applyVolume();
collateralLabel.setText("Collateral (" + getCollateralAsPercent() + "):"); collateralLabel.setText("Collateral (" + getCollateralAsPercent() + "):");
applyCollateral(); applyCollateral();
applyTotal(); applyTotal();
feeTextField.setText(BitSquareFormatter.formatCoinWithCode(getFee())); feeTextField.setText(BSFormatter.formatCoinWithCode(getFee()));
totalTextField.setText(getFormattedTotal()); totalTextField.setText(getFormattedTotal());
bankAccountTypeTextField.setText(offer.getBankAccountType().toString()); bankAccountTypeTextField.setText(offer.getBankAccountType().toString());
@ -134,9 +134,9 @@ public class TakerOfferController extends CachedViewController {
//todo list //todo list
// arbitratorsTextField.setText(offer.getArbitrator().getName()); // arbitratorsTextField.setText(offer.getArbitrator().getName());
supportedLanguagesTextField.setText(BitSquareFormatter.languageLocalesToString( supportedLanguagesTextField.setText(BSFormatter.languageLocalesToString(
offer.getAcceptedLanguageLocales())); offer.getAcceptedLanguageLocales()));
supportedCountriesTextField.setText(BitSquareFormatter.countryLocalesToString(offer.getAcceptedCountries())); supportedCountriesTextField.setText(BSFormatter.countryLocalesToString(offer.getAcceptedCountries()));
amountTextField.textProperty().addListener(e -> { amountTextField.textProperty().addListener(e -> {
applyVolume(); applyVolume();
@ -153,7 +153,7 @@ public class TakerOfferController extends CachedViewController {
@FXML @FXML
public void onTakeOffer() { public void onTakeOffer() {
AddressEntry addressEntry = walletFacade.getAddressInfoByTradeID(offer.getId()); AddressEntry addressEntry = walletFacade.getAddressInfoByTradeID(offer.getId());
Coin amount = BitSquareFormatter.parseToCoin(getAmountString()); Coin amount = BSFormatter.parseToCoin(getAmountString());
// TODO more validation (fee payment, blacklist,...) // TODO more validation (fee payment, blacklist,...)
if (amountTextField.isInvalid()) { if (amountTextField.isInvalid()) {
Popups.openErrorPopup("Invalid input", "The requested amount you entered is not a valid amount."); Popups.openErrorPopup("Invalid input", "The requested amount you entered is not a valid amount.");
@ -168,7 +168,7 @@ public class TakerOfferController extends CachedViewController {
} }
else if (tradeManager.isOfferAlreadyInTrades(offer)) { else if (tradeManager.isOfferAlreadyInTrades(offer)) {
Popups.openErrorPopup("Offer previously accepted", Popups.openErrorPopup("Offer previously accepted",
"You have that offer already taken. Open the offer section to find that trade."); "You have that offer already taken. Open the offer section to find that trade.");
} }
else { else {
takeOfferButton.setDisable(true); takeOfferButton.setDisable(true);
@ -179,8 +179,8 @@ public class TakerOfferController extends CachedViewController {
setDepositTxId(depositTxId); setDepositTxId(depositTxId);
accordion.setExpandedPane(waitBankTxTitledPane); accordion.setExpandedPane(waitBankTxTitledPane);
infoLabel.setText("Deposit transaction published by offerer.\n" + infoLabel.setText("Deposit transaction published by offerer.\n" +
"As soon as the offerer starts the \n" + "As soon as the offerer starts the \n" +
"Bank transfer, you will get informed."); "Bank transfer, you will get informed.");
depositTxIdTextField.setText(depositTxId); depositTxIdTextField.setText(depositTxId);
} }
@ -196,11 +196,11 @@ public class TakerOfferController extends CachedViewController {
public void onPayoutTxPublished(Trade trade, String payoutTxId) { public void onPayoutTxPublished(Trade trade, String payoutTxId) {
accordion.setExpandedPane(summaryTitledPane); accordion.setExpandedPane(summaryTitledPane);
summaryPaidTextField.setText(BitSquareFormatter.formatCoinWithCode(trade.getTradeAmount())); summaryPaidTextField.setText(BSFormatter.formatCoinWithCode(trade.getTradeAmount()));
summaryReceivedTextField.setText(BitSquareFormatter.formatVolume(trade.getTradeVolume())); summaryReceivedTextField.setText(BSFormatter.formatVolume(trade.getTradeVolume()));
summaryFeesTextField.setText(BitSquareFormatter.formatCoinWithCode( summaryFeesTextField.setText(BSFormatter.formatCoinWithCode(
FeePolicy.TAKE_OFFER_FEE.add(FeePolicy.TX_FEE))); FeePolicy.TAKE_OFFER_FEE.add(FeePolicy.TX_FEE)));
summaryCollateralTextField.setText(BitSquareFormatter.formatCoinWithCode( summaryCollateralTextField.setText(BSFormatter.formatCoinWithCode(
trade.getCollateralAmount())); trade.getCollateralAmount()));
summaryDepositTxIdTextField.setText(depositTxId); summaryDepositTxIdTextField.setText(depositTxId);
summaryPayoutTxIdTextField.setText(payoutTxId); summaryPayoutTxIdTextField.setText(payoutTxId);
@ -210,7 +210,7 @@ public class TakerOfferController extends CachedViewController {
public void onFault(Throwable throwable, ProtocolForTakerAsSeller.State state) { public void onFault(Throwable throwable, ProtocolForTakerAsSeller.State state) {
log.error("Error while executing trade process at state: " + state + " / " + throwable); log.error("Error while executing trade process at state: " + state + " / " + throwable);
Popups.openErrorPopup("Error while executing trade process", Popups.openErrorPopup("Error while executing trade process",
"Error while executing trade process at state: " + state + " / " + throwable); "Error while executing trade process at state: " + state + " / " + throwable);
} }
@Override @Override
@ -227,8 +227,8 @@ public class TakerOfferController extends CachedViewController {
public void onTakeOfferRequestRejected(Trade trade) { public void onTakeOfferRequestRejected(Trade trade) {
log.error("Take offer request rejected"); log.error("Take offer request rejected");
Popups.openErrorPopup("Take offer request rejected", Popups.openErrorPopup("Take offer request rejected",
"Your take offer request has been rejected. It might be that the offerer got another " + "Your take offer request has been rejected. It might be that the offerer got another " +
"request shortly before your request arrived."); "request shortly before your request arrived.");
} }
}); });
} }
@ -265,21 +265,21 @@ public class TakerOfferController extends CachedViewController {
// formatted // formatted
private String getFormattedVolume() { private String getFormattedVolume() {
return BitSquareFormatter.formatVolume(getVolume()); return BSFormatter.formatVolume(getVolume());
} }
private String getFormattedTotal() { private String getFormattedTotal() {
return BitSquareFormatter.formatCoinWithCode(getTotal()); return BSFormatter.formatCoinWithCode(getTotal());
} }
// values // values
private double getAmountAsDouble() { private double getAmountAsDouble() {
return BitSquareFormatter.parseToDouble(getAmountString()); return BSFormatter.parseToDouble(getAmountString());
} }
private Coin getAmountInSatoshis() { private Coin getAmountInSatoshis() {
return BitSquareFormatter.parseToCoin(getAmountString()); return BSFormatter.parseToCoin(getAmountString());
} }
private String getAmountString() { private String getAmountString() {
@ -304,21 +304,21 @@ public class TakerOfferController extends CachedViewController {
} }
private Coin getCollateralAsCoin() { private Coin getCollateralAsCoin() {
Coin amountAsCoin = BitSquareFormatter.parseToCoin(getAmountString()); Coin amountAsCoin = BSFormatter.parseToCoin(getAmountString());
return amountAsCoin.divide((long) (1d / offer.getCollateral())); return amountAsCoin.divide((long) (1d / offer.getCollateral()));
} }
private String getFormattedCollateralAsBtc() { private String getFormattedCollateralAsBtc() {
Coin amountAsCoin = BitSquareFormatter.parseToCoin(getAmountString()); Coin amountAsCoin = BSFormatter.parseToCoin(getAmountString());
Coin collateralAsCoin = amountAsCoin.divide((long) (1d / getCollateral())); Coin collateralAsCoin = amountAsCoin.divide((long) (1d / getCollateral()));
return BitSquareFormatter.formatCoin(collateralAsCoin); return BSFormatter.formatCoin(collateralAsCoin);
} }
private String getCollateralAsPercent() { private String getCollateralAsPercent() {
return BitSquareFormatter.formatCollateralPercent(getCollateral()); return BSFormatter.formatCollateralPercent(getCollateral());
} }
private double getCollateral() { private long getCollateral() {
// TODO // TODO
return offer.getCollateral(); return offer.getCollateral();
} }

View file

@ -23,10 +23,13 @@ import io.bitsquare.trade.Direction;
import io.bitsquare.user.Arbitrator; import io.bitsquare.user.Arbitrator;
import com.google.bitcoin.core.Coin; import com.google.bitcoin.core.Coin;
import com.google.bitcoin.utils.CoinFormat;
import com.google.bitcoin.utils.Fiat;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.Currency;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -36,44 +39,85 @@ import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.*; import static com.google.common.base.Preconditions.*;
//TODO cleanup... //TODO a lot of old trash... need to cleanup...
public class BitSquareFormatter { public class BSFormatter
private static final Logger log = LoggerFactory.getLogger(BitSquareFormatter.class); {
private static final Logger log = LoggerFactory.getLogger(BSFormatter.class);
// format is like: 1,00 or 1,0010 never more then 4 decimals
private static CoinFormat coinFormat = CoinFormat.BTC.repeatOptionalDecimals(2, 1);
// format is like: 1,00 never more then 2 decimals
private static CoinFormat fiatFormat = CoinFormat.FIAT.repeatOptionalDecimals(0, 0);
private static String currencyCode = Currency.getInstance(Locale.getDefault()).getCurrencyCode();
private static Locale locale = Locale.getDefault();
public static void useMilliBitFormat()
{
coinFormat = CoinFormat.MBTC.repeatOptionalDecimals(2, 1);
}
public static void setFiatCurrencyCode(String currencyCode)
{
BSFormatter.currencyCode = currencyCode;
}
public static void setLocale(Locale locale)
{
BSFormatter.locale = locale;
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// BTC // BTC
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public static String formatCoin(Coin coin) { public static String formatBtc(Coin coin)
return coin != null ? coin.toPlainString() : ""; {
try
{
return coinFormat.noCode().format(coin).toString();
} catch (Throwable t)
{
log.warn("Exception at formatBtc: " + t.toString());
return "";
}
} }
public static String formatBtcWithCode(Coin coin)
/* public static String formatCoinToWithSymbol(Coin coin)
{ {
return "฿ " + coin.toPlainString(); try
} */ {
return coinFormat.postfixCode().format(coin).toString();
} catch (Throwable t)
{
log.warn("Exception at formatBtcWithCode: " + t.toString());
return "";
}
}
public static String formatCoinWithCode(Coin coin) { public static Coin parseToCoin(String input)
return coin != null ? coin.toFriendlyString() : ""; {
try
{
input = input.replace(",", ".");
Double.parseDouble(input); // test if valid double
return Coin.parseCoin(input);
} catch (Throwable t)
{
log.warn("Exception at parseToCoin: " + t.toString());
return Coin.ZERO;
}
} }
/** /**
* @param input String input in decimal or integer format. Both decimal marks (",", ".") are supported. * Transform a coin with the properties defined in the format (used to reduce decimal places)
* If input has an incorrect format it returns a zero value coin. *
* @return * @param coin The coin which should be transformed
* @return The transformed coin
*/ */
public static Coin parseToCoin(String input) { public static Coin applyFormatRules(Coin coin)
Coin result; {
try { return parseToCoin(formatBtc(coin));
input = input.replace(",", ".");
Double.parseDouble(input);
result = Coin.parseCoin(input);
} catch (Exception e) {
//log.warn("Exception at parseBtcToCoin: " + e.toString());
result = Coin.ZERO;
}
return result;
} }
@ -81,16 +125,42 @@ public class BitSquareFormatter {
// FIAT // FIAT
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public static String formatPrice(double price) { public static String formatFiat(Fiat fiat)
return formatDouble(price); {
try
{
return fiatFormat.noCode().format(fiat).toString();
} catch (Throwable t)
{
log.warn("Exception at formatFiat: " + t.toString());
return "";
}
} }
public static String formatVolume(double volume) { public static String formatFiatWithCode(Fiat fiat)
return formatDouble(volume); {
try
{
return fiatFormat.postfixCode().format(fiat).toString();
} catch (Throwable t)
{
log.warn("Exception at formatFiatWithCode: " + t.toString());
return "";
}
} }
public static String formatVolumeWithMinVolume(double volume, double minVolume) { public static Fiat parseToFiat(String input)
return formatDouble(volume) + " (" + formatDouble(minVolume) + ")"; {
try
{
input = input.replace(",", ".");
Double.parseDouble(input); // test if valid double
return Fiat.parseFiat(currencyCode, input);
} catch (Exception e)
{
//log.warn("Exception at parseBtcToCoin: " + e.toString());
return Fiat.valueOf(currencyCode, 0);
}
} }
@ -99,79 +169,79 @@ public class BitSquareFormatter {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
/** /**
* @param input String to be converted to a double. Both decimal points "." and ", * @param input String to be converted to a double. Both decimal points "." and "," are supported. Thousands separator is not supported.
* " are supported. Thousands separator is not supported.
* @return Returns a double value. Any invalid value returns Double.NEGATIVE_INFINITY. * @return Returns a double value. Any invalid value returns Double.NEGATIVE_INFINITY.
*/ */
public static double parseToDouble(String input) { public static double parseToDouble(String input)
try { {
try
{
checkNotNull(input); checkNotNull(input);
checkArgument(input.length() > 0); checkArgument(input.length() > 0);
input = input.replace(",", ".").trim(); input = input.replace(",", ".").trim();
return Double.parseDouble(input); return Double.parseDouble(input);
} catch (Exception e) { } catch (Exception e)
{
return 0; return 0;
} }
} }
public static String formatCollateralAsBtc(String amount, double collateral) { public static String formatDirection(Direction direction, boolean allUpperCase)
Coin amountAsCoin = BitSquareFormatter.parseToCoin(amount); {
Coin collateralAsCoin = amountAsCoin.divide((long) (1d / collateral));
return formatCoinWithCode(collateralAsCoin);
}
public static String formatTotalsAsBtc(String amount, double collateral, Coin fees) {
Coin amountAsCoin = BitSquareFormatter.parseToCoin(amount);
Coin collateralAsCoin = amountAsCoin.divide((long) (1d / collateral));
Coin totals = collateralAsCoin.add(fees);
return formatCoinWithCode(totals);
}
public static String formatDirection(Direction direction, boolean allUpperCase) {
String result = (direction == Direction.BUY) ? "Buy" : "Sell"; String result = (direction == Direction.BUY) ? "Buy" : "Sell";
if (allUpperCase) { if (allUpperCase)
{
result = result.toUpperCase(); result = result.toUpperCase();
} }
return result; return result;
} }
public static String formatDouble(double value) { public static String formatDouble(double value)
{
return formatDouble(value, 4); return formatDouble(value, 4);
} }
public static String formatDouble(double value, int fractionDigits) { public static String formatDouble(double value, int fractionDigits)
{
DecimalFormat decimalFormat = getDecimalFormat(fractionDigits); DecimalFormat decimalFormat = getDecimalFormat(fractionDigits);
return decimalFormat.format(value); return decimalFormat.format(value);
} }
public static DecimalFormat getDecimalFormat(int fractionDigits) { public static DecimalFormat getDecimalFormat(int fractionDigits)
DecimalFormat decimalFormat = (DecimalFormat) DecimalFormat.getInstance(Locale.getDefault()); {
DecimalFormat decimalFormat = (DecimalFormat) DecimalFormat.getInstance(locale);
decimalFormat.setMinimumFractionDigits(fractionDigits); decimalFormat.setMinimumFractionDigits(fractionDigits);
decimalFormat.setMaximumFractionDigits(fractionDigits); decimalFormat.setMaximumFractionDigits(fractionDigits);
decimalFormat.setGroupingUsed(false); decimalFormat.setGroupingUsed(false);
return decimalFormat; return decimalFormat;
} }
public static String countryLocalesToString(List<Country> countries) { public static String countryLocalesToString(List<Country> countries)
{
String result = ""; String result = "";
int i = 0; int i = 0;
for (Country country : countries) { for (Country country : countries)
{
result += country.getName(); result += country.getName();
i++; i++;
if (i < countries.size()) { if (i < countries.size())
{
result += ", "; result += ", ";
} }
} }
return result; return result;
} }
public static String languageLocalesToString(List<Locale> languageLocales) { public static String languageLocalesToString(List<Locale> languageLocales)
{
String result = ""; String result = "";
int i = 0; int i = 0;
for (Locale locale : languageLocales) { for (Locale locale : languageLocales)
{
result += locale.getDisplayLanguage(); result += locale.getDisplayLanguage();
i++; i++;
if (i < languageLocales.size()) { if (i < languageLocales.size())
{
result += ", "; result += ", ";
} }
} }
@ -179,13 +249,16 @@ public class BitSquareFormatter {
} }
public static String arbitrationMethodsToString(List<Arbitrator.METHOD> items) { public static String arbitrationMethodsToString(List<Arbitrator.METHOD> items)
{
String result = ""; String result = "";
int i = 0; int i = 0;
for (Arbitrator.METHOD item : items) { for (Arbitrator.METHOD item : items)
{
result += Localisation.get(item.toString()); result += Localisation.get(item.toString());
i++; i++;
if (i < items.size()) { if (i < items.size())
{
result += ", "; result += ", ";
} }
} }
@ -193,26 +266,62 @@ public class BitSquareFormatter {
} }
public static String arbitrationIDVerificationsToString(List<Arbitrator.ID_VERIFICATION> items) { public static String arbitrationIDVerificationsToString(List<Arbitrator.ID_VERIFICATION> items)
{
String result = ""; String result = "";
int i = 0; int i = 0;
for (Arbitrator.ID_VERIFICATION item : items) { for (Arbitrator.ID_VERIFICATION item : items)
{
result += Localisation.get(item.toString()); result += Localisation.get(item.toString());
i++; i++;
if (i < items.size()) { if (i < items.size())
{
result += ", "; result += ", ";
} }
} }
return result; return result;
} }
public static String formatDateTime(Date date) { public static String formatDateTime(Date date)
DateFormat dateFormatter = DateFormat.getDateInstance(DateFormat.DEFAULT, Locale.getDefault()); {
DateFormat timeFormatter = DateFormat.getTimeInstance(DateFormat.DEFAULT, Locale.getDefault()); DateFormat dateFormatter = DateFormat.getDateInstance(DateFormat.DEFAULT, locale);
DateFormat timeFormatter = DateFormat.getTimeInstance(DateFormat.DEFAULT, locale);
return dateFormatter.format(date) + " " + timeFormatter.format(date); return dateFormatter.format(date) + " " + timeFormatter.format(date);
} }
public static String formatCollateralPercent(double collateral) { public static String formatCollateralPercent(long collateral)
return getDecimalFormat(2).format(collateral * 100) + " %"; {
return getDecimalFormat(1).format(collateral / 10) + " %";
}
@Deprecated
public static String formatPrice(double volume)
{
return formatDouble(volume);
}
@Deprecated
public static String formatVolume(double volume)
{
return formatDouble(volume);
}
@Deprecated
public static String formatVolumeWithMinVolume(double volume, double minVolume)
{
return formatDouble(volume) + " (" + formatDouble(minVolume) + ")";
}
@Deprecated
public static String formatCoin(Coin coin)
{
return coin != null ? coin.toPlainString() : "";
}
@Deprecated
public static String formatCoinWithCode(Coin coin)
{
return coin != null ? coin.toFriendlyString() : "";
} }
} }

View file

@ -44,6 +44,9 @@ public class Localisation {
public static String get(String key) { public static String get(String key) {
if (key == null)
return "";
try { try {
return Localisation.getResourceBundle().getString(key); return Localisation.getResourceBundle().getString(key);
} catch (MissingResourceException e) { } catch (MissingResourceException e) {

View file

@ -31,11 +31,11 @@ import java.util.Locale;
public class Settings implements Serializable { public class Settings implements Serializable {
private static final long serialVersionUID = 7995048077355006861L; private static final long serialVersionUID = 7995048077355006861L;
private List<Locale> acceptedLanguageLocales = new ArrayList<>(); private List<Locale> acceptedLanguageLocales = new ArrayList<>();
private List<Country> acceptedCountryLocales = new ArrayList<>(); private List<Country> acceptedCountryLocales = new ArrayList<>();
private List<Arbitrator> acceptedArbitrators = new ArrayList<>(); private List<Arbitrator> acceptedArbitrators = new ArrayList<>();
private double collateral = 0.01;
private long collateral = 100; // is 1/1000 so 100 is a multiplier of 0,1 or 10% of the amount
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -91,10 +91,9 @@ public class Settings implements Serializable {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Getters // Setters/Getters
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public List<Arbitrator> getAcceptedArbitrators() { public List<Arbitrator> getAcceptedArbitrators() {
return acceptedArbitrators; return acceptedArbitrators;
} }
@ -123,8 +122,11 @@ public class Settings implements Serializable {
return !candidates.isEmpty() ? candidates.get((int) (Math.random() * candidates.size())) : null; return !candidates.isEmpty() ? candidates.get((int) (Math.random() * candidates.size())) : null;
} }
public void setCollateral(long collateral) {
this.collateral = collateral;
}
public double getCollateral() { public long getCollateral() {
return collateral; return collateral;
} }

View file

@ -53,7 +53,7 @@ public class Offer implements Serializable {
private final BankAccountType bankAccountType; private final BankAccountType bankAccountType;
private final Country bankAccountCountry; private final Country bankAccountCountry;
private final double collateral; private final long collateral;
private final List<Country> acceptedCountries; private final List<Country> acceptedCountries;
private final List<Locale> acceptedLanguageLocales; private final List<Locale> acceptedLanguageLocales;
private final String bankAccountUID; private final String bankAccountUID;
@ -76,7 +76,7 @@ public class Offer implements Serializable {
Country bankAccountCountry, Country bankAccountCountry,
String bankAccountUID, String bankAccountUID,
Arbitrator arbitrator, Arbitrator arbitrator,
double collateral, long collateral,
List<Country> acceptedCountries, List<Country> acceptedCountries,
List<Locale> acceptedLanguageLocales) { List<Locale> acceptedLanguageLocales) {
this.id = id; this.id = id;
@ -178,7 +178,7 @@ public class Offer implements Serializable {
return arbitrator; return arbitrator;
} }
public double getCollateral() { public long getCollateral() {
return collateral; return collateral;
} }

View file

@ -18,6 +18,7 @@
package io.bitsquare.user; package io.bitsquare.user;
import io.bitsquare.bank.BankAccount; import io.bitsquare.bank.BankAccount;
import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.util.DSAKeyUtil; import io.bitsquare.util.DSAKeyUtil;
import java.io.Serializable; import java.io.Serializable;
@ -26,7 +27,9 @@ import java.security.KeyPair;
import java.security.PublicKey; import java.security.PublicKey;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Currency;
import java.util.List; import java.util.List;
import java.util.Locale;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -74,6 +77,7 @@ public class User implements Serializable {
} }
bankAccountsSizeProperty.set(bankAccounts.size()); bankAccountsSizeProperty.set(bankAccounts.size());
BSFormatter.setFiatCurrencyCode(Currency.getInstance(Locale.getDefault()).getCurrencyCode());
} }
public void addBankAccount(BankAccount bankAccount) { public void addBankAccount(BankAccount bankAccount) {
@ -110,6 +114,9 @@ public class User implements Serializable {
public void setCurrentBankAccount(@Nullable BankAccount bankAccount) { public void setCurrentBankAccount(@Nullable BankAccount bankAccount) {
currentBankAccount = bankAccount; currentBankAccount = bankAccount;
BSFormatter.setFiatCurrencyCode(currentBankAccount.getCurrency().getCurrencyCode());
int index = -1; int index = -1;
for (index = 0; index < bankAccounts.size(); index++) { for (index = 0; index < bankAccounts.size(); index++) {
if (currentBankAccount != null && currentBankAccount.equals(bankAccounts.get(index))) if (currentBankAccount != null && currentBankAccount.equals(bankAccounts.get(index)))

View file

@ -18,6 +18,7 @@
package io.bitsquare; package io.bitsquare;
import io.bitsquare.btc.BtcValidatorTest; import io.bitsquare.btc.BtcValidatorTest;
import io.bitsquare.gui.trade.createoffer.CreateOfferPresenterTest;
import io.bitsquare.gui.util.BitSquareConverterTest; import io.bitsquare.gui.util.BitSquareConverterTest;
import io.bitsquare.gui.util.BitSquareNumberValidatorTest; import io.bitsquare.gui.util.BitSquareNumberValidatorTest;
import io.bitsquare.gui.util.FiatValidatorTest; import io.bitsquare.gui.util.FiatValidatorTest;
@ -33,7 +34,8 @@ import org.junit.runners.Suite;
BitSquareNumberValidatorTest.class, BitSquareNumberValidatorTest.class,
P2PNodeTest.class, P2PNodeTest.class,
FiatValidatorTest.class, FiatValidatorTest.class,
BtcValidatorTest.class BtcValidatorTest.class,
CreateOfferPresenterTest.class
}) })
public class BitSquareTestSuite { public class BitSquareTestSuite {

View file

@ -0,0 +1,107 @@
package io.bitsquare.gui.trade.createoffer;
import io.bitsquare.bank.BankAccountType;
import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.locale.Country;
import com.google.bitcoin.core.Coin;
import com.google.bitcoin.utils.Fiat;
import java.util.Locale;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.junit.Assert.*;
public class CreateOfferPresenterTest
{
private static final Logger log = LoggerFactory.getLogger(CreateOfferPresenterTest.class);
@Test
public void testBindings()
{
CreateOfferModel model = new CreateOfferModel(null, null, null, null);
BSFormatter.setLocale(Locale.US);
CreateOfferPresenter presenter = new CreateOfferPresenter(model);
presenter.onViewInitialized();
model.collateralAsLong.set(100);
presenter.price.set("500");
presenter.amount.set("1");
assertEquals("500.00", presenter.volume.get());
assertEquals(Coin.COIN, model.amountAsCoin);
assertEquals(Fiat.valueOf("EUR", 500 * 10000), model.priceAsFiat);
assertEquals(Fiat.valueOf("EUR", 500 * 10000), model.tradeVolumeAsFiat);
assertEquals(Coin.parseCoin("0.1011"), model.totalToPayAsCoin);
presenter.price.set("500");
presenter.volume.set("500");
assertEquals("1.00", presenter.amount.get());
assertEquals(Coin.COIN, model.amountAsCoin);
assertEquals(Fiat.valueOf("EUR", 500 * 10000), model.priceAsFiat);
assertEquals(Fiat.valueOf("EUR", 500 * 10000), model.tradeVolumeAsFiat);
presenter.price.set("300");
presenter.volume.set("1000");
assertEquals("3.3333", presenter.amount.get());
assertEquals(Coin.parseCoin("3.3333"), model.amountAsCoin);
assertEquals(Fiat.valueOf("EUR", 300 * 10000), model.priceAsFiat);
assertEquals(Fiat.valueOf("EUR", 9999900), model.tradeVolumeAsFiat);
presenter.price.set("300");
presenter.amount.set("3.3333");
assertEquals("999.99", presenter.volume.get());
assertEquals(Coin.parseCoin("3.3333"), model.amountAsCoin);
assertEquals(Fiat.valueOf("EUR", 300 * 10000), model.priceAsFiat);
assertEquals(Fiat.valueOf("EUR", 9999900), model.tradeVolumeAsFiat);
presenter.price.set("300");
presenter.amount.set("3.33333333");
assertEquals("999.99", presenter.volume.get());
assertEquals(Coin.parseCoin("3.3333"), model.amountAsCoin);
assertEquals(Fiat.valueOf("EUR", 300 * 10000), model.priceAsFiat);
assertEquals(Fiat.valueOf("EUR", 9999900), model.tradeVolumeAsFiat);
model.collateralAsLong.set(100);
assertEquals("Collateral (10.0 %):", presenter.collateralLabel.get());
model.collateralAsLong.set(0);
assertEquals("Collateral (0.0 %):", presenter.collateralLabel.get());
model.bankAccountType.set(BankAccountType.SEPA.toString());
assertEquals("Sepa", presenter.bankAccountType.get());
model.bankAccountType.set(BankAccountType.WIRE.toString());
assertEquals("Wire", presenter.bankAccountType.get());
model.bankAccountCurrency.set("EUR");
assertEquals("EUR", presenter.bankAccountCurrency.get());
model.bankAccountCurrency.set("USD");
assertEquals("USD", presenter.bankAccountCurrency.get());
model.bankAccountCounty.set("Spain");
assertEquals("Spain", presenter.bankAccountCounty.get());
model.bankAccountCounty.set("Italy");
assertEquals("Italy", presenter.bankAccountCounty.get());
model.acceptedCountries.add(new Country(null, "Italy", null));
assertEquals("Italy", presenter.acceptedCountries.get());
model.acceptedCountries.add(new Country(null, "Spain", null));
assertEquals("Italy, Spain", presenter.acceptedCountries.get());
}
}

View file

@ -26,19 +26,19 @@ public class BitSquareConverterTest {
@Test @Test
public void testStringToDouble() { public void testStringToDouble() {
assertEquals(1, BitSquareFormatter.parseToDouble("1"), 0); assertEquals(1, BSFormatter.parseToDouble("1"), 0);
assertEquals(0.1, BitSquareFormatter.parseToDouble("0.1"), 0); assertEquals(0.1, BSFormatter.parseToDouble("0.1"), 0);
assertEquals(0.1, BitSquareFormatter.parseToDouble("0,1"), 0); assertEquals(0.1, BSFormatter.parseToDouble("0,1"), 0);
assertEquals(1, BitSquareFormatter.parseToDouble("1.0"), 0); assertEquals(1, BSFormatter.parseToDouble("1.0"), 0);
assertEquals(1, BitSquareFormatter.parseToDouble("1,0"), 0); assertEquals(1, BSFormatter.parseToDouble("1,0"), 0);
assertEquals(0, BitSquareFormatter.parseToDouble("1,000.2"), 0); assertEquals(0, BSFormatter.parseToDouble("1,000.2"), 0);
assertEquals(0, BitSquareFormatter.parseToDouble("1,000.2"), 0); assertEquals(0, BSFormatter.parseToDouble("1,000.2"), 0);
assertEquals(0, BitSquareFormatter.parseToDouble(null), 0); assertEquals(0, BSFormatter.parseToDouble(null), 0);
assertEquals(0, BitSquareFormatter.parseToDouble(""), 0); assertEquals(0, BSFormatter.parseToDouble(""), 0);
assertEquals(0, BitSquareFormatter.parseToDouble(""), 0); assertEquals(0, BSFormatter.parseToDouble(""), 0);
assertEquals(0, BitSquareFormatter.parseToDouble("."), 0); assertEquals(0, BSFormatter.parseToDouble("."), 0);
assertEquals(0, BitSquareFormatter.parseToDouble(","), 0); assertEquals(0, BSFormatter.parseToDouble(","), 0);
assertEquals(0, BitSquareFormatter.parseToDouble("a"), 0); assertEquals(0, BSFormatter.parseToDouble("a"), 0);
} }
} }