mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 09:52:23 +01:00
changed validation
This commit is contained in:
parent
ed5cc4d628
commit
b91fe8273b
@ -22,7 +22,6 @@ import io.bitsquare.btc.BlockChainFacade;
|
||||
import io.bitsquare.btc.FeePolicy;
|
||||
import io.bitsquare.btc.WalletFacade;
|
||||
import io.bitsquare.crypto.CryptoFacade;
|
||||
import io.bitsquare.gui.util.BSFormatter;
|
||||
import io.bitsquare.msg.BootstrappedPeerFactory;
|
||||
import io.bitsquare.msg.MessageFacade;
|
||||
import io.bitsquare.msg.P2PNode;
|
||||
@ -64,7 +63,6 @@ public class BitSquareModule extends AbstractModule {
|
||||
bind(BootstrappedPeerFactory.class).asEagerSingleton();
|
||||
|
||||
bind(TradeManager.class).asEagerSingleton();
|
||||
bind(BSFormatter.class).asEagerSingleton();
|
||||
|
||||
|
||||
//bind(String.class).annotatedWith(Names.named("networkType")).toInstance(WalletFacade.MAIN_NET);
|
||||
|
@ -19,8 +19,8 @@ package io.bitsquare.gui.components;
|
||||
|
||||
import io.bitsquare.gui.util.validation.InputValidator;
|
||||
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Point2D;
|
||||
import javafx.scene.control.*;
|
||||
@ -43,15 +43,14 @@ import org.slf4j.LoggerFactory;
|
||||
*/
|
||||
public class ValidatingTextField extends TextField {
|
||||
private static final Logger log = LoggerFactory.getLogger(ValidatingTextField.class);
|
||||
private static PopOver popOver;
|
||||
|
||||
private Effect invalidEffect = new DropShadow(BlurType.GAUSSIAN, Color.RED, 4, 0.0, 0, 0);
|
||||
|
||||
private final BooleanProperty isValid = new SimpleBooleanProperty(true);
|
||||
private InputValidator validator;
|
||||
private boolean validateOnFocusOut = true;
|
||||
private boolean needsValidationOnFocusOut;
|
||||
private Region errorPopupLayoutReference;
|
||||
final ObjectProperty<InputValidator.ValidationResult> amountValidationResult = new SimpleObjectProperty<>(new
|
||||
InputValidator.ValidationResult(true));
|
||||
|
||||
private static PopOver popOver;
|
||||
private Region errorPopupLayoutReference = this;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -62,15 +61,31 @@ public class ValidatingTextField extends TextField {
|
||||
if (popOver != null)
|
||||
popOver.hide();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public ValidatingTextField() {
|
||||
super();
|
||||
setupListeners();
|
||||
|
||||
amountValidationResult.addListener((ov, oldValue, newValue) -> {
|
||||
if (newValue != null) {
|
||||
setEffect(newValue.isValid ? null : invalidEffect);
|
||||
|
||||
if (newValue.isValid)
|
||||
hidePopover();
|
||||
else
|
||||
applyErrorMessage(newValue);
|
||||
}
|
||||
});
|
||||
|
||||
sceneProperty().addListener((ov, oldValue, newValue) -> {
|
||||
// we got removed from the scene
|
||||
// lets hide an open popup
|
||||
if (newValue == null)
|
||||
hidePopover();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -78,21 +93,14 @@ public class ValidatingTextField extends TextField {
|
||||
// Public methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void reValidate() {
|
||||
validate(getText());
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Setters
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void setValidator(InputValidator validator) {
|
||||
this.validator = validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param errorPopupLayoutReference The node used as reference for positioning
|
||||
* @param errorPopupLayoutReference The node used as reference for positioning. If not set explicitely the
|
||||
* ValidatingTextField instance is used.
|
||||
*/
|
||||
public void setErrorPopupLayoutReference(Region errorPopupLayoutReference) {
|
||||
this.errorPopupLayoutReference = errorPopupLayoutReference;
|
||||
@ -103,12 +111,8 @@ public class ValidatingTextField extends TextField {
|
||||
// Getters
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public boolean getIsValid() {
|
||||
return isValid.get();
|
||||
}
|
||||
|
||||
public BooleanProperty isValidProperty() {
|
||||
return isValid;
|
||||
public ObjectProperty<InputValidator.ValidationResult> amountValidationResultProperty() {
|
||||
return amountValidationResult;
|
||||
}
|
||||
|
||||
|
||||
@ -116,40 +120,6 @@ public class ValidatingTextField extends TextField {
|
||||
// Private methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void setupListeners() {
|
||||
sceneProperty().addListener((ov, oldValue, newValue) -> {
|
||||
// we got removed from the scene
|
||||
// lets hide an open popup
|
||||
if (newValue == null)
|
||||
hidePopover();
|
||||
});
|
||||
|
||||
textProperty().addListener((ov, oldValue, newValue) -> {
|
||||
if (validator != null) {
|
||||
if (!validateOnFocusOut)
|
||||
validate(newValue);
|
||||
else
|
||||
needsValidationOnFocusOut = true;
|
||||
}
|
||||
});
|
||||
|
||||
focusedProperty().addListener((ov, oldValue, newValue) -> {
|
||||
if (validateOnFocusOut && needsValidationOnFocusOut &&
|
||||
!newValue && getScene() != null && getScene().getWindow().isFocused())
|
||||
validate(getText());
|
||||
});
|
||||
|
||||
isValid.addListener((ov, oldValue, newValue) -> applyEffect(newValue));
|
||||
}
|
||||
|
||||
private void validate(String input) {
|
||||
if (input != null && validator != null) {
|
||||
InputValidator.ValidationResult validationResult = validator.validate(input);
|
||||
isValid.set(validationResult.isValid);
|
||||
applyErrorMessage(validationResult);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyErrorMessage(InputValidator.ValidationResult validationResult) {
|
||||
if (validationResult.isValid) {
|
||||
if (popOver != null) {
|
||||
@ -160,35 +130,21 @@ public class ValidatingTextField extends TextField {
|
||||
if (popOver == null)
|
||||
createErrorPopOver(validationResult.errorMessage);
|
||||
else
|
||||
setErrorMessage(validationResult.errorMessage);
|
||||
((Label) popOver.getContentNode()).setText(validationResult.errorMessage);
|
||||
|
||||
popOver.show(getScene().getWindow(), getErrorPopupPosition().getX(), getErrorPopupPosition().getY());
|
||||
}
|
||||
}
|
||||
|
||||
private void applyEffect(boolean isValid) {
|
||||
setEffect(isValid ? null : invalidEffect);
|
||||
}
|
||||
|
||||
private Point2D getErrorPopupPosition() {
|
||||
Window window = getScene().getWindow();
|
||||
Point2D point;
|
||||
double x;
|
||||
if (errorPopupLayoutReference == null) {
|
||||
point = localToScene(0, 0);
|
||||
x = point.getX() + window.getX() + getWidth() + 20;
|
||||
}
|
||||
else {
|
||||
point = errorPopupLayoutReference.localToScene(0, 0);
|
||||
x = point.getX() + window.getX() + errorPopupLayoutReference.getWidth() + 20;
|
||||
}
|
||||
point = errorPopupLayoutReference.localToScene(0, 0);
|
||||
double x = point.getX() + window.getX() + errorPopupLayoutReference.getWidth() + 20;
|
||||
double y = point.getY() + window.getY() + Math.floor(getHeight() / 2);
|
||||
return new Point2D(x, y);
|
||||
}
|
||||
|
||||
private static void setErrorMessage(String errorMessage) {
|
||||
((Label) popOver.getContentNode()).setText(errorMessage);
|
||||
}
|
||||
|
||||
private static void createErrorPopOver(String errorMessage) {
|
||||
Label errorLabel = new Label(errorMessage);
|
||||
@ -196,8 +152,8 @@ public class ValidatingTextField extends TextField {
|
||||
errorLabel.setPadding(new Insets(0, 10, 0, 10));
|
||||
|
||||
popOver = new PopOver(errorLabel);
|
||||
popOver.setAutoFix(true);
|
||||
popOver.setDetachedTitle("");
|
||||
popOver.setDetachable(false);
|
||||
popOver.setArrowIndent(5);
|
||||
}
|
||||
|
||||
}
|
@ -75,6 +75,8 @@ public class TradeController extends CachedViewController {
|
||||
|
||||
// TODO find better solution
|
||||
// Textfield focus out triggers validation, use runLater as quick fix...
|
||||
|
||||
//TODO update to new verison
|
||||
((TabPane) root).getSelectionModel().selectedIndexProperty().addListener((observableValue) ->
|
||||
Platform.runLater(ValidatingTextField::hidePopover));
|
||||
}
|
||||
|
@ -24,9 +24,6 @@ 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.validation.BtcValidator;
|
||||
import io.bitsquare.gui.util.validation.FiatValidator;
|
||||
import io.bitsquare.gui.util.validation.ValidationHelper;
|
||||
import io.bitsquare.trade.orderbook.OrderBookFilter;
|
||||
|
||||
import java.net.URL;
|
||||
@ -78,8 +75,12 @@ public class CreateOfferCB extends CachedViewController {
|
||||
public void initialize(URL url, ResourceBundle rb) {
|
||||
super.initialize(url, rb);
|
||||
|
||||
//TODO handle in base class
|
||||
pm.onViewInitialized();
|
||||
|
||||
setupBindings();
|
||||
setupListeners();
|
||||
configTextFieldValidators();
|
||||
balanceTextField.setup(pm.getWalletFacade(), pm.address.get());
|
||||
}
|
||||
|
||||
@ -87,21 +88,19 @@ public class CreateOfferCB extends CachedViewController {
|
||||
public void deactivate() {
|
||||
super.deactivate();
|
||||
|
||||
//TODO handle in base class
|
||||
pm.deactivate();
|
||||
|
||||
//TODO check that again
|
||||
((TradeController) parentController).onCreateOfferViewRemoved();
|
||||
if (parentController != null) ((TradeController) parentController).onCreateOfferViewRemoved();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activate() {
|
||||
super.activate();
|
||||
|
||||
//TODO handle in base class
|
||||
pm.activate();
|
||||
|
||||
setupBindings();
|
||||
setupListeners();
|
||||
setupTextFieldValidators();
|
||||
}
|
||||
|
||||
|
||||
@ -138,7 +137,7 @@ public class CreateOfferCB extends CachedViewController {
|
||||
|
||||
private void setupListeners() {
|
||||
volumeTextField.focusedProperty().addListener((o, oldValue, newValue) -> {
|
||||
pm.onFocusOutVolumeTextField(oldValue, newValue, volumeTextField.getText());
|
||||
pm.onFocusOutVolumeTextField(oldValue, newValue);
|
||||
volumeTextField.setText(pm.volume.get());
|
||||
});
|
||||
|
||||
@ -157,15 +156,6 @@ public class CreateOfferCB extends CachedViewController {
|
||||
minAmountTextField.setText(pm.minAmount.get());
|
||||
});
|
||||
|
||||
pm.needsInputValidation.addListener((o, oldValue, newValue) -> {
|
||||
if (newValue) {
|
||||
amountTextField.reValidate();
|
||||
minAmountTextField.reValidate();
|
||||
volumeTextField.reValidate();
|
||||
priceTextField.reValidate();
|
||||
}
|
||||
});
|
||||
|
||||
pm.showWarningInvalidBtcDecimalPlaces.addListener((o, oldValue, newValue) -> {
|
||||
if (newValue) {
|
||||
Popups.openWarningPopup("Warning", "The amount you have entered exceeds the number of allowed decimal" +
|
||||
@ -182,11 +172,11 @@ public class CreateOfferCB extends CachedViewController {
|
||||
}
|
||||
});
|
||||
|
||||
pm.showWarningInvalidBtcFractions.addListener((o, oldValue, newValue) -> {
|
||||
pm.showWarningAdjustedVolume.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.");
|
||||
pm.showWarningInvalidBtcFractions.set(false);
|
||||
pm.showWarningAdjustedVolume.set(false);
|
||||
volumeTextField.setText(pm.volume.get());
|
||||
}
|
||||
});
|
||||
@ -224,46 +214,21 @@ public class CreateOfferCB extends CachedViewController {
|
||||
totalFeesTextField.textProperty().bind(pm.totalFees);
|
||||
transactionIdTextField.textProperty().bind(pm.transactionId);
|
||||
|
||||
amountTextField.amountValidationResultProperty().bind(pm.amountValidationResult);
|
||||
minAmountTextField.amountValidationResultProperty().bind(pm.minAmountValidationResult);
|
||||
priceTextField.amountValidationResultProperty().bind(pm.priceValidationResult);
|
||||
volumeTextField.amountValidationResultProperty().bind(pm.volumeValidationResult);
|
||||
|
||||
placeOfferButton.visibleProperty().bind(pm.isPlaceOfferButtonVisible);
|
||||
placeOfferButton.disableProperty().bind(pm.isPlaceOfferButtonDisabled);
|
||||
closeButton.visibleProperty().bind(pm.isCloseButtonVisible);
|
||||
|
||||
//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() {
|
||||
private void configTextFieldValidators() {
|
||||
Region referenceNode = (Region) amountTextField.getParent();
|
||||
|
||||
BtcValidator amountValidator = new BtcValidator();
|
||||
amountTextField.setValidator(amountValidator);
|
||||
amountTextField.setErrorPopupLayoutReference(referenceNode);
|
||||
|
||||
priceTextField.setValidator(new FiatValidator());
|
||||
priceTextField.setErrorPopupLayoutReference(referenceNode);
|
||||
|
||||
volumeTextField.setValidator(new FiatValidator());
|
||||
volumeTextField.setErrorPopupLayoutReference(referenceNode);
|
||||
|
||||
BtcValidator minAmountValidator = new BtcValidator();
|
||||
minAmountTextField.setValidator(minAmountValidator);
|
||||
|
||||
ValidationHelper.setupMinAmountInRangeOfAmountValidation(amountTextField,
|
||||
minAmountTextField,
|
||||
pm.amount,
|
||||
pm.minAmount,
|
||||
amountValidator,
|
||||
minAmountValidator);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ import org.slf4j.LoggerFactory;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
/**
|
||||
* Domain for that UI element.
|
||||
* Domain for that UI element.
|
||||
* Note that the create offer domain has a deeper scope in the application domain (TradeManager).
|
||||
* That model is just responsible for the domain specific parts displayed needed in that UI element.
|
||||
*/
|
||||
@ -152,6 +152,15 @@ class CreateOfferModel {
|
||||
);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Validation
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
boolean isMinAmountLessOrEqualAmount() {
|
||||
if (minAmountAsCoin != null && amountAsCoin != null)
|
||||
return !minAmountAsCoin.isGreaterThan(amountAsCoin);
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Setter/Getter
|
||||
|
@ -19,6 +19,9 @@ package io.bitsquare.gui.trade.createoffer;
|
||||
|
||||
import io.bitsquare.btc.WalletFacade;
|
||||
import io.bitsquare.gui.util.BSFormatter;
|
||||
import io.bitsquare.gui.util.validation.BtcValidator;
|
||||
import io.bitsquare.gui.util.validation.FiatValidator;
|
||||
import io.bitsquare.gui.util.validation.InputValidator;
|
||||
import io.bitsquare.locale.Localisation;
|
||||
import io.bitsquare.trade.Direction;
|
||||
import io.bitsquare.trade.orderbook.OrderBookFilter;
|
||||
@ -46,6 +49,8 @@ class CreateOfferPM {
|
||||
private static final Logger log = LoggerFactory.getLogger(CreateOfferPM.class);
|
||||
|
||||
private CreateOfferModel model;
|
||||
private BtcValidator btcValidator = new BtcValidator();
|
||||
private FiatValidator fiatValidator = new FiatValidator();
|
||||
|
||||
final StringProperty amount = new SimpleStringProperty();
|
||||
final StringProperty minAmount = new SimpleStringProperty();
|
||||
@ -69,19 +74,23 @@ class CreateOfferPM {
|
||||
final BooleanProperty isCloseButtonVisible = new SimpleBooleanProperty();
|
||||
final BooleanProperty isPlaceOfferButtonVisible = new SimpleBooleanProperty(true);
|
||||
final BooleanProperty isPlaceOfferButtonDisabled = new SimpleBooleanProperty();
|
||||
final BooleanProperty needsInputValidation = new SimpleBooleanProperty();
|
||||
final BooleanProperty showWarningInvalidBtcFractions = new SimpleBooleanProperty();
|
||||
final BooleanProperty showWarningAdjustedVolume = new SimpleBooleanProperty();
|
||||
final BooleanProperty showWarningInvalidFiatDecimalPlaces = new SimpleBooleanProperty();
|
||||
final BooleanProperty showWarningInvalidBtcDecimalPlaces = new SimpleBooleanProperty();
|
||||
final BooleanProperty showTransactionPublishedScreen = new SimpleBooleanProperty();
|
||||
final BooleanProperty requestPlaceOfferFailed = new SimpleBooleanProperty();
|
||||
|
||||
final ObjectProperty<InputValidator.ValidationResult> amountValidationResult = new SimpleObjectProperty<>();
|
||||
final ObjectProperty<InputValidator.ValidationResult> minAmountValidationResult = new SimpleObjectProperty<>();
|
||||
final ObjectProperty<InputValidator.ValidationResult> priceValidationResult = new SimpleObjectProperty<>();
|
||||
final ObjectProperty<InputValidator.ValidationResult> volumeValidationResult = new SimpleObjectProperty<>();
|
||||
|
||||
final ObjectProperty<Coin> totalToPayAsCoin = new SimpleObjectProperty<>();
|
||||
final ObjectProperty<Address> address = new SimpleObjectProperty<>();
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
// Constructor (called by CB)
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CreateOfferPM(CreateOfferModel model) {
|
||||
@ -90,7 +99,7 @@ class CreateOfferPM {
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Lifecycle
|
||||
// Lifecycle (called by CB)
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void onViewInitialized() {
|
||||
@ -134,46 +143,54 @@ class CreateOfferPM {
|
||||
}
|
||||
|
||||
void activate() {
|
||||
//TODO handle in base class
|
||||
model.activate();
|
||||
}
|
||||
|
||||
|
||||
void deactivate() {
|
||||
//TODO handle in base class
|
||||
model.deactivate();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Public methods
|
||||
// Public API methods (called by CB)
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void setOrderBookFilter(OrderBookFilter orderBookFilter) {
|
||||
model.setDirection(orderBookFilter.getDirection());
|
||||
model.amountAsCoin = orderBookFilter.getAmount();
|
||||
model.minAmountAsCoin = orderBookFilter.getAmount();
|
||||
directionLabel.set(model.getDirection() == Direction.BUY ? "Buy:" : "Sell:");
|
||||
|
||||
if (orderBookFilter.getAmount() != null) {
|
||||
model.amountAsCoin = orderBookFilter.getAmount();
|
||||
amount.set(formatCoin(model.amountAsCoin));
|
||||
|
||||
model.minAmountAsCoin = orderBookFilter.getAmount();
|
||||
minAmount.set(formatCoin(model.minAmountAsCoin));
|
||||
}
|
||||
|
||||
// TODO use Fiat in orderBookFilter
|
||||
model.priceAsFiat = parseToFiatWith2Decimals(String.valueOf(orderBookFilter.getPrice()));
|
||||
if (orderBookFilter.getPrice() != 0) {
|
||||
model.priceAsFiat = parseToFiatWith2Decimals(String.valueOf(orderBookFilter.getPrice()));
|
||||
price.set(formatFiat(model.priceAsFiat));
|
||||
}
|
||||
|
||||
directionLabel.set(model.getDirection() == Direction.BUY ? "Buy:" : "Sell:");
|
||||
amount.set(formatCoin(model.amountAsCoin));
|
||||
minAmount.set(formatCoin(model.minAmountAsCoin));
|
||||
price.set(formatFiat(model.priceAsFiat));
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// View Events
|
||||
// UI actions (called by CB)
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void placeOffer() {
|
||||
model.amountAsCoin = parseToCoinWith4Decimals(amount.get());
|
||||
model.minAmountAsCoin = parseToCoinWith4Decimals(minAmount.get());
|
||||
model.priceAsFiat = parseToFiatWith2Decimals(price.get());
|
||||
model.minAmountAsCoin = parseToCoinWith4Decimals(minAmount.get());
|
||||
if (allInputsValid()) {
|
||||
|
||||
needsInputValidation.set(true);
|
||||
model.amountAsCoin = parseToCoinWith4Decimals(amount.get());
|
||||
model.minAmountAsCoin = parseToCoinWith4Decimals(minAmount.get());
|
||||
model.priceAsFiat = parseToFiatWith2Decimals(price.get());
|
||||
model.minAmountAsCoin = parseToCoinWith4Decimals(minAmount.get());
|
||||
|
||||
if (inputValid()) {
|
||||
model.placeOffer();
|
||||
isPlaceOfferButtonDisabled.set(true);
|
||||
isPlaceOfferButtonVisible.set(true);
|
||||
@ -183,79 +200,100 @@ class CreateOfferPM {
|
||||
void close() {
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// UI events (called by CB)
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void setupInputListeners() {
|
||||
|
||||
// bindBidirectional for amount, price, volume and minAmount
|
||||
amount.addListener(ov -> {
|
||||
model.amountAsCoin = parseToCoinWith4Decimals(amount.get());
|
||||
calculateVolume();
|
||||
calculateTotalToPay();
|
||||
calculateCollateral();
|
||||
|
||||
});
|
||||
|
||||
price.addListener(ov -> {
|
||||
model.priceAsFiat = parseToFiatWith2Decimals(price.get());
|
||||
calculateVolume();
|
||||
calculateTotalToPay();
|
||||
calculateCollateral();
|
||||
});
|
||||
|
||||
volume.addListener(ov -> {
|
||||
model.volumeAsFiat = parseToFiatWith2Decimals(volume.get());
|
||||
calculateAmount();
|
||||
calculateTotalToPay();
|
||||
calculateCollateral();
|
||||
});
|
||||
}
|
||||
// when focus out we do validation and apply the data to the model
|
||||
|
||||
void onFocusOutAmountTextField(Boolean oldValue, Boolean newValue) {
|
||||
|
||||
if (oldValue && !newValue) {
|
||||
showWarningInvalidBtcDecimalPlaces.set(!hasBtcValidDecimals(amount.get()));
|
||||
model.amountAsCoin = parseToCoinWith4Decimals(amount.get());
|
||||
amount.set(formatCoin(model.amountAsCoin));
|
||||
calculateVolume();
|
||||
InputValidator.ValidationResult result = isBtcInputValid(amount.get());
|
||||
boolean isValid = result.isValid;
|
||||
amountValidationResult.set(result);
|
||||
if (isValid) {
|
||||
showWarningInvalidBtcDecimalPlaces.set(!hasBtcValidDecimals(amount.get()));
|
||||
// only allow max 4 decimal places for btc values
|
||||
model.amountAsCoin = parseToCoinWith4Decimals(amount.get());
|
||||
// reformat input to general btc format
|
||||
amount.set(formatCoin(model.amountAsCoin));
|
||||
calculateVolume();
|
||||
|
||||
if (!model.isMinAmountLessOrEqualAmount()) {
|
||||
amountValidationResult.set(new InputValidator.ValidationResult(false,
|
||||
"Amount cannot be smaller than minimum amount."));
|
||||
}
|
||||
else {
|
||||
amountValidationResult.set(result);
|
||||
if (minAmount.get() != null)
|
||||
minAmountValidationResult.set(isBtcInputValid(minAmount.get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onFocusOutMinAmountTextField(Boolean oldValue, Boolean newValue) {
|
||||
|
||||
if (oldValue && !newValue) {
|
||||
showWarningInvalidBtcDecimalPlaces.set(!hasBtcValidDecimals(minAmount.get()));
|
||||
model.minAmountAsCoin = parseToCoinWith4Decimals(minAmount.get());
|
||||
minAmount.set(formatCoin(model.minAmountAsCoin));
|
||||
}
|
||||
}
|
||||
InputValidator.ValidationResult result = isBtcInputValid(minAmount.get());
|
||||
boolean isValid = result.isValid;
|
||||
minAmountValidationResult.set(result);
|
||||
if (isValid) {
|
||||
showWarningInvalidBtcDecimalPlaces.set(!hasBtcValidDecimals(minAmount.get()));
|
||||
model.minAmountAsCoin = parseToCoinWith4Decimals(minAmount.get());
|
||||
minAmount.set(formatCoin(model.minAmountAsCoin));
|
||||
|
||||
void onFocusOutVolumeTextField(Boolean oldValue, Boolean newValue, String volumeTextFieldText) {
|
||||
if (oldValue && !newValue) {
|
||||
showWarningInvalidFiatDecimalPlaces.set(!hasFiatValidDecimals(volume.get()));
|
||||
model.volumeAsFiat = parseToFiatWith2Decimals(volume.get());
|
||||
volume.set(formatFiat(model.volumeAsFiat));
|
||||
calculateAmount();
|
||||
|
||||
showWarningInvalidBtcFractions.set(!formatFiat(parseToFiatWith2Decimals(volumeTextFieldText)).equals
|
||||
(volume.get()));
|
||||
if (!model.isMinAmountLessOrEqualAmount()) {
|
||||
minAmountValidationResult.set(new InputValidator.ValidationResult(false,
|
||||
"Minimum amount cannot be larger than amount."));
|
||||
}
|
||||
else {
|
||||
minAmountValidationResult.set(result);
|
||||
if (amount.get() != null)
|
||||
amountValidationResult.set(isBtcInputValid(amount.get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onFocusOutPriceTextField(Boolean oldValue, Boolean newValue) {
|
||||
if (oldValue && !newValue) {
|
||||
showWarningInvalidFiatDecimalPlaces.set(!hasFiatValidDecimals(price.get()));
|
||||
model.priceAsFiat = parseToFiatWith2Decimals(price.get());
|
||||
price.set(formatFiat(model.priceAsFiat));
|
||||
calculateVolume();
|
||||
InputValidator.ValidationResult result = isFiatInputValid(price.get());
|
||||
boolean isValid = result.isValid;
|
||||
priceValidationResult.set(result);
|
||||
if (isValid) {
|
||||
showWarningInvalidFiatDecimalPlaces.set(!hasFiatValidDecimals(price.get()));
|
||||
model.priceAsFiat = parseToFiatWith2Decimals(price.get());
|
||||
price.set(formatFiat(model.priceAsFiat));
|
||||
calculateVolume();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onFocusOutVolumeTextField(Boolean oldValue, Boolean newValue) {
|
||||
if (oldValue && !newValue) {
|
||||
InputValidator.ValidationResult result = isBtcInputValid(volume.get());
|
||||
boolean isValid = result.isValid;
|
||||
volumeValidationResult.set(result);
|
||||
if (isValid) {
|
||||
String origVolume = volume.get();
|
||||
showWarningInvalidFiatDecimalPlaces.set(!hasFiatValidDecimals(volume.get()));
|
||||
model.volumeAsFiat = parseToFiatWith2Decimals(volume.get());
|
||||
|
||||
volume.set(formatFiat(model.volumeAsFiat));
|
||||
calculateAmount();
|
||||
|
||||
// must be after calculateAmount (btc value has been adjusted in case the calculation leads to
|
||||
// invalid decimal places for the amount value
|
||||
showWarningAdjustedVolume.set(!formatFiat(parseToFiatWith2Decimals(origVolume)).equals(volume.get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Getters
|
||||
// Getters (called by CB)
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WalletFacade getWalletFacade() {
|
||||
@ -267,11 +305,45 @@ class CreateOfferPM {
|
||||
// Private
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private boolean inputValid() {
|
||||
//TODO
|
||||
return true;
|
||||
private void setupInputListeners() {
|
||||
|
||||
// bindBidirectional for amount, price, volume and minAmount
|
||||
// We do volume/amount calculation during input
|
||||
amount.addListener((ov, oldValue, newValue) -> {
|
||||
if (isBtcInputValid(newValue).isValid) {
|
||||
model.amountAsCoin = parseToCoinWith4Decimals(newValue);
|
||||
calculateVolume();
|
||||
calculateTotalToPay();
|
||||
calculateCollateral();
|
||||
}
|
||||
});
|
||||
|
||||
price.addListener((ov, oldValue, newValue) -> {
|
||||
if (isFiatInputValid(newValue).isValid) {
|
||||
model.priceAsFiat = parseToFiatWith2Decimals(newValue);
|
||||
calculateVolume();
|
||||
calculateTotalToPay();
|
||||
calculateCollateral();
|
||||
}
|
||||
});
|
||||
|
||||
volume.addListener((ov, oldValue, newValue) -> {
|
||||
if (isFiatInputValid(newValue).isValid) {
|
||||
model.volumeAsFiat = parseToFiatWith2Decimals(newValue);
|
||||
calculateAmount();
|
||||
calculateTotalToPay();
|
||||
calculateCollateral();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private boolean allInputsValid() {
|
||||
return isBtcInputValid(amount.get()).isValid && isFiatInputValid(price.get()).isValid && isFiatInputValid
|
||||
(volume.get()).isValid;
|
||||
}
|
||||
|
||||
//TODO move to model
|
||||
private void calculateVolume() {
|
||||
model.amountAsCoin = parseToCoinWith4Decimals(amount.get());
|
||||
model.priceAsFiat = parseToFiatWith2Decimals(price.get());
|
||||
@ -282,6 +354,7 @@ class CreateOfferPM {
|
||||
}
|
||||
}
|
||||
|
||||
//TODO move to model
|
||||
private void calculateAmount() {
|
||||
model.volumeAsFiat = parseToFiatWith2Decimals(volume.get());
|
||||
model.priceAsFiat = parseToFiatWith2Decimals(price.get());
|
||||
@ -295,8 +368,20 @@ class CreateOfferPM {
|
||||
calculateTotalToPay();
|
||||
calculateCollateral();
|
||||
}
|
||||
|
||||
if (!model.isMinAmountLessOrEqualAmount()) {
|
||||
amountValidationResult.set(new InputValidator.ValidationResult(false,
|
||||
"Amount cannot be smaller than minimum amount."));
|
||||
}
|
||||
else {
|
||||
if (amount.get() != null)
|
||||
amountValidationResult.set(isBtcInputValid(amount.get()));
|
||||
if (minAmount.get() != null)
|
||||
minAmountValidationResult.set(isBtcInputValid(minAmount.get()));
|
||||
}
|
||||
}
|
||||
|
||||
//TODO move to model
|
||||
private void calculateTotalToPay() {
|
||||
calculateCollateral();
|
||||
|
||||
@ -307,10 +392,27 @@ class CreateOfferPM {
|
||||
}
|
||||
}
|
||||
|
||||
//TODO move to model
|
||||
private void calculateCollateral() {
|
||||
if (model.amountAsCoin != null) {
|
||||
model.collateralAsCoin = model.amountAsCoin.multiply(model.collateralAsLong.get()).divide(1000);
|
||||
collateral.set(BSFormatter.formatCoinWithCode(model.collateralAsCoin));
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Package scope for testing
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
InputValidator.ValidationResult isBtcInputValid(String input) {
|
||||
|
||||
return btcValidator.validate(input);
|
||||
}
|
||||
|
||||
InputValidator.ValidationResult isFiatInputValid(String input) {
|
||||
|
||||
return fiatValidator.validate(input);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -80,8 +80,7 @@ public class BtcValidator extends NumberValidator {
|
||||
if (satoshis.scale() > 0)
|
||||
return new ValidationResult(
|
||||
false,
|
||||
"Input results in a Bitcoin value with a fraction of the smallest unit (Satoshi).",
|
||||
ErrorType.FRACTIONAL_SATOSHI);
|
||||
"Input results in a Bitcoin value with a fraction of the smallest unit (Satoshi).");
|
||||
else
|
||||
return new ValidationResult(true);
|
||||
}
|
||||
@ -92,8 +91,7 @@ public class BtcValidator extends NumberValidator {
|
||||
if (satoshis.longValue() > NetworkParameters.MAX_MONEY.longValue())
|
||||
return new ValidationResult(
|
||||
false,
|
||||
"Input larger as maximum possible Bitcoin value is not allowed.",
|
||||
ErrorType.EXCEEDS_MAX_BTC_VALUE);
|
||||
"Input larger as maximum possible Bitcoin value is not allowed.");
|
||||
else
|
||||
return new ValidationResult(true);
|
||||
}
|
||||
|
@ -65,8 +65,7 @@ public class FiatValidator extends NumberValidator {
|
||||
if (d < MIN_FIAT_VALUE)
|
||||
return new ValidationResult(
|
||||
false,
|
||||
"Input smaller as minimum possible Fiat value is not allowed..",
|
||||
ErrorType.UNDERCUT_MIN_FIAT_VALUE);
|
||||
"Input smaller as minimum possible Fiat value is not allowed..");
|
||||
else
|
||||
return new ValidationResult(true);
|
||||
}
|
||||
@ -76,8 +75,7 @@ public class FiatValidator extends NumberValidator {
|
||||
if (d > MAX_FIAT_VALUE)
|
||||
return new ValidationResult(
|
||||
false,
|
||||
"Input larger as maximum possible Fiat value is not allowed.",
|
||||
ErrorType.EXCEEDS_MAX_FIAT_VALUE);
|
||||
"Input larger as maximum possible Fiat value is not allowed.");
|
||||
else
|
||||
return new ValidationResult(true);
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ public abstract class InputValidator {
|
||||
|
||||
protected ValidationResult validateIfNotEmpty(String input) {
|
||||
if (input == null || input.length() == 0)
|
||||
return new ValidationResult(false, "Empty input is not allowed.", ErrorType.EMPTY_INPUT);
|
||||
return new ValidationResult(false, "Empty input is not allowed.");
|
||||
else
|
||||
return new ValidationResult(true);
|
||||
}
|
||||
@ -54,21 +54,6 @@ public abstract class InputValidator {
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -76,16 +61,14 @@ public abstract class InputValidator {
|
||||
public static class ValidationResult {
|
||||
public final boolean isValid;
|
||||
public final String errorMessage;
|
||||
public final ErrorType errorType;
|
||||
|
||||
public ValidationResult(boolean isValid, String errorMessage, ErrorType errorType) {
|
||||
public ValidationResult(boolean isValid, String errorMessage) {
|
||||
this.isValid = isValid;
|
||||
this.errorMessage = errorMessage;
|
||||
this.errorType = errorType;
|
||||
}
|
||||
|
||||
ValidationResult(boolean isValid) {
|
||||
this(isValid, null, null);
|
||||
public ValidationResult(boolean isValid) {
|
||||
this(isValid, null);
|
||||
}
|
||||
|
||||
public ValidationResult and(ValidationResult next) {
|
||||
@ -100,7 +83,6 @@ public abstract class InputValidator {
|
||||
return "ValidationResult{" +
|
||||
"isValid=" + isValid +
|
||||
", errorMessage='" + errorMessage + '\'' +
|
||||
", errorType=" + errorType +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
@ -45,20 +45,20 @@ public abstract class NumberValidator extends InputValidator {
|
||||
Double.parseDouble(input);
|
||||
return new ValidationResult(true);
|
||||
} catch (Exception e) {
|
||||
return new ValidationResult(false, "Input is not a valid number.", ErrorType.NOT_A_NUMBER);
|
||||
return new ValidationResult(false, "Input is not a valid number.");
|
||||
}
|
||||
}
|
||||
|
||||
protected ValidationResult validateIfNotZero(String input) {
|
||||
if (Double.parseDouble(input) == 0)
|
||||
return new ValidationResult(false, "Input of 0 is not allowed.", ErrorType.ZERO_NUMBER);
|
||||
return new ValidationResult(false, "Input of 0 is not allowed.");
|
||||
else
|
||||
return new ValidationResult(true);
|
||||
}
|
||||
|
||||
protected ValidationResult validateIfNotNegative(String input) {
|
||||
if (Double.parseDouble(input) < 0)
|
||||
return new ValidationResult(false, "A negative value is not allowed.", ErrorType.NEGATIVE_NUMBER);
|
||||
return new ValidationResult(false, "A negative value is not allowed.");
|
||||
else
|
||||
return new ValidationResult(true);
|
||||
}
|
||||
|
@ -1,117 +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.util.validation;
|
||||
|
||||
import io.bitsquare.gui.components.ValidatingTextField;
|
||||
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.scene.control.*;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Helper class for setting up the validation and dependencies for minAmount and Amount.
|
||||
* TODO Might be improved but does the job for now...
|
||||
*/
|
||||
public class ValidationHelper {
|
||||
private static final Logger log = LoggerFactory.getLogger(ValidationHelper.class);
|
||||
|
||||
/**
|
||||
* Handles validation between minAmount and amount fields
|
||||
* Min amount must not be larger as amount.
|
||||
* Handles focus out events to display always the error popup from the field where the focus out happened.
|
||||
*/
|
||||
public static void setupMinAmountInRangeOfAmountValidation(ValidatingTextField amountTextField,
|
||||
ValidatingTextField minAmountTextField,
|
||||
StringProperty amount,
|
||||
StringProperty minAmount,
|
||||
BtcValidator amountValidator,
|
||||
BtcValidator 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())
|
||||
validateMinAmount(amountTextField,
|
||||
minAmountTextField,
|
||||
amount,
|
||||
minAmount,
|
||||
amountValidator,
|
||||
minAmountValidator,
|
||||
amountTextField);
|
||||
});
|
||||
|
||||
minAmountTextField.focusedProperty().addListener((ov, oldValue, newValue) -> {
|
||||
// only on focus out and ignore focus loss from window
|
||||
if (!newValue && minAmountTextField.getScene() != null &&
|
||||
minAmountTextField.getScene().getWindow().isFocused())
|
||||
validateMinAmount(amountTextField,
|
||||
minAmountTextField,
|
||||
amount,
|
||||
minAmount,
|
||||
amountValidator,
|
||||
minAmountValidator,
|
||||
minAmountTextField);
|
||||
});
|
||||
}
|
||||
|
||||
private static void validateMinAmount(ValidatingTextField amountTextField,
|
||||
ValidatingTextField minAmountTextField,
|
||||
StringProperty amount,
|
||||
StringProperty minAmount,
|
||||
BtcValidator amountValidator,
|
||||
BtcValidator minAmountValidator,
|
||||
TextField currentTextField) {
|
||||
amountValidator.overrideResult(null);
|
||||
String amountCleaned = amount.get() != null ? amount.get().replace(",", ".").trim() : "0";
|
||||
String minAmountCleaned = minAmount.get() != null ? minAmount.get().replace(",", ".").trim() : "0";
|
||||
|
||||
if (!amountValidator.validate(amountCleaned).isValid)
|
||||
return;
|
||||
|
||||
minAmountValidator.overrideResult(null);
|
||||
if (!minAmountValidator.validate(minAmountCleaned).isValid)
|
||||
return;
|
||||
|
||||
if (currentTextField == amountTextField) {
|
||||
if (Double.parseDouble(amountCleaned) < Double.parseDouble(minAmountCleaned)) {
|
||||
amountValidator.overrideResult(new NumberValidator.ValidationResult(false,
|
||||
"Amount cannot be smaller than minimum amount.",
|
||||
NumberValidator.ErrorType.AMOUNT_LESS_THAN_MIN_AMOUNT));
|
||||
amountTextField.reValidate();
|
||||
}
|
||||
else {
|
||||
amountValidator.overrideResult(null);
|
||||
minAmountTextField.reValidate();
|
||||
}
|
||||
}
|
||||
else if (currentTextField == minAmountTextField) {
|
||||
if (Double.parseDouble(minAmountCleaned) > Double.parseDouble(amountCleaned)) {
|
||||
minAmountValidator.overrideResult(new NumberValidator.ValidationResult(false,
|
||||
"Minimum amount cannot be larger than amount.",
|
||||
NumberValidator.ErrorType.MIN_AMOUNT_LARGER_THAN_MIN_AMOUNT));
|
||||
minAmountTextField.reValidate();
|
||||
}
|
||||
else {
|
||||
minAmountValidator.overrideResult(null);
|
||||
amountTextField.reValidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -10,15 +10,19 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
// TODO update to open source file when its released
|
||||
|
||||
/** Manages the directory where the app stores all its files. */
|
||||
/**
|
||||
* Manages the directory where the app stores all its files.
|
||||
*/
|
||||
public class AppDirectory {
|
||||
public static Path getUserDataDir() {
|
||||
String os = System.getProperty("os.name").toLowerCase();
|
||||
if (os.contains("win")) {
|
||||
return Paths.get(System.getenv("APPDATA"));
|
||||
} else if (os.contains("mac")) {
|
||||
}
|
||||
else if (os.contains("mac")) {
|
||||
return Paths.get(System.getProperty("user.home"), "Library", "Application Support");
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// Linux and other similar systems, we hope (not Android).
|
||||
return Paths.get(System.getProperty("user.home"), ".local", "share");
|
||||
}
|
||||
@ -30,7 +34,7 @@ public class AppDirectory {
|
||||
|
||||
public static Path initAppDir(String appName) throws IOException {
|
||||
AppDirectory.appName = appName;
|
||||
|
||||
|
||||
Path dir = dir();
|
||||
if (!Files.exists(dir))
|
||||
Files.createDirectory(dir);
|
||||
@ -39,7 +43,7 @@ public class AppDirectory {
|
||||
return dir;
|
||||
}
|
||||
|
||||
private static String appName;
|
||||
private static String appName = "";
|
||||
|
||||
private static Path dir;
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
-->
|
||||
</root>
|
||||
|
||||
<logger name="io.bitsquare" level="WARN"/>
|
||||
<logger name="io.bitsquare" level="TRACE"/>
|
||||
|
||||
<logger name="com.google.bitcoin" level="WARN"/>
|
||||
<logger name="net.tomp2p" level="WARN"/>
|
||||
|
@ -22,10 +22,12 @@ import io.bitsquare.gui.util.BSFormatter;
|
||||
import io.bitsquare.locale.Country;
|
||||
|
||||
import com.google.bitcoin.core.Coin;
|
||||
import com.google.bitcoin.core.NetworkParameters;
|
||||
import com.google.bitcoin.utils.Fiat;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
@ -36,15 +38,71 @@ import static org.junit.Assert.*;
|
||||
public class CreateOfferPMTest {
|
||||
private static final Logger log = LoggerFactory.getLogger(CreateOfferPMTest.class);
|
||||
|
||||
@Test
|
||||
public void testBindings() {
|
||||
CreateOfferModel model = new CreateOfferModel(null, null, null, null);
|
||||
private CreateOfferModel model;
|
||||
private CreateOfferPM presenter;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
model = new CreateOfferModel(null, null, null, null);
|
||||
|
||||
BSFormatter.setLocale(Locale.US);
|
||||
BSFormatter.setFiatCurrencyCode("USD");
|
||||
|
||||
CreateOfferPM presenter = new CreateOfferPM(model);
|
||||
presenter = new CreateOfferPM(model);
|
||||
presenter.onViewInitialized();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsBtcInputValid() {
|
||||
assertTrue(presenter.isBtcInputValid("1").isValid);
|
||||
assertTrue(presenter.isBtcInputValid("1,1").isValid);
|
||||
assertTrue(presenter.isBtcInputValid("1.1").isValid);
|
||||
assertTrue(presenter.isBtcInputValid(",1").isValid);
|
||||
assertTrue(presenter.isBtcInputValid(".1").isValid);
|
||||
assertTrue(presenter.isBtcInputValid("0.12345678").isValid);
|
||||
assertTrue(presenter.isBtcInputValid(Coin.SATOSHI.toPlainString()).isValid);
|
||||
assertTrue(presenter.isBtcInputValid(NetworkParameters.MAX_MONEY.toPlainString()).isValid);
|
||||
|
||||
assertFalse(presenter.isBtcInputValid(null).isValid);
|
||||
assertFalse(presenter.isBtcInputValid("").isValid);
|
||||
assertFalse(presenter.isBtcInputValid("0").isValid);
|
||||
assertFalse(presenter.isBtcInputValid("0.0").isValid);
|
||||
assertFalse(presenter.isBtcInputValid("0,1,1").isValid);
|
||||
assertFalse(presenter.isBtcInputValid("0.1.1").isValid);
|
||||
assertFalse(presenter.isBtcInputValid("1,000.1").isValid);
|
||||
assertFalse(presenter.isBtcInputValid("1.000,1").isValid);
|
||||
assertFalse(presenter.isBtcInputValid("0.123456789").isValid);
|
||||
assertFalse(presenter.isBtcInputValid("-1").isValid);
|
||||
assertFalse(presenter.isBtcInputValid(String.valueOf(NetworkParameters.MAX_MONEY.longValue() + Coin.SATOSHI
|
||||
.longValue())).isValid);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsFiatInputValid() {
|
||||
assertTrue(presenter.isFiatInputValid("1").isValid);
|
||||
assertTrue(presenter.isFiatInputValid("1,1").isValid);
|
||||
assertTrue(presenter.isFiatInputValid("1.1").isValid);
|
||||
assertTrue(presenter.isFiatInputValid(",1").isValid);
|
||||
assertTrue(presenter.isFiatInputValid(".1").isValid);
|
||||
assertTrue(presenter.isFiatInputValid("0.01").isValid);
|
||||
assertTrue(presenter.isFiatInputValid("1000000.00").isValid);
|
||||
|
||||
assertFalse(presenter.isFiatInputValid(null).isValid);
|
||||
assertFalse(presenter.isFiatInputValid("").isValid);
|
||||
assertFalse(presenter.isFiatInputValid("0").isValid);
|
||||
assertFalse(presenter.isFiatInputValid("-1").isValid);
|
||||
assertFalse(presenter.isFiatInputValid("0.0").isValid);
|
||||
assertFalse(presenter.isFiatInputValid("0,1,1").isValid);
|
||||
assertFalse(presenter.isFiatInputValid("0.1.1").isValid);
|
||||
assertFalse(presenter.isFiatInputValid("1,000.1").isValid);
|
||||
assertFalse(presenter.isFiatInputValid("1.000,1").isValid);
|
||||
assertFalse(presenter.isFiatInputValid("0.009").isValid);
|
||||
assertFalse(presenter.isFiatInputValid("1000000.01").isValid);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindings() {
|
||||
|
||||
|
||||
model.collateralAsLong.set(100);
|
||||
presenter.price.set("500");
|
||||
|
Loading…
Reference in New Issue
Block a user