mirror of
https://github.com/bisq-network/bisq.git
synced 2025-03-13 11:09:10 +01:00
update MVP for create offer, improve addressTF, balanceTF, create inputvalidator
This commit is contained in:
parent
e8761467ca
commit
8e22e42556
15 changed files with 377 additions and 379 deletions
|
@ -342,10 +342,12 @@ public class WalletFacade {
|
|||
|
||||
public TransactionConfidence getConfidenceForAddress(Address address) {
|
||||
List<TransactionConfidence> transactionConfidenceList = new ArrayList<>();
|
||||
Set<Transaction> transactions = wallet.getTransactions(true);
|
||||
if (transactions != null) {
|
||||
transactionConfidenceList.addAll(transactions.stream().map(tx ->
|
||||
getTransactionConfidence(tx, address)).collect(Collectors.toList()));
|
||||
if (wallet != null) {
|
||||
Set<Transaction> transactions = wallet.getTransactions(true);
|
||||
if (transactions != null) {
|
||||
transactionConfidenceList.addAll(transactions.stream().map(tx ->
|
||||
getTransactionConfidence(tx, address)).collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
return getMostRecentConfidence(transactionConfidenceList);
|
||||
}
|
||||
|
@ -430,7 +432,7 @@ public class WalletFacade {
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public Coin getBalanceForAddress(Address address) {
|
||||
return getBalance(wallet.calculateAllSpendCandidates(true), address);
|
||||
return wallet != null ? getBalance(wallet.calculateAllSpendCandidates(true), address) : Coin.ZERO;
|
||||
}
|
||||
|
||||
private Coin getBalance(LinkedList<TransactionOutput> transactionOutputs, Address address) {
|
||||
|
|
|
@ -27,8 +27,8 @@ import io.bitsquare.msg.BootstrappedPeerFactory;
|
|||
import io.bitsquare.msg.MessageFacade;
|
||||
import io.bitsquare.msg.P2PNode;
|
||||
import io.bitsquare.msg.SeedNodeAddress;
|
||||
import io.bitsquare.settings.Settings;
|
||||
import io.bitsquare.persistence.Persistence;
|
||||
import io.bitsquare.settings.Settings;
|
||||
import io.bitsquare.trade.TradeManager;
|
||||
import io.bitsquare.trade.orderbook.OrderBook;
|
||||
import io.bitsquare.user.User;
|
||||
|
@ -66,7 +66,7 @@ public class BitSquareModule extends AbstractModule {
|
|||
bind(TradeManager.class).asEagerSingleton();
|
||||
bind(BSFormatter.class).asEagerSingleton();
|
||||
|
||||
|
||||
|
||||
//bind(String.class).annotatedWith(Names.named("networkType")).toInstance(WalletFacade.MAIN_NET);
|
||||
// how to use reg test see description in the readme file
|
||||
bind(String.class).annotatedWith(Names.named("networkType")).toInstance(WalletFacade.REG_TEST_NET);
|
||||
|
|
|
@ -79,28 +79,13 @@
|
|||
-fx-background-color: transparent;
|
||||
}
|
||||
|
||||
#qr-code-icon {
|
||||
-fx-fill: #0096c9;
|
||||
-fx-cursor: hand;
|
||||
}
|
||||
|
||||
#copy-icon {
|
||||
-fx-fill: #0096c9;
|
||||
-fx-cursor: hand;
|
||||
}
|
||||
|
||||
#copy-icon .hover {
|
||||
-fx-fill: #0096c9;
|
||||
-fx-cursor: hand;
|
||||
}
|
||||
|
||||
.copy-icon {
|
||||
-fx-fill: #0096c9;
|
||||
-fx-text-fill: #0096c9;
|
||||
-fx-cursor: hand;
|
||||
}
|
||||
|
||||
.copy-icon:hover {
|
||||
-fx-fill: black;
|
||||
-fx-text-fill: black;
|
||||
}
|
||||
|
||||
/* Same stlye like non editable textfield. But textfield spans a whole column in a grid, so we use generally textfield */
|
||||
|
@ -118,6 +103,9 @@
|
|||
-fx-border-radius: 4;
|
||||
-fx-padding: 4 4 4 4;
|
||||
}
|
||||
#address-label:hover {
|
||||
-fx-text-fill: black;
|
||||
}
|
||||
|
||||
#funds-confidence {
|
||||
-fx-progress-color: dimgrey;
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
package io.bitsquare.gui.components;
|
||||
|
||||
import io.bitsquare.gui.util.validation.NumberValidator;
|
||||
import io.bitsquare.gui.util.validation.InputValidator;
|
||||
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
|
@ -38,7 +38,7 @@ import org.slf4j.LoggerFactory;
|
|||
* TextField with validation support. Validation is executed on the Validator object.
|
||||
* In case of a invalid result we display a error message with a PopOver.
|
||||
* The position is derived from the textField or if set from the errorPopupLayoutReference object.
|
||||
* <p/>
|
||||
* <p>
|
||||
* That class implements just what we need for the moment. It is not intended as a general purpose library class.
|
||||
*/
|
||||
public class ValidatingTextField extends TextField {
|
||||
|
@ -48,7 +48,7 @@ public class ValidatingTextField extends TextField {
|
|||
private Effect invalidEffect = new DropShadow(BlurType.GAUSSIAN, Color.RED, 4, 0.0, 0, 0);
|
||||
|
||||
private final BooleanProperty isValid = new SimpleBooleanProperty(true);
|
||||
private NumberValidator numberValidator;
|
||||
private InputValidator validator;
|
||||
private boolean validateOnFocusOut = true;
|
||||
private boolean needsValidationOnFocusOut;
|
||||
private Region errorPopupLayoutReference;
|
||||
|
@ -88,8 +88,8 @@ public class ValidatingTextField extends TextField {
|
|||
// Setters
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void setNumberValidator(NumberValidator numberValidator) {
|
||||
this.numberValidator = numberValidator;
|
||||
public void setValidator(InputValidator validator) {
|
||||
this.validator = validator;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -126,7 +126,7 @@ public class ValidatingTextField extends TextField {
|
|||
});
|
||||
|
||||
textProperty().addListener((ov, oldValue, newValue) -> {
|
||||
if (numberValidator != null) {
|
||||
if (validator != null) {
|
||||
if (!validateOnFocusOut)
|
||||
validate(newValue);
|
||||
else
|
||||
|
@ -144,14 +144,14 @@ public class ValidatingTextField extends TextField {
|
|||
}
|
||||
|
||||
private void validate(String input) {
|
||||
if (input != null) {
|
||||
NumberValidator.ValidationResult validationResult = numberValidator.validate(input);
|
||||
if (input != null && validator != null) {
|
||||
InputValidator.ValidationResult validationResult = validator.validate(input);
|
||||
isValid.set(validationResult.isValid);
|
||||
applyErrorMessage(validationResult);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyErrorMessage(NumberValidator.ValidationResult validationResult) {
|
||||
private void applyErrorMessage(InputValidator.ValidationResult validationResult) {
|
||||
if (validationResult.isValid) {
|
||||
if (popOver != null) {
|
||||
popOver.hide();
|
||||
|
|
|
@ -29,6 +29,10 @@ import java.io.IOException;
|
|||
|
||||
import java.net.URI;
|
||||
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.image.Image;
|
||||
|
@ -51,44 +55,52 @@ import org.slf4j.LoggerFactory;
|
|||
public class AddressTextField extends AnchorPane {
|
||||
private static final Logger log = LoggerFactory.getLogger(AddressTextField.class);
|
||||
|
||||
private final Label copyIcon;
|
||||
private final Label addressLabel;
|
||||
private final Label qrCode;
|
||||
private String address;
|
||||
private Coin amountToPay;
|
||||
private String paymentLabel;
|
||||
private final StringProperty address = new SimpleStringProperty();
|
||||
private final StringProperty paymentLabel = new SimpleStringProperty();
|
||||
public final ObjectProperty<Coin> amountAsCoin = new SimpleObjectProperty<>();
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public AddressTextField() {
|
||||
addressLabel = new Label();
|
||||
Label addressLabel = new Label();
|
||||
addressLabel.setFocusTraversable(false);
|
||||
addressLabel.setId("address-label");
|
||||
addressLabel.textProperty().bind(address);
|
||||
addressLabel.setOnMouseClicked(mouseEvent -> {
|
||||
try {
|
||||
if (address != null)
|
||||
Desktop.getDesktop().browse(URI.create(getBitcoinURI()));
|
||||
} catch (IOException e) {
|
||||
log.warn(e.getMessage());
|
||||
Popups.openWarningPopup("Information", "Opening a system Bitcoin wallet application has failed. " +
|
||||
"Perhaps you don't have one installed?");
|
||||
}
|
||||
});
|
||||
|
||||
copyIcon = new Label();
|
||||
Label copyIcon = new Label();
|
||||
copyIcon.setLayoutY(3);
|
||||
copyIcon.setId("copy-icon");
|
||||
copyIcon.getStyleClass().add("copy-icon");
|
||||
Tooltip.install(copyIcon, new Tooltip("Copy address to clipboard"));
|
||||
AwesomeDude.setIcon(copyIcon, AwesomeIcon.COPY);
|
||||
copyIcon.setOnMouseClicked(e -> {
|
||||
if (address != null && address.length() > 0) {
|
||||
if (address.get() != null && address.get().length() > 0) {
|
||||
Clipboard clipboard = Clipboard.getSystemClipboard();
|
||||
ClipboardContent content = new ClipboardContent();
|
||||
content.putString(address);
|
||||
content.putString(address.get());
|
||||
clipboard.setContent(content);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
qrCode = new Label();
|
||||
qrCode.setId("qr-code-icon");
|
||||
Label qrCode = new Label();
|
||||
qrCode.getStyleClass().add("copy-icon");
|
||||
qrCode.setLayoutY(3);
|
||||
AwesomeDude.setIcon(qrCode, AwesomeIcon.QRCODE);
|
||||
Tooltip.install(qrCode, new Tooltip("Show QR code for this address"));
|
||||
qrCode.setOnMouseClicked(e -> {
|
||||
if (address != null && address.length() > 0) {
|
||||
if (address.get() != null && address.get().length() > 0) {
|
||||
final byte[] imageBytes = QRCode
|
||||
.from(getBitcoinURI())
|
||||
.withSize(300, 220)
|
||||
|
@ -119,16 +131,6 @@ public class AddressTextField extends AnchorPane {
|
|||
AnchorPane.setLeftAnchor(addressLabel, 0.0);
|
||||
|
||||
getChildren().addAll(addressLabel, copyIcon, qrCode);
|
||||
|
||||
addressLabel.setOnMouseClicked(mouseEvent -> {
|
||||
try {
|
||||
if (address != null)
|
||||
Desktop.getDesktop().browse(URI.create(getBitcoinURI()));
|
||||
} catch (IOException e) {
|
||||
log.warn(e.getMessage());
|
||||
Popups.openWarningPopup("Opening wallet app failed", "Perhaps you don't have one installed?");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
@ -137,16 +139,39 @@ public class AddressTextField extends AnchorPane {
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
addressLabel.setText(address);
|
||||
this.address.set(address);
|
||||
}
|
||||
|
||||
public void setAmountToPay(Coin amountToPay) {
|
||||
this.amountToPay = amountToPay;
|
||||
public String getAddress() {
|
||||
return address.get();
|
||||
}
|
||||
|
||||
public StringProperty addressProperty() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public Coin getAmountAsCoin() {
|
||||
return amountAsCoin.get();
|
||||
}
|
||||
|
||||
public ObjectProperty<Coin> amountAsCoinProperty() {
|
||||
return amountAsCoin;
|
||||
}
|
||||
|
||||
public void setAmountAsCoin(Coin amountAsCoin) {
|
||||
this.amountAsCoin.set(amountAsCoin);
|
||||
}
|
||||
|
||||
public String getPaymentLabel() {
|
||||
return paymentLabel.get();
|
||||
}
|
||||
|
||||
public StringProperty paymentLabelProperty() {
|
||||
return paymentLabel;
|
||||
}
|
||||
|
||||
public void setPaymentLabel(String paymentLabel) {
|
||||
this.paymentLabel = paymentLabel;
|
||||
this.paymentLabel.set(paymentLabel);
|
||||
}
|
||||
|
||||
|
||||
|
@ -155,7 +180,7 @@ public class AddressTextField extends AnchorPane {
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private String getBitcoinURI() {
|
||||
return BitcoinURI.convertToBitcoinURI(address, amountToPay, paymentLabel, null);
|
||||
return address.get() != null ? BitcoinURI.convertToBitcoinURI(address.get(), amountAsCoin.get(),
|
||||
paymentLabel.get(), null) : "";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import io.bitsquare.btc.WalletFacade;
|
|||
import io.bitsquare.btc.listeners.BalanceListener;
|
||||
import io.bitsquare.btc.listeners.ConfidenceListener;
|
||||
import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator;
|
||||
import io.bitsquare.gui.util.BSFormatter;
|
||||
|
||||
import com.google.bitcoin.core.Address;
|
||||
import com.google.bitcoin.core.Coin;
|
||||
|
@ -36,13 +37,8 @@ public class BalanceTextField extends AnchorPane {
|
|||
private static final Logger log = LoggerFactory.getLogger(BalanceTextField.class);
|
||||
|
||||
private final TextField balanceTextField;
|
||||
private Address address;
|
||||
private final Tooltip progressIndicatorTooltip;
|
||||
private final ConfidenceProgressIndicator progressIndicator;
|
||||
private WalletFacade walletFacade;
|
||||
private ConfidenceListener confidenceListener;
|
||||
private BalanceListener balanceListener;
|
||||
private Coin balance;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -72,18 +68,8 @@ public class BalanceTextField extends AnchorPane {
|
|||
getChildren().addAll(balanceTextField, progressIndicator);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Setters
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void setAddress(Address address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public void setWalletFacade(WalletFacade walletFacade) {
|
||||
this.walletFacade = walletFacade;
|
||||
confidenceListener = walletFacade.addConfidenceListener(new ConfidenceListener(address) {
|
||||
public void setup(WalletFacade walletFacade, Address address) {
|
||||
walletFacade.addConfidenceListener(new ConfidenceListener(address) {
|
||||
@Override
|
||||
public void onTransactionConfidenceChanged(TransactionConfidence confidence) {
|
||||
updateConfidence(confidence);
|
||||
|
@ -91,8 +77,7 @@ public class BalanceTextField extends AnchorPane {
|
|||
});
|
||||
updateConfidence(walletFacade.getConfidenceForAddress(address));
|
||||
|
||||
|
||||
balanceListener = walletFacade.addBalanceListener(new BalanceListener(address) {
|
||||
walletFacade.addBalanceListener(new BalanceListener(address) {
|
||||
@Override
|
||||
public void onBalanceChanged(Coin balance) {
|
||||
updateBalance(balance);
|
||||
|
@ -101,21 +86,6 @@ public class BalanceTextField extends AnchorPane {
|
|||
updateBalance(walletFacade.getBalanceForAddress(address));
|
||||
}
|
||||
|
||||
// TODO not called yet...
|
||||
public void cleanup() {
|
||||
walletFacade.removeConfidenceListener(confidenceListener);
|
||||
walletFacade.removeBalanceListener(balanceListener);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Getters
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public Coin getBalance() {
|
||||
return balance;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Private methods
|
||||
|
@ -152,11 +122,7 @@ public class BalanceTextField extends AnchorPane {
|
|||
}
|
||||
|
||||
private void updateBalance(Coin balance) {
|
||||
this.balance = balance;
|
||||
if (balance != null) {
|
||||
//TODO use BSFormatter
|
||||
balanceTextField.setText(balance.toFriendlyString());
|
||||
}
|
||||
balanceTextField.setText(BSFormatter.formatBtc(balance));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,44 +34,45 @@ import javax.inject.Inject;
|
|||
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.layout.*;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Code behind (FXML Controller is part of View, not a classical controller from MVC):
|
||||
* <p/>
|
||||
* Code behind (FXML Controller is part of View, not a classical MVC controller):
|
||||
* <p>
|
||||
* Creates Presenter and passes Model from DI to Presenter. Does not hold a reference to Model
|
||||
* <p/>
|
||||
* <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/>
|
||||
* - Has no logic and no state, only view elements and a presenter reference!
|
||||
* <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/>
|
||||
* <p>
|
||||
* Optional ViewBuilder:
|
||||
* - Replacement for FXML view definitions.
|
||||
*
|
||||
* Note: Don't assign the root node as it is defined in the base class!
|
||||
*
|
||||
*/
|
||||
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;
|
||||
totalFeesTextField, transactionIdTextField;
|
||||
@FXML private ConfidenceProgressIndicator progressIndicator;
|
||||
@FXML private AddressTextField addressTextField;
|
||||
@FXML private BalanceTextField balanceTextField;
|
||||
|
@ -94,31 +95,30 @@ public class CreateOfferCodeBehind extends CachedViewController {
|
|||
@Override
|
||||
public void initialize(URL url, ResourceBundle rb) {
|
||||
super.initialize(url, rb);
|
||||
|
||||
presenter.onViewInitialized();
|
||||
|
||||
balanceTextField.setup(presenter.getWalletFacade(), presenter.address.get());
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -130,6 +130,7 @@ public class CreateOfferCodeBehind extends CachedViewController {
|
|||
presenter.setOrderBookFilter(orderBookFilter);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// UI Handlers
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -143,7 +144,7 @@ public class CreateOfferCodeBehind extends CachedViewController {
|
|||
public void onClose() {
|
||||
presenter.close();
|
||||
|
||||
TabPane tabPane = ((TabPane) (rootContainer.getParent().getParent()));
|
||||
TabPane tabPane = ((TabPane) (root.getParent().getParent()));
|
||||
tabPane.getTabs().remove(tabPane.getSelectionModel().getSelectedItem());
|
||||
}
|
||||
|
||||
|
@ -154,7 +155,7 @@ public class CreateOfferCodeBehind extends CachedViewController {
|
|||
|
||||
private void setupListeners() {
|
||||
volumeTextField.focusedProperty().addListener((observableValue, oldValue,
|
||||
newValue) -> presenter.checkVolumeOnFocusOut(oldValue,
|
||||
newValue) -> presenter.validateVolumeOnFocusOut(oldValue,
|
||||
newValue, volumeTextField.getText()));
|
||||
amountTextField.focusedProperty().addListener((observableValue, oldValue,
|
||||
newValue) -> presenter.onFocusOutAmountTextField(oldValue,
|
||||
|
@ -163,7 +164,7 @@ public class CreateOfferCodeBehind extends CachedViewController {
|
|||
newValue) -> presenter.onFocusOutPriceTextField(oldValue,
|
||||
newValue));
|
||||
|
||||
presenter.validateInput.addListener((o, oldValue, newValue) -> {
|
||||
presenter.needsInputValidation.addListener((o, oldValue, newValue) -> {
|
||||
if (newValue) {
|
||||
amountTextField.reValidate();
|
||||
minAmountTextField.reValidate();
|
||||
|
@ -179,6 +180,12 @@ public class CreateOfferCodeBehind extends CachedViewController {
|
|||
volumeTextField.setText(presenter.volume.get());
|
||||
}
|
||||
});
|
||||
presenter.requestPlaceOfferFailed.addListener((o, oldValue, newValue) -> {
|
||||
if (newValue) {
|
||||
Popups.openErrorPopup("Error", "An error occurred when placing the offer.\n" +
|
||||
presenter.requestPlaceOfferErrorMessage);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setupBindings() {
|
||||
|
@ -192,17 +199,22 @@ public class CreateOfferCodeBehind extends CachedViewController {
|
|||
collateralTextField.textProperty().bind(presenter.collateral);
|
||||
totalToPayTextField.textProperty().bind(presenter.totalToPay);
|
||||
|
||||
addressTextField.amountAsCoinProperty().bind(presenter.totalToPayAsCoin);
|
||||
addressTextField.paymentLabelProperty().bind(presenter.paymentLabel);
|
||||
addressTextField.addressProperty().bind(presenter.addressAsString);
|
||||
|
||||
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);
|
||||
totalFeesTextField.textProperty().bind(presenter.totalFees);
|
||||
transactionIdTextField.textProperty().bind(presenter.transactionId);
|
||||
|
||||
placeOfferButton.visibleProperty().bind(presenter.placeOfferButtonVisible);
|
||||
closeButton.visibleProperty().bind(presenter.isOfferPlacedScreen);
|
||||
placeOfferButton.visibleProperty().bind(presenter.isPlaceOfferButtonVisible);
|
||||
placeOfferButton.disableProperty().bind(presenter.isPlaceOfferButtonDisabled);
|
||||
closeButton.visibleProperty().bind(presenter.isCloseButtonVisible);
|
||||
|
||||
//TODO
|
||||
/* progressIndicator.visibleProperty().bind(viewModel.isOfferPlacedScreen);
|
||||
|
@ -240,57 +252,5 @@ public class CreateOfferCodeBehind extends CachedViewController {
|
|||
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));
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
|
|
|
@ -54,10 +54,10 @@ import static com.google.common.base.Preconditions.checkArgument;
|
|||
/**
|
||||
* Data model:
|
||||
* Does not know the Presenter and View (CodeBehind)
|
||||
* Use Guice for DI
|
||||
* <p/>
|
||||
* Use Guice for DI to get domain objects
|
||||
* <p>
|
||||
* - Holds domain data
|
||||
* - Use Properties for bindable data
|
||||
* - Apply business logic (no view related, that is done in presenter)
|
||||
*/
|
||||
class CreateOfferModel {
|
||||
private static final Logger log = LoggerFactory.getLogger(CreateOfferModel.class);
|
||||
|
@ -67,38 +67,34 @@ class CreateOfferModel {
|
|||
private final Settings settings;
|
||||
private final User user;
|
||||
|
||||
String getOfferId() {
|
||||
return offerId;
|
||||
}
|
||||
|
||||
private final String offerId;
|
||||
|
||||
final Coin totalFeesAsCoin;
|
||||
|
||||
|
||||
private Direction direction = null;
|
||||
|
||||
final Coin totalFeesAsCoin;
|
||||
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();
|
||||
|
||||
final LongProperty collateralAsLong = new SimpleLongProperty();
|
||||
|
||||
final BooleanProperty requestPlaceOfferSuccess = new SimpleBooleanProperty();
|
||||
final BooleanProperty requestPlaceOfferFailed = new SimpleBooleanProperty();
|
||||
|
||||
final ObjectProperty<Coin> totalToPayAsCoin = new SimpleObjectProperty<>();
|
||||
|
||||
ObservableList<Country> acceptedCountries = FXCollections.observableArrayList();
|
||||
ObservableList<Locale> acceptedLanguages = FXCollections.observableArrayList();
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -110,8 +106,12 @@ class CreateOfferModel {
|
|||
this.settings = settings;
|
||||
this.user = user;
|
||||
|
||||
// static data
|
||||
offerId = UUID.randomUUID().toString();
|
||||
totalFeesAsCoin = FeePolicy.CREATE_OFFER_FEE.add(FeePolicy.TX_FEE);
|
||||
|
||||
|
||||
//TODO just for unit testing, use mockito?
|
||||
if (walletFacade != null && walletFacade.getWallet() != null)
|
||||
addressEntry = walletFacade.getAddressInfoByTradeID(offerId);
|
||||
}
|
||||
|
@ -122,6 +122,7 @@ class CreateOfferModel {
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void activate() {
|
||||
// dynamic data, might be changing when switching screen and returning (edit settings)
|
||||
collateralAsLong.set(settings.getCollateral());
|
||||
|
||||
BankAccount bankAccount = user.getCurrentBankAccount();
|
||||
|
@ -134,10 +135,13 @@ class CreateOfferModel {
|
|||
acceptedLanguages.setAll(settings.getAcceptedLanguageLocales());
|
||||
}
|
||||
|
||||
void deactivate() {
|
||||
}
|
||||
|
||||
void placeOffer() {
|
||||
tradeManager.requestPlaceOffer(offerId,
|
||||
direction,
|
||||
priceAsFiat.value,
|
||||
priceAsFiat,
|
||||
amountAsCoin,
|
||||
minAmountAsCoin,
|
||||
(transaction) -> {
|
||||
|
@ -161,10 +165,17 @@ class CreateOfferModel {
|
|||
}
|
||||
|
||||
void setDirection(Direction direction) {
|
||||
// direction must not be changed once it is initially set
|
||||
// direction can not be changed once it is initially set
|
||||
checkArgument(this.direction == null);
|
||||
this.direction = direction;
|
||||
}
|
||||
|
||||
public WalletFacade getWalletFacade() {
|
||||
return walletFacade;
|
||||
}
|
||||
|
||||
String getOfferId() {
|
||||
return offerId;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,11 +17,13 @@
|
|||
|
||||
package io.bitsquare.gui.trade.createoffer;
|
||||
|
||||
import io.bitsquare.btc.WalletFacade;
|
||||
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.Address;
|
||||
import com.google.bitcoin.core.Coin;
|
||||
import com.google.bitcoin.utils.ExchangeRate;
|
||||
|
||||
|
@ -43,12 +45,13 @@ 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 CodeBehind. 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.
|
||||
* <p>
|
||||
* - Holds data and state of the View (formatting,...)
|
||||
* - Receive user input via method calls from CodeBehind.
|
||||
* - Validates input, applies business logic and converts input to Model.
|
||||
* - Format model data to properties used for binding from the view.
|
||||
* - Listen to updates from Model via Bindings.
|
||||
* - Is testable
|
||||
*/
|
||||
class CreateOfferPresenter {
|
||||
private static final Logger log = LoggerFactory.getLogger(CreateOfferPresenter.class);
|
||||
|
@ -63,21 +66,27 @@ class CreateOfferPresenter {
|
|||
final StringProperty totalToPay = new SimpleStringProperty();
|
||||
final StringProperty directionLabel = new SimpleStringProperty();
|
||||
final StringProperty collateralLabel = new SimpleStringProperty();
|
||||
final StringProperty totalFeesLabel = new SimpleStringProperty();
|
||||
final StringProperty totalFees = 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 addressAsString = new SimpleStringProperty();
|
||||
final StringProperty paymentLabel = new SimpleStringProperty();
|
||||
final StringProperty transactionId = new SimpleStringProperty();
|
||||
final BooleanProperty isOfferPlacedScreen = new SimpleBooleanProperty();
|
||||
final BooleanProperty placeOfferButtonVisible = new SimpleBooleanProperty(true);
|
||||
final StringProperty requestPlaceOfferErrorMessage = new SimpleStringProperty();
|
||||
|
||||
final BooleanProperty isCloseButtonVisible = new SimpleBooleanProperty();
|
||||
final BooleanProperty isPlaceOfferButtonVisible = new SimpleBooleanProperty(true);
|
||||
final BooleanProperty isPlaceOfferButtonDisabled = new SimpleBooleanProperty();
|
||||
final BooleanProperty validateInput = new SimpleBooleanProperty();
|
||||
final BooleanProperty needsInputValidation = new SimpleBooleanProperty();
|
||||
final BooleanProperty showVolumeAdjustedWarning = new SimpleBooleanProperty();
|
||||
final BooleanProperty showTransactionPublishedScreen = new SimpleBooleanProperty();
|
||||
final BooleanProperty requestPlaceOfferFailed = new SimpleBooleanProperty();
|
||||
|
||||
final ObjectProperty<Coin> totalToPayAsCoin = new SimpleObjectProperty<>();
|
||||
final ObjectProperty<Address> address = new SimpleObjectProperty<>();
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -94,9 +103,13 @@ class CreateOfferPresenter {
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void onViewInitialized() {
|
||||
totalFeesLabel.set(BSFormatter.formatBtc(model.totalFeesAsCoin));
|
||||
totalFees.set(BSFormatter.formatBtc(model.totalFeesAsCoin));
|
||||
paymentLabel.set("Bitsquare trade (" + model.getOfferId() + ")");
|
||||
// address.set(model.addressEntry.getAddress().toString());
|
||||
|
||||
if (model.addressEntry != null) {
|
||||
addressAsString.set(model.addressEntry.getAddress().toString());
|
||||
address.set(model.addressEntry.getAddress());
|
||||
}
|
||||
|
||||
setupInputListeners();
|
||||
|
||||
|
@ -113,32 +126,43 @@ class CreateOfferPresenter {
|
|||
model.acceptedLanguages.addListener((Observable o) -> acceptedLanguages.set(BSFormatter
|
||||
.languageLocalesToString(model.acceptedLanguages)));
|
||||
|
||||
}
|
||||
isCloseButtonVisible.bind(model.requestPlaceOfferSuccess);
|
||||
requestPlaceOfferErrorMessage.bind(model.requestPlaceOfferErrorMessage);
|
||||
requestPlaceOfferFailed.bind(model.requestPlaceOfferFailed);
|
||||
showTransactionPublishedScreen.bind(model.requestPlaceOfferSuccess);
|
||||
|
||||
void deactivate() {
|
||||
model.requestPlaceOfferFailed.addListener((o, oldValue, newValue) -> {
|
||||
if (newValue) isPlaceOfferButtonDisabled.set(false);
|
||||
});
|
||||
|
||||
model.requestPlaceOfferSuccess.addListener((o, oldValue, newValue) -> {
|
||||
if (newValue) isPlaceOfferButtonVisible.set(false);
|
||||
});
|
||||
|
||||
// TODO transactionId,
|
||||
}
|
||||
|
||||
void activate() {
|
||||
model.activate();
|
||||
|
||||
|
||||
// totalToPay.addListener((ov) -> addressTextField.setAmountToPay(model.totalToPayAsCoin));
|
||||
}
|
||||
|
||||
void deactivate() {
|
||||
model.deactivate();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Public methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void setOrderBookFilter(OrderBookFilter orderBookFilter) {
|
||||
// model
|
||||
model.setDirection(orderBookFilter.getDirection());
|
||||
model.amountAsCoin = orderBookFilter.getAmount();
|
||||
model.minAmountAsCoin = orderBookFilter.getAmount();
|
||||
//TODO
|
||||
|
||||
// TODO use Fiat in orderBookFilter
|
||||
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));
|
||||
|
@ -156,115 +180,52 @@ class CreateOfferPresenter {
|
|||
model.priceAsFiat = parseToFiat(price.get());
|
||||
model.minAmountAsCoin = parseToCoin(minAmount.get());
|
||||
|
||||
validateInput.set(true);
|
||||
|
||||
//balanceTextField.getBalance()
|
||||
needsInputValidation.set(true);
|
||||
|
||||
if (inputValid()) {
|
||||
model.placeOffer();
|
||||
isPlaceOfferButtonDisabled.set(true);
|
||||
placeOfferButtonVisible.set(true);
|
||||
|
||||
isPlaceOfferButtonVisible.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();
|
||||
calculateVolume();
|
||||
calculateTotalToPay();
|
||||
calculateCollateral();
|
||||
});
|
||||
|
||||
price.addListener(ov -> {
|
||||
model.priceAsFiat = parseToFiat(price.get());
|
||||
setVolume();
|
||||
setTotalToPay();
|
||||
setCollateral();
|
||||
calculateVolume();
|
||||
calculateTotalToPay();
|
||||
calculateCollateral();
|
||||
});
|
||||
|
||||
volume.addListener(ov -> {
|
||||
model.tradeVolumeAsFiat = parseToFiat(volume.get());
|
||||
setAmount();
|
||||
setTotalToPay();
|
||||
setCollateral();
|
||||
calculateAmount();
|
||||
calculateTotalToPay();
|
||||
calculateCollateral();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
void validateVolumeOnFocusOut(Boolean oldValue, Boolean newValue, String volumeTextFieldText) {
|
||||
if (oldValue && !newValue) {
|
||||
setVolume();
|
||||
calculateVolume();
|
||||
if (!formatFiat(parseToFiat(volumeTextFieldText)).equals(volume.get()))
|
||||
showVolumeAdjustedWarning.set(true);
|
||||
}
|
||||
|
@ -293,15 +254,59 @@ class CreateOfferPresenter {
|
|||
// Getters
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Setters
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
WalletFacade getWalletFacade() {
|
||||
return model.getWalletFacade();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Private methods
|
||||
// Private
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private boolean inputValid() {
|
||||
//TODO
|
||||
return true;
|
||||
}
|
||||
|
||||
private void calculateVolume() {
|
||||
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 calculateAmount() {
|
||||
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));
|
||||
calculateTotalToPay();
|
||||
calculateCollateral();
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateTotalToPay() {
|
||||
calculateCollateral();
|
||||
|
||||
if (model.collateralAsCoin != null) {
|
||||
model.totalToPayAsCoin.set(model.collateralAsCoin.add(model.totalFeesAsCoin));
|
||||
totalToPay.bind(createStringBinding(() -> formatBtcWithCode(model.totalToPayAsCoin.get()),
|
||||
model.totalToPayAsCoin));
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateCollateral() {
|
||||
if (model.amountAsCoin != null) {
|
||||
model.collateralAsCoin = model.amountAsCoin.multiply(model.collateralAsLong.get()).divide(1000);
|
||||
collateral.set(BSFormatter.formatBtcWithCode(model.collateralAsCoin));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@
|
|||
focusTraversable="false"/>
|
||||
|
||||
<Label GridPane.rowIndex="11" text="Offer Fee + transaction fee:"/>
|
||||
<TextField GridPane.rowIndex="11" fx:id="feeLabel" editable="false" focusTraversable="false"
|
||||
<TextField GridPane.rowIndex="11" fx:id="totalFeesTextField" editable="false" focusTraversable="false"
|
||||
GridPane.columnIndex="1"/>
|
||||
|
||||
|
||||
|
@ -163,7 +163,7 @@
|
|||
<Label fx:id="confirmationLabel" text="Checking confirmations..." visible="false" GridPane.columnIndex="3"
|
||||
GridPane.rowIndex="14"/>
|
||||
|
||||
|
||||
|
||||
<columnConstraints>
|
||||
<ColumnConstraints halignment="RIGHT" hgrow="SOMETIMES"/>
|
||||
<ColumnConstraints hgrow="ALWAYS" minWidth="400"/>
|
||||
|
|
|
@ -26,7 +26,7 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
/**
|
||||
* BtcValidator for validating BTC values.
|
||||
* <p/>
|
||||
* <p>
|
||||
* That class implements just what we need for the moment. It is not intended as a general purpose library class.
|
||||
*/
|
||||
public class BtcValidator extends NumberValidator {
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* 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.util.validation;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* BaseValidator for validating basic number values.
|
||||
* Localisation not supported at the moment
|
||||
* The decimal mark can be either "." or ",". Thousand separators are not supported yet,
|
||||
* but might be added alter with Local support.
|
||||
* <p/>
|
||||
* That class implements just what we need for the moment. It is not intended as a general purpose library class.
|
||||
*/
|
||||
public abstract class InputValidator {
|
||||
private static final Logger log = LoggerFactory.getLogger(InputValidator.class);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Abstract methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
abstract public ValidationResult validate(String input);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Protected methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected ValidationResult validateIfNotEmpty(String input) {
|
||||
if (input == null || input.length() == 0)
|
||||
return new ValidationResult(false, "Empty input is not allowed.", ErrorType.EMPTY_INPUT);
|
||||
else
|
||||
return new ValidationResult(true);
|
||||
}
|
||||
|
||||
protected String cleanInput(String input) {
|
||||
return input.replace(",", ".").trim();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ErrorType
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public enum ErrorType {
|
||||
EMPTY_INPUT,
|
||||
NOT_A_NUMBER,
|
||||
ZERO_NUMBER,
|
||||
NEGATIVE_NUMBER,
|
||||
FRACTIONAL_SATOSHI,
|
||||
EXCEEDS_MAX_FIAT_VALUE, UNDERCUT_MIN_FIAT_VALUE, AMOUNT_LESS_THAN_MIN_AMOUNT,
|
||||
MIN_AMOUNT_LARGER_THAN_MIN_AMOUNT, EXCEEDS_MAX_BTC_VALUE
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ValidationResult
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static class ValidationResult {
|
||||
public final boolean isValid;
|
||||
public final String errorMessage;
|
||||
public final ErrorType errorType;
|
||||
|
||||
public ValidationResult(boolean isValid, String errorMessage, ErrorType errorType) {
|
||||
this.isValid = isValid;
|
||||
this.errorMessage = errorMessage;
|
||||
this.errorType = errorType;
|
||||
}
|
||||
|
||||
ValidationResult(boolean isValid) {
|
||||
this(isValid, null, null);
|
||||
}
|
||||
|
||||
public ValidationResult and(ValidationResult next) {
|
||||
if (this.isValid)
|
||||
return next;
|
||||
else
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ValidationResult{" +
|
||||
"isValid=" + isValid +
|
||||
", errorMessage='" + errorMessage + '\'' +
|
||||
", errorType=" + errorType +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,27 +28,14 @@ import org.slf4j.LoggerFactory;
|
|||
* <p/>
|
||||
* That class implements just what we need for the moment. It is not intended as a general purpose library class.
|
||||
*/
|
||||
public abstract class NumberValidator {
|
||||
public abstract class NumberValidator extends InputValidator {
|
||||
private static final Logger log = LoggerFactory.getLogger(NumberValidator.class);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Abstract methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
abstract public ValidationResult validate(String input);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Protected methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected ValidationResult validateIfNotEmpty(String input) {
|
||||
if (input == null || input.length() == 0)
|
||||
return new ValidationResult(false, "Empty input is not allowed.", ErrorType.EMPTY_INPUT);
|
||||
else
|
||||
return new ValidationResult(true);
|
||||
}
|
||||
|
||||
protected String cleanInput(String input) {
|
||||
return input.replace(",", ".").trim();
|
||||
}
|
||||
|
@ -75,56 +62,4 @@ public abstract class NumberValidator {
|
|||
else
|
||||
return new ValidationResult(true);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ErrorType
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public enum ErrorType {
|
||||
EMPTY_INPUT,
|
||||
NOT_A_NUMBER,
|
||||
ZERO_NUMBER,
|
||||
NEGATIVE_NUMBER,
|
||||
FRACTIONAL_SATOSHI,
|
||||
EXCEEDS_MAX_FIAT_VALUE, UNDERCUT_MIN_FIAT_VALUE, AMOUNT_LESS_THAN_MIN_AMOUNT,
|
||||
MIN_AMOUNT_LARGER_THAN_MIN_AMOUNT, EXCEEDS_MAX_BTC_VALUE
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ValidationResult
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static class ValidationResult {
|
||||
public final boolean isValid;
|
||||
public final String errorMessage;
|
||||
public final ErrorType errorType;
|
||||
|
||||
public ValidationResult(boolean isValid, String errorMessage, ErrorType errorType) {
|
||||
this.isValid = isValid;
|
||||
this.errorMessage = errorMessage;
|
||||
this.errorType = errorType;
|
||||
}
|
||||
|
||||
ValidationResult(boolean isValid) {
|
||||
this(isValid, null, null);
|
||||
}
|
||||
|
||||
public ValidationResult and(ValidationResult next) {
|
||||
if (this.isValid)
|
||||
return next;
|
||||
else
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ValidationResult{" +
|
||||
"isValid=" + isValid +
|
||||
", errorMessage='" + errorMessage + '\'' +
|
||||
", errorType=" + errorType +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,12 +23,12 @@ import io.bitsquare.crypto.CryptoFacade;
|
|||
import io.bitsquare.gui.components.Popups;
|
||||
import io.bitsquare.msg.MessageFacade;
|
||||
import io.bitsquare.msg.listeners.TakeOfferRequestListener;
|
||||
import io.bitsquare.settings.Settings;
|
||||
import io.bitsquare.persistence.Persistence;
|
||||
import io.bitsquare.settings.Settings;
|
||||
import io.bitsquare.trade.handlers.ErrorMessageHandler;
|
||||
import io.bitsquare.trade.handlers.TransactionResultHandler;
|
||||
import io.bitsquare.trade.protocol.trade.TradeMessage;
|
||||
import io.bitsquare.trade.protocol.createoffer.CreateOfferCoordinator;
|
||||
import io.bitsquare.trade.protocol.trade.TradeMessage;
|
||||
import io.bitsquare.trade.protocol.trade.offerer.BuyerAcceptsOfferProtocol;
|
||||
import io.bitsquare.trade.protocol.trade.offerer.BuyerAcceptsOfferProtocolListener;
|
||||
import io.bitsquare.trade.protocol.trade.offerer.messages.BankTransferInitedMessage;
|
||||
|
@ -47,6 +47,7 @@ import com.google.bitcoin.core.Coin;
|
|||
import com.google.bitcoin.core.Transaction;
|
||||
import com.google.bitcoin.core.TransactionConfidence;
|
||||
import com.google.bitcoin.core.Utils;
|
||||
import com.google.bitcoin.utils.Fiat;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
@ -68,7 +69,7 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The domain for the trading
|
||||
* The domain for the trading
|
||||
* TODO: Too messy, need to be improved a lot....
|
||||
*/
|
||||
public class TradeManager {
|
||||
|
@ -160,16 +161,17 @@ public class TradeManager {
|
|||
|
||||
public void requestPlaceOffer(String id,
|
||||
Direction direction,
|
||||
double price,
|
||||
Fiat price,
|
||||
Coin amount,
|
||||
Coin minAmount,
|
||||
TransactionResultHandler resultHandler,
|
||||
ErrorMessageHandler errorMessageHandler) {
|
||||
|
||||
// TODO price.value -> use Fiat in Offer for price
|
||||
Offer offer = new Offer(id,
|
||||
user.getMessagePublicKey(),
|
||||
direction,
|
||||
price,
|
||||
price.value,
|
||||
amount,
|
||||
minAmount,
|
||||
user.getCurrentBankAccount().getBankAccountType(),
|
||||
|
|
|
@ -17,14 +17,11 @@
|
|||
|
||||
package io.bitsquare.trade.protocol.createoffer.tasks;
|
||||
|
||||
import io.bitsquare.btc.FeePolicy;
|
||||
import io.bitsquare.btc.Restrictions;
|
||||
import io.bitsquare.trade.Offer;
|
||||
import io.bitsquare.trade.handlers.FaultHandler;
|
||||
import io.bitsquare.trade.handlers.ResultHandler;
|
||||
|
||||
import com.google.bitcoin.core.Coin;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
@ -62,8 +59,8 @@ public class ValidateOffer {
|
|||
checkArgument(offer.getPrice() > 0);
|
||||
|
||||
// TODO check balance
|
||||
Coin collateralAsCoin = offer.getAmount().divide((long) (1d / offer.getCollateral()));
|
||||
Coin totalsToFund = collateralAsCoin.add(FeePolicy.CREATE_OFFER_FEE.add(FeePolicy.TX_FEE));
|
||||
// Coin collateralAsCoin = offer.getAmount().divide((long) (1d / offer.getCollateral()));
|
||||
// Coin totalsToFund = collateralAsCoin.add(FeePolicy.CREATE_OFFER_FEE.add(FeePolicy.TX_FEE));
|
||||
// getAddressInfoByTradeID(offerId)
|
||||
// TODO when offer is flattened continue here...
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue