Add spinner to create offer UI

This commit is contained in:
Manfred Karrer 2016-03-31 20:38:25 +02:00
parent 04845e4382
commit 9f42c5ac61
4 changed files with 279 additions and 202 deletions

View File

@ -92,9 +92,10 @@ class CreateOfferDataModel extends ActivatableDataModel {
final StringProperty btcCode = new SimpleStringProperty();
final BooleanProperty isWalletFunded = new SimpleBooleanProperty();
final BooleanProperty useMBTC = new SimpleBooleanProperty();
final BooleanProperty isMainNet = new SimpleBooleanProperty();
final BooleanProperty isFeeFromFundingTxSufficient = new SimpleBooleanProperty();
final ObjectProperty<Coin> feeFromFundingTxProperty = new SimpleObjectProperty(Coin.NEGATIVE_SATOSHI);
final ObjectProperty<Coin> amountAsCoin = new SimpleObjectProperty<>();
final ObjectProperty<Coin> minAmountAsCoin = new SimpleObjectProperty<>();
final ObjectProperty<Fiat> priceAsFiat = new SimpleObjectProperty<>();
@ -134,6 +135,8 @@ class CreateOfferDataModel extends ActivatableDataModel {
this.blockchainService = blockchainService;
this.formatter = formatter;
isMainNet.set(preferences.getBitcoinNetwork() == BitcoinNetwork.MAINNET);
offerId = UUID.randomUUID().toString();
addressEntry = walletService.getTradeAddressEntry(offerId);
offerFeeAsCoin = FeePolicy.getCreateOfferFee();

View File

@ -65,6 +65,8 @@ import net.glxn.qrgen.image.ImageType;
import org.bitcoinj.core.Coin;
import org.bitcoinj.uri.BitcoinURI;
import org.controlsfx.control.PopOver;
import org.fxmisc.easybind.EasyBind;
import org.fxmisc.easybind.Subscription;
import org.jetbrains.annotations.NotNull;
import javax.inject.Inject;
@ -87,12 +89,13 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
private AddressTextField addressTextField;
private BalanceTextField balanceTextField;
private TitledGroupBg payFundsPane;
private ProgressIndicator spinner;
private Button nextButton, cancelButton1, cancelButton2, fundFromSavingsWalletButton, fundFromExternalWalletButton, placeOfferButton;
private InputTextField amountTextField, minAmountTextField, priceTextField, volumeTextField;
private TextField currencyTextField;
private Label directionLabel, amountDescriptionLabel, addressLabel, balanceLabel, totalToPayLabel, totalToPayInfoIconLabel, amountBtcLabel, priceCurrencyLabel,
volumeCurrencyLabel, minAmountBtcLabel, priceDescriptionLabel, volumeDescriptionLabel, currencyTextFieldLabel,
currencyComboBoxLabel;
currencyComboBoxLabel, spinnerInfoLabel;
private TextFieldWithCopyIcon totalToPayTextField;
private ComboBox<PaymentAccount> paymentAccountsComboBox;
private ComboBox<TradeCurrency> currencyComboBox;
@ -119,6 +122,7 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
private ImageView qrCodeImageView;
private ChangeListener<Coin> balanceListener;
private HBox fundingHBox;
private Subscription isSpinnerVisibleSubscription;
///////////////////////////////////////////////////////////////////////////////////////////
@ -165,6 +169,10 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
protected void activate() {
addBindings();
addListeners();
addSubscriptions();
if (spinner != null && spinner.isVisible())
spinner.setProgress(-1);
directionLabel.setText(model.getDirectionLabel());
amountDescriptionLabel.setText(model.getAmountDescription());
@ -184,6 +192,11 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
protected void deactivate() {
removeBindings();
removeListeners();
removeSubscriptions();
if (spinner != null)
spinner.setProgress(0);
if (balanceTextField != null)
balanceTextField.cleanup();
}
@ -270,7 +283,7 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
paymentAccountsComboBox.setMouseTransparent(true);
balanceTextField.setTargetAmount(model.dataModel.totalToPayAsCoin.get());
if (!BitsquareApp.DEV_MODE) {
String key = "securityDepositInfo";
new Popup().backgroundInfo("To ensure that both traders follow the trade protocol they need to pay a security deposit.\n\n" +
@ -306,6 +319,8 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
cancelButton1.setManaged(false);
cancelButton1.setOnAction(null);
spinner.setProgress(-1);
payFundsPane.setVisible(true);
totalToPayLabel.setVisible(true);
totalToPayInfoIconLabel.setVisible(true);
@ -375,26 +390,18 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
// Bindings, Listeners
///////////////////////////////////////////////////////////////////////////////////////////
private void addBindings() {
amountBtcLabel.textProperty().bind(model.btcCode);
priceCurrencyLabel.textProperty().bind(createStringBinding(() ->
model.tradeCurrencyCode.get() + "/" + model.btcCode.get(), model.btcCode, model.tradeCurrencyCode));
priceCurrencyLabel.textProperty().bind(createStringBinding(() -> model.tradeCurrencyCode.get() + "/" + model.btcCode.get(), model.btcCode, model.tradeCurrencyCode));
volumeCurrencyLabel.textProperty().bind(model.tradeCurrencyCode);
minAmountBtcLabel.textProperty().bind(model.btcCode);
priceDescriptionLabel.textProperty().bind(createStringBinding(() ->
BSResources.get("createOffer.amountPriceBox.priceDescription", model.tradeCurrencyCode.get()), model.tradeCurrencyCode));
volumeDescriptionLabel.textProperty().bind(createStringBinding(model.volumeDescriptionLabel::get, model.tradeCurrencyCode, model
.volumeDescriptionLabel));
priceDescriptionLabel.textProperty().bind(createStringBinding(() -> BSResources.get("createOffer.amountPriceBox.priceDescription", model.tradeCurrencyCode.get()), model.tradeCurrencyCode));
volumeDescriptionLabel.textProperty().bind(createStringBinding(model.volumeDescriptionLabel::get, model.tradeCurrencyCode, model.volumeDescriptionLabel));
amountTextField.textProperty().bindBidirectional(model.amount);
minAmountTextField.textProperty().bindBidirectional(model.minAmount);
priceTextField.textProperty().bindBidirectional(model.price);
volumeTextField.textProperty().bindBidirectional(model.volume);
volumeTextField.promptTextProperty().bind(model.volumePromptLabel);
totalToPayTextField.textProperty().bind(model.totalToPay);
addressTextField.amountAsCoinProperty().bind(model.dataModel.missingCoin);
@ -404,10 +411,14 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
priceTextField.validationResultProperty().bind(model.priceValidationResult);
volumeTextField.validationResultProperty().bind(model.volumeValidationResult);
// buttons
// funding
fundingHBox.visibleProperty().bind(model.dataModel.isWalletFunded.not().and(model.showPayFundsScreenDisplayed));
fundingHBox.managedProperty().bind(model.dataModel.isWalletFunded.not().and(model.showPayFundsScreenDisplayed));
spinner.visibleProperty().bind(model.isSpinnerVisible);
spinner.managedProperty().bind(model.isSpinnerVisible);
spinnerInfoLabel.visibleProperty().bind(model.isSpinnerVisible);
spinnerInfoLabel.managedProperty().bind(model.isSpinnerVisible);
spinnerInfoLabel.textProperty().bind(model.spinnerInfoText);
placeOfferButton.visibleProperty().bind(model.dataModel.isWalletFunded.and(model.showPayFundsScreenDisplayed));
placeOfferButton.managedProperty().bind(model.dataModel.isWalletFunded.and(model.showPayFundsScreenDisplayed));
placeOfferButton.disableProperty().bind(model.isPlaceOfferButtonDisabled);
@ -435,27 +446,48 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
minAmountTextField.textProperty().unbindBidirectional(model.minAmount);
priceTextField.textProperty().unbindBidirectional(model.price);
volumeTextField.textProperty().unbindBidirectional(model.volume);
volumeTextField.promptTextProperty().unbindBidirectional(model.volume);
totalToPayTextField.textProperty().unbind();
addressTextField.amountAsCoinProperty().unbind();
// Validation
amountTextField.validationResultProperty().unbind();
minAmountTextField.validationResultProperty().unbind();
priceTextField.validationResultProperty().unbind();
volumeTextField.validationResultProperty().unbind();
// funding
fundingHBox.visibleProperty().unbind();
fundingHBox.managedProperty().unbind();
spinner.visibleProperty().unbind();
spinner.managedProperty().unbind();
spinnerInfoLabel.visibleProperty().unbind();
spinnerInfoLabel.managedProperty().unbind();
spinnerInfoLabel.textProperty().unbind();
placeOfferButton.visibleProperty().unbind();
placeOfferButton.managedProperty().unbind();
placeOfferButton.disableProperty().unbind();
cancelButton2.disableProperty().unbind();
// payment account
currencyComboBox.managedProperty().unbind();
currencyComboBox.prefWidthProperty().unbind();
currencyComboBoxLabel.visibleProperty().unbind();
currencyComboBoxLabel.managedProperty().unbind();
currencyTextField.visibleProperty().unbind();
currencyTextField.managedProperty().unbind();
currencyTextFieldLabel.visibleProperty().unbind();
currencyTextFieldLabel.managedProperty().unbind();
currencyComboBox.prefWidthProperty().unbind();
volumeTextField.promptTextProperty().unbind();
}
private void addSubscriptions() {
isSpinnerVisibleSubscription = EasyBind.subscribe(model.isSpinnerVisible,
isSpinnerVisible -> spinner.setProgress(isSpinnerVisible ? -1 : 0));
}
private void removeSubscriptions() {
isSpinnerVisibleSubscription.unsubscribe();
}
private void createListeners() {
@ -787,7 +819,13 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
"Perhaps you don't have one installed?").show();
}
});
fundingHBox.getChildren().addAll(fundFromSavingsWalletButton, label, fundFromExternalWalletButton);
spinner = new ProgressIndicator(0);
spinner.setPrefHeight(18);
spinner.setPrefWidth(18);
spinnerInfoLabel = new Label();
spinnerInfoLabel.setPadding(new Insets(5, 0, 0, 0));
fundingHBox.getChildren().addAll(fundFromSavingsWalletButton, label, fundFromExternalWalletButton, spinner, spinnerInfoLabel);
GridPane.setRowIndex(fundingHBox, ++gridRow);
GridPane.setColumnIndex(fundingHBox, 1);
GridPane.setMargin(fundingHBox, new Insets(15, 10, 0, 0));

View File

@ -78,6 +78,7 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
final StringProperty errorMessage = new SimpleStringProperty();
final StringProperty btcCode = new SimpleStringProperty();
final StringProperty tradeCurrencyCode = new SimpleStringProperty();
final StringProperty spinnerInfoText = new SimpleStringProperty("");
final BooleanProperty isPlaceOfferButtonDisabled = new SimpleBooleanProperty(true);
final BooleanProperty cancelButtonDisabled = new SimpleBooleanProperty();
@ -87,6 +88,8 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
final BooleanProperty showWarningInvalidBtcDecimalPlaces = new SimpleBooleanProperty();
final BooleanProperty placeOfferCompleted = new SimpleBooleanProperty();
final BooleanProperty showPayFundsScreenDisplayed = new SimpleBooleanProperty();
final BooleanProperty showTransactionPublishedScreen = new SimpleBooleanProperty();
final BooleanProperty isSpinnerVisible = new SimpleBooleanProperty();
final ObjectProperty<InputValidator.ValidationResult> amountValidationResult = new SimpleObjectProperty<>();
final ObjectProperty<InputValidator.ValidationResult> minAmountValidationResult = new
@ -151,8 +154,10 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
setMinAmountToModel();
setPriceToModel();
calculateVolume();
dataModel.calculateTotalToPay();
updateButtonDisableState();
updateSpinnerInfo();
}
addBindings();
@ -345,6 +350,8 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
placeOfferCompleted.set(true);
errorMessage.set(null);
});
updateSpinnerInfo();
}
private void stopTimeoutTimer() {
@ -392,6 +399,7 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
void onShowPayFundsScreen() {
showPayFundsScreenDisplayed.set(true);
updateSpinnerInfo();
}
boolean useSavingsWalletForFunding() {
@ -626,6 +634,24 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
return fiatValidator.validate(input);
}
private void updateSpinnerInfo() {
if (!showPayFundsScreenDisplayed.get() ||
errorMessage.get() != null ||
showTransactionPublishedScreen.get()) {
spinnerInfoText.set("");
} else if (dataModel.isWalletFunded.get()) {
if (dataModel.isFeeFromFundingTxSufficient.get()) {
spinnerInfoText.set("");
} else {
spinnerInfoText.set("Check if funding tx miner fee is sufficient...");
}
} else {
spinnerInfoText.set("Waiting for funds...");
}
isSpinnerVisible.set(!spinnerInfoText.get().isEmpty());
}
private void updateButtonDisableState() {
log.debug("updateButtonDisableState");
boolean inputDataValid = isBtcInputValid(amount.get()).isValid &&

View File

@ -149,204 +149,43 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
};
}
@Override
protected void activate() {
paymentAccountsComboBox.setOnAction(e -> onPaymentAccountsComboBoxSelected());
addBindings();
addSubscriptions();
amountTextField.focusedProperty().addListener(amountFocusedListener);
amountBtcLabel.textProperty().bind(model.btcCode);
amountTextField.textProperty().bindBidirectional(model.amount);
volumeTextField.textProperty().bindBidirectional(model.volume);
totalToPayTextField.textProperty().bind(model.totalToPay);
addressTextField.amountAsCoinProperty().bind(model.dataModel.missingCoin);
amountTextField.validationResultProperty().bind(model.amountValidationResult);
takeOfferButton.disableProperty().bind(model.isTakeOfferButtonDisabled);
takeOfferButton.visibleProperty().bind(model.dataModel.isWalletFunded.and(model.showPayFundsScreenDisplayed));
takeOfferButton.managedProperty().bind(model.dataModel.isWalletFunded.and(model.showPayFundsScreenDisplayed));
fundingHBox.visibleProperty().bind(model.dataModel.isWalletFunded.not().and(model.showPayFundsScreenDisplayed));
fundingHBox.managedProperty().bind(model.dataModel.isWalletFunded.not().and(model.showPayFundsScreenDisplayed));
spinner.visibleProperty().bind(model.isSpinnerVisible);
spinner.managedProperty().bind(model.isSpinnerVisible);
spinnerInfoLabel.visibleProperty().bind(model.isSpinnerVisible);
spinnerInfoLabel.managedProperty().bind(model.isSpinnerVisible);
spinnerInfoLabel.textProperty().bind(model.spinnerInfoText);
priceCurrencyLabel.textProperty().bind(createStringBinding(() ->
model.dataModel.getCurrencyCode() + "/" + model.btcCode.get(), model.btcCode));
volumeCurrencyLabel.setText(model.dataModel.getCurrencyCode());
amountRangeBtcLabel.textProperty().bind(model.btcCode);
priceDescriptionLabel.setText(BSResources.get("createOffer.amountPriceBox.priceDescription", model.dataModel.getCurrencyCode()));
volumeDescriptionLabel.setText(model.volumeDescriptionLabel.get());
errorPopupDisplayed = new SimpleBooleanProperty();
offerWarningSubscription = EasyBind.subscribe(model.offerWarning, newValue -> {
if (newValue != null) {
if (offerDetailsWindowDisplayed)
offerDetailsWindow.hide();
UserThread.runAfter(() -> new Popup().warning(newValue + "\n\n" +
"If you have already paid in funds you can withdraw it in the " +
"\"Funds/Available for withdrawal\" screen.")
.actionButtonText("Go to \"Available for withdrawal\"")
.onAction(() -> {
errorPopupDisplayed.set(true);
model.resetOfferWarning();
close();
navigation.navigateTo(MainView.class, FundsView.class, WithdrawalView.class);
})
.onClose(() -> {
errorPopupDisplayed.set(true);
model.resetOfferWarning();
close();
})
.show(), 100, TimeUnit.MILLISECONDS);
}
});
errorMessageSubscription = EasyBind.subscribe(model.errorMessage, newValue -> {
if (newValue != null) {
new Popup().error(BSResources.get("takeOffer.error.message", model.errorMessage.get()) +
"Please try to restart you application and check your network connection to see if you can resolve the issue.")
.onClose(() -> {
errorPopupDisplayed.set(true);
model.resetErrorMessage();
close();
})
.show();
}
});
isOfferAvailableSubscription = EasyBind.subscribe(model.isOfferAvailable, newValue -> {
if (newValue) {
offerAvailabilitySpinner.setProgress(0);
offerAvailabilitySpinner.setVisible(false);
offerAvailabilitySpinnerLabel.setVisible(false);
}
});
isSpinnerVisibleSubscription = EasyBind.subscribe(model.isSpinnerVisible,
isSpinnerVisible -> spinner.setProgress(isSpinnerVisible ? -1 : 0));
showWarningInvalidBtcDecimalPlacesSubscription = EasyBind.subscribe(model.showWarningInvalidBtcDecimalPlaces, newValue -> {
if (newValue) {
new Popup().warning(BSResources.get("takeOffer.amountPriceBox.warning.invalidBtcDecimalPlaces")).show();
model.showWarningInvalidBtcDecimalPlaces.set(false);
}
});
showTransactionPublishedScreenSubscription = EasyBind.subscribe(model.showTransactionPublishedScreen, newValue -> {
if (newValue && BitsquareApp.DEV_MODE) {
close();
navigation.navigateTo(MainView.class, PortfolioView.class, PendingTradesView.class);
} else if (newValue && model.getTrade() != null && model.getTrade().errorMessageProperty().get() == null) {
String key = "takeOfferSuccessInfo";
if (preferences.showAgain(key)) {
UserThread.runAfter(() -> new Popup().headLine(BSResources.get("takeOffer.success.headline"))
.feedback(BSResources.get("takeOffer.success.info"))
.actionButtonText("Go to \"Open trades\"")
.dontShowAgainId(key, preferences)
.onAction(() -> {
UserThread.runAfter(
() -> navigation.navigateTo(MainView.class, PortfolioView.class, PendingTradesView.class)
, 100, TimeUnit.MILLISECONDS);
close();
})
.onClose(this::close)
.show(), 1);
} else {
close();
}
}
});
if (model.getPossiblePaymentAccounts().size() > 1) {
paymentAccountsComboBox.setItems(model.getPossiblePaymentAccounts());
paymentAccountsComboBox.getSelectionModel().select(0);
}
noSufficientFeeBinding = EasyBind.combine(model.dataModel.isWalletFunded, model.dataModel.isMainNet, model.dataModel.isFeeFromFundingTxSufficient,
(isWalletFunded, isMainNet, isFeeSufficient) -> isWalletFunded && isMainNet && !isFeeSufficient);
noSufficientFeeSubscription = noSufficientFeeBinding.subscribe((observable, oldValue, newValue) -> {
if (newValue)
new Popup().warning("The mining fee from your funding transaction is not sufficiently high.\n\n" +
"You need to use at least a mining fee of " +
model.formatter.formatCoinWithCode(FeePolicy.getMinRequiredFeeForFundingTx()) + ".\n\n" +
"The fee used in your funding transaction was only " +
model.formatter.formatCoinWithCode(model.dataModel.feeFromFundingTx) + ".\n\n" +
"The trade transactions might take too much time to be included in " +
"a block if the fee is too low.\n" +
"Please check at your external wallet that you set the required fee and " +
"do a funding again with the correct fee.\n\n" +
"In the \"Funds/Open for withdrawal\" section you can withdraw those funds.")
.closeButtonText("Close")
.onClose(() -> {
close();
navigation.navigateTo(MainView.class, FundsView.class, WithdrawalView.class);
})
.show();
});
if (offerAvailabilitySpinner != null && offerAvailabilitySpinner.isVisible())
offerAvailabilitySpinner.setProgress(-1);
if (spinner != null && spinner.isVisible())
spinner.setProgress(-1);
balanceSubscription = EasyBind.subscribe(model.dataModel.balance, newValue -> balanceTextField.setBalance(newValue));
totalToPaySubscription = EasyBind.subscribe(model.dataModel.totalToPayAsCoin, newValue -> balanceTextField.setTargetAmount(newValue));
volumeCurrencyLabel.setText(model.dataModel.getCurrencyCode());
priceDescriptionLabel.setText(BSResources.get("createOffer.amountPriceBox.priceDescription", model.dataModel.getCurrencyCode()));
volumeDescriptionLabel.setText(model.volumeDescriptionLabel.get());
if (model.getPossiblePaymentAccounts().size() > 1) {
paymentAccountsComboBox.setItems(model.getPossiblePaymentAccounts());
paymentAccountsComboBox.getSelectionModel().select(0);
}
}
@Override
protected void deactivate() {
paymentAccountsComboBox.setOnAction(null);
removeBindings();
removeSubscriptions();
amountTextField.focusedProperty().removeListener(amountFocusedListener);
amountBtcLabel.textProperty().unbind();
amountTextField.textProperty().unbindBidirectional(model.amount);
volumeTextField.textProperty().unbindBidirectional(model.volume);
totalToPayTextField.textProperty().unbind();
addressTextField.amountAsCoinProperty().unbind();
amountTextField.validationResultProperty().unbind();
priceCurrencyLabel.textProperty().unbind();
volumeCurrencyLabel.textProperty().unbind();
amountRangeBtcLabel.textProperty().unbind();
priceDescriptionLabel.textProperty().unbind();
volumeDescriptionLabel.textProperty().unbind();
fundingHBox.visibleProperty().unbind();
fundingHBox.managedProperty().unbind();
takeOfferButton.visibleProperty().unbind();
takeOfferButton.managedProperty().unbind();
takeOfferButton.disableProperty().unbind();
spinner.visibleProperty().unbind();
spinner.managedProperty().unbind();
spinnerInfoLabel.visibleProperty().unbind();
spinnerInfoLabel.managedProperty().unbind();
spinnerInfoLabel.textProperty().unbind();
offerWarningSubscription.unsubscribe();
errorMessageSubscription.unsubscribe();
isOfferAvailableSubscription.unsubscribe();
isSpinnerVisibleSubscription.unsubscribe();
showWarningInvalidBtcDecimalPlacesSubscription.unsubscribe();
showTransactionPublishedScreenSubscription.unsubscribe();
noSufficientFeeSubscription.unsubscribe();
if (balanceTextField != null)
balanceTextField.cleanup();
if (offerAvailabilitySpinner != null)
offerAvailabilitySpinner.setProgress(0);
if (spinner != null)
spinner.setProgress(0);
balanceSubscription.unsubscribe();
totalToPaySubscription.unsubscribe();
if (balanceTextField != null)
balanceTextField.cleanup();
}
@ -444,10 +283,6 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
}
}
private void onPaymentAccountsComboBoxSelected() {
model.onPaymentAccountSelected(paymentAccountsComboBox.getSelectionModel().getSelectedItem());
}
private void onShowPayFundsScreen() {
model.onShowPayFundsScreen();
@ -537,7 +372,180 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
closeHandler.close();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Bindings, Listeners
///////////////////////////////////////////////////////////////////////////////////////////
private void addBindings() {
amountBtcLabel.textProperty().bind(model.btcCode);
amountTextField.textProperty().bindBidirectional(model.amount);
volumeTextField.textProperty().bindBidirectional(model.volume);
totalToPayTextField.textProperty().bind(model.totalToPay);
addressTextField.amountAsCoinProperty().bind(model.dataModel.missingCoin);
amountTextField.validationResultProperty().bind(model.amountValidationResult);
priceCurrencyLabel.textProperty().bind(createStringBinding(() -> model.dataModel.getCurrencyCode() + "/" + model.btcCode.get(), model.btcCode));
amountRangeBtcLabel.textProperty().bind(model.btcCode);
nextButton.disableProperty().bind(model.isNextButtonDisabled);
// funding
fundingHBox.visibleProperty().bind(model.dataModel.isWalletFunded.not().and(model.showPayFundsScreenDisplayed));
fundingHBox.managedProperty().bind(model.dataModel.isWalletFunded.not().and(model.showPayFundsScreenDisplayed));
spinner.visibleProperty().bind(model.isSpinnerVisible);
spinner.managedProperty().bind(model.isSpinnerVisible);
spinnerInfoLabel.visibleProperty().bind(model.isSpinnerVisible);
spinnerInfoLabel.managedProperty().bind(model.isSpinnerVisible);
spinnerInfoLabel.textProperty().bind(model.spinnerInfoText);
takeOfferButton.disableProperty().bind(model.isTakeOfferButtonDisabled);
takeOfferButton.visibleProperty().bind(model.dataModel.isWalletFunded.and(model.showPayFundsScreenDisplayed));
takeOfferButton.managedProperty().bind(model.dataModel.isWalletFunded.and(model.showPayFundsScreenDisplayed));
}
private void removeBindings() {
amountBtcLabel.textProperty().unbind();
amountTextField.textProperty().unbindBidirectional(model.amount);
volumeTextField.textProperty().unbindBidirectional(model.volume);
totalToPayTextField.textProperty().unbind();
addressTextField.amountAsCoinProperty().unbind();
amountTextField.validationResultProperty().unbind();
priceCurrencyLabel.textProperty().unbind();
amountRangeBtcLabel.textProperty().unbind();
nextButton.disableProperty().unbind();
// funding
fundingHBox.visibleProperty().unbind();
fundingHBox.managedProperty().unbind();
spinner.visibleProperty().unbind();
spinner.managedProperty().unbind();
spinnerInfoLabel.visibleProperty().unbind();
spinnerInfoLabel.managedProperty().unbind();
spinnerInfoLabel.textProperty().unbind();
takeOfferButton.visibleProperty().unbind();
takeOfferButton.managedProperty().unbind();
takeOfferButton.disableProperty().unbind();
}
private void addSubscriptions() {
errorPopupDisplayed = new SimpleBooleanProperty();
offerWarningSubscription = EasyBind.subscribe(model.offerWarning, newValue -> {
if (newValue != null) {
if (offerDetailsWindowDisplayed)
offerDetailsWindow.hide();
UserThread.runAfter(() -> new Popup().warning(newValue + "\n\n" +
"If you have already paid in funds you can withdraw it in the " +
"\"Funds/Available for withdrawal\" screen.")
.actionButtonText("Go to \"Available for withdrawal\"")
.onAction(() -> {
errorPopupDisplayed.set(true);
model.resetOfferWarning();
close();
navigation.navigateTo(MainView.class, FundsView.class, WithdrawalView.class);
})
.onClose(() -> {
errorPopupDisplayed.set(true);
model.resetOfferWarning();
close();
})
.show(), 100, TimeUnit.MILLISECONDS);
}
});
errorMessageSubscription = EasyBind.subscribe(model.errorMessage, newValue -> {
if (newValue != null) {
new Popup().error(BSResources.get("takeOffer.error.message", model.errorMessage.get()) +
"Please try to restart you application and check your network connection to see if you can resolve the issue.")
.onClose(() -> {
errorPopupDisplayed.set(true);
model.resetErrorMessage();
close();
})
.show();
}
});
isOfferAvailableSubscription = EasyBind.subscribe(model.isOfferAvailable, newValue -> {
if (newValue) {
offerAvailabilitySpinner.setProgress(0);
offerAvailabilitySpinner.setVisible(false);
offerAvailabilitySpinnerLabel.setVisible(false);
}
});
isSpinnerVisibleSubscription = EasyBind.subscribe(model.isSpinnerVisible,
isSpinnerVisible -> spinner.setProgress(isSpinnerVisible ? -1 : 0));
showWarningInvalidBtcDecimalPlacesSubscription = EasyBind.subscribe(model.showWarningInvalidBtcDecimalPlaces, newValue -> {
if (newValue) {
new Popup().warning(BSResources.get("takeOffer.amountPriceBox.warning.invalidBtcDecimalPlaces")).show();
model.showWarningInvalidBtcDecimalPlaces.set(false);
}
});
showTransactionPublishedScreenSubscription = EasyBind.subscribe(model.showTransactionPublishedScreen, newValue -> {
if (newValue && BitsquareApp.DEV_MODE) {
close();
navigation.navigateTo(MainView.class, PortfolioView.class, PendingTradesView.class);
} else if (newValue && model.getTrade() != null && model.getTrade().errorMessageProperty().get() == null) {
String key = "takeOfferSuccessInfo";
if (preferences.showAgain(key)) {
UserThread.runAfter(() -> new Popup().headLine(BSResources.get("takeOffer.success.headline"))
.feedback(BSResources.get("takeOffer.success.info"))
.actionButtonText("Go to \"Open trades\"")
.dontShowAgainId(key, preferences)
.onAction(() -> {
UserThread.runAfter(
() -> navigation.navigateTo(MainView.class, PortfolioView.class, PendingTradesView.class)
, 100, TimeUnit.MILLISECONDS);
close();
})
.onClose(this::close)
.show(), 1);
} else {
close();
}
}
});
noSufficientFeeBinding = EasyBind.combine(model.dataModel.isWalletFunded, model.dataModel.isMainNet, model.dataModel.isFeeFromFundingTxSufficient,
(isWalletFunded, isMainNet, isFeeSufficient) -> isWalletFunded && isMainNet && !isFeeSufficient);
noSufficientFeeSubscription = noSufficientFeeBinding.subscribe((observable, oldValue, newValue) -> {
if (newValue)
new Popup().warning("The mining fee from your funding transaction is not sufficiently high.\n\n" +
"You need to use at least a mining fee of " +
model.formatter.formatCoinWithCode(FeePolicy.getMinRequiredFeeForFundingTx()) + ".\n\n" +
"The fee used in your funding transaction was only " +
model.formatter.formatCoinWithCode(model.dataModel.feeFromFundingTx) + ".\n\n" +
"The trade transactions might take too much time to be included in " +
"a block if the fee is too low.\n" +
"Please check at your external wallet that you set the required fee and " +
"do a funding again with the correct fee.\n\n" +
"In the \"Funds/Open for withdrawal\" section you can withdraw those funds.")
.closeButtonText("Close")
.onClose(() -> {
close();
navigation.navigateTo(MainView.class, FundsView.class, WithdrawalView.class);
})
.show();
});
balanceSubscription = EasyBind.subscribe(model.dataModel.balance, newValue -> balanceTextField.setBalance(newValue));
totalToPaySubscription = EasyBind.subscribe(model.dataModel.totalToPayAsCoin, newValue -> balanceTextField.setTargetAmount(newValue));
}
private void removeSubscriptions() {
offerWarningSubscription.unsubscribe();
errorMessageSubscription.unsubscribe();
isOfferAvailableSubscription.unsubscribe();
isSpinnerVisibleSubscription.unsubscribe();
showWarningInvalidBtcDecimalPlacesSubscription.unsubscribe();
showTransactionPublishedScreenSubscription.unsubscribe();
noSufficientFeeSubscription.unsubscribe();
balanceSubscription.unsubscribe();
totalToPaySubscription.unsubscribe();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Build UI elements
///////////////////////////////////////////////////////////////////////////////////////////
@ -597,6 +605,8 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
});
paymentAccountsComboBox.setVisible(false);
paymentAccountsComboBox.setManaged(false);
paymentAccountsComboBox.setOnAction(e -> model.onPaymentAccountSelected(paymentAccountsComboBox.getSelectionModel().getSelectedItem()));
Tuple2<Label, TextField> tuple2 = addLabelTextField(gridPane, gridRow, "Payment method:", "", Layout.FIRST_ROW_DISTANCE);
paymentMethodLabel = tuple2.first;
paymentMethodTextField = tuple2.second;
@ -630,14 +640,14 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
nextButton = new Button(BSResources.get("takeOffer.amountPriceBox.next"));
nextButton.setDefaultButton(true);
nextButton.disableProperty().bind(model.isNextButtonDisabled);
nextButton.setOnAction(e -> onShowPayFundsScreen());
//UserThread.runAfter(() -> nextButton.requestFocus(), 100, TimeUnit.MILLISECONDS);
cancelButton1 = new Button(BSResources.get("shared.cancel"));
cancelButton1.setOnAction(e -> close());
cancelButton1.setDefaultButton(false);
cancelButton1.setId("cancel-button");
cancelButton1.setOnAction(e -> close());
offerAvailabilitySpinner = new ProgressIndicator(0);
offerAvailabilitySpinner.setPrefSize(18, 18);