diff --git a/gui/src/main/java/io/bitsquare/app/BitsquareApp.java b/gui/src/main/java/io/bitsquare/app/BitsquareApp.java index 6267476110..7b275318b9 100644 --- a/gui/src/main/java/io/bitsquare/app/BitsquareApp.java +++ b/gui/src/main/java/io/bitsquare/app/BitsquareApp.java @@ -61,14 +61,12 @@ import org.bitcoinj.store.BlockStoreException; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.controlsfx.dialog.Dialogs; import org.reactfx.EventStreams; -import org.reactfx.util.FxTimer; import org.slf4j.LoggerFactory; import org.springframework.core.env.Environment; import java.io.IOException; import java.nio.file.Paths; import java.security.Security; -import java.time.Duration; import java.util.ArrayList; import java.util.List; @@ -333,9 +331,9 @@ public class BitsquareApp extends Application { }); }); // we wait max 5 sec. - FxTimer.runLater(Duration.ofMillis(5000), resultHandler::handleResult); + UserThread.runAfter(resultHandler::handleResult, 5); } else { - FxTimer.runLater(Duration.ofMillis(500), resultHandler::handleResult); + UserThread.runAfter(resultHandler::handleResult, 1); } } catch (Throwable t) { log.info("App shutdown failed with exception"); diff --git a/gui/src/main/java/io/bitsquare/gui/main/disputes/trader/TraderDisputeView.java b/gui/src/main/java/io/bitsquare/gui/main/disputes/trader/TraderDisputeView.java index a756638ac2..00989ff6aa 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/disputes/trader/TraderDisputeView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/disputes/trader/TraderDisputeView.java @@ -55,8 +55,6 @@ import javafx.scene.text.TextAlignment; import javafx.stage.FileChooser; import javafx.stage.Stage; import javafx.util.Callback; -import org.reactfx.util.FxTimer; -import org.reactfx.util.Timer; import javax.annotation.Nullable; import javax.inject.Inject; @@ -66,10 +64,10 @@ import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; -import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.concurrent.TimeUnit; // will be probably only used for arbitration communication, will be renamed and the icon changed @FxmlView @@ -214,7 +212,7 @@ public class TraderDisputeView extends ActivatableView { inputTextArea.setDisable(true); inputTextArea.clear(); - final Timer timer = FxTimer.runLater(Duration.ofMillis(500), () -> { + io.bitsquare.common.Timer timer = UserThread.runAfter(() -> { sendMsgInfoLabel.setVisible(true); sendMsgInfoLabel.setManaged(true); sendMsgInfoLabel.setText("Sending Message..."); @@ -222,7 +220,7 @@ public class TraderDisputeView extends ActivatableView { sendMsgProgressIndicator.setProgress(-1); sendMsgProgressIndicator.setVisible(true); sendMsgProgressIndicator.setManaged(true); - }); + }, 500, TimeUnit.MILLISECONDS); arrivedPropertyListener = (observable, oldValue, newValue) -> { if (newValue) { @@ -242,14 +240,14 @@ public class TraderDisputeView extends ActivatableView { disputeCommunicationMessage.storedInMailboxProperty().addListener(storedInMailboxPropertyListener); } - private void hideSendMsgInfo(Timer timer) { + private void hideSendMsgInfo(io.bitsquare.common.Timer timer) { timer.stop(); inputTextArea.setDisable(false); - FxTimer.runLater(Duration.ofMillis(5000), () -> { + UserThread.runAfter(() -> { sendMsgInfoLabel.setVisible(false); sendMsgInfoLabel.setManaged(false); - }); + }, 5); sendMsgProgressIndicator.setProgress(0); sendMsgProgressIndicator.setVisible(false); sendMsgProgressIndicator.setManaged(false); diff --git a/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferView.java b/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferView.java index f04cd1ea37..44561a562c 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferView.java @@ -21,6 +21,7 @@ import de.jensd.fx.fontawesome.AwesomeDude; import de.jensd.fx.fontawesome.AwesomeIcon; import io.bitsquare.app.BitsquareApp; import io.bitsquare.btc.FeePolicy; +import io.bitsquare.common.UserThread; import io.bitsquare.common.util.Tuple2; import io.bitsquare.common.util.Tuple3; import io.bitsquare.common.util.Utilities; @@ -62,10 +63,9 @@ import javafx.stage.Window; import javafx.util.StringConverter; import org.bitcoinj.core.Coin; import org.controlsfx.control.PopOver; -import org.reactfx.util.FxTimer; import javax.inject.Inject; -import java.time.Duration; +import java.util.concurrent.TimeUnit; import static io.bitsquare.gui.util.FormBuilder.*; import static javafx.beans.binding.Bindings.createStringBinding; @@ -81,17 +81,16 @@ public class CreateOfferView extends ActivatableViewAndModel paymentAccountsComboBox; private ComboBox currencyComboBox; - private PopOver totalToPayInfoPopover; private OfferView.CloseHandler closeHandler; @@ -104,8 +103,8 @@ public class CreateOfferView extends ActivatableViewAndModel showWarningInvalidFiatDecimalPlacesPlacesListener; private ChangeListener showWarningAdjustedVolumeListener; private ChangeListener errorMessageListener; - private ChangeListener isPlaceOfferSpinnerVisibleListener; - private ChangeListener showTransactionPublishedScreen; + private ChangeListener isSpinnerVisibleListener; + private ChangeListener placeOfferCompletedListener; private ChangeListener feeFromFundingTxListener; private EventHandler paymentAccountsComboBoxSelectionHandler; @@ -175,6 +174,9 @@ public class CreateOfferView extends ActivatableViewAndModel + model.onPlaceOffer(offer, () -> + offerDetailsWindow.hide())) .show(offer); } else { new Popup().warning("You have no arbitrator selected.\n" + @@ -253,6 +257,9 @@ public class CreateOfferView extends ActivatableViewAndModel { if (newValue != null) - new Popup().error(BSResources.get("createOffer.amountPriceBox.error.message", model.errorMessage.get()) + + UserThread.runAfter(() -> new Popup().error(BSResources.get("createOffer.amountPriceBox.error.message", model.errorMessage.get()) + "\n\nThere have no funds left your wallet yet.\n" + "Please try to restart you application and check your network connection to see if you can resolve the issue.") - .show(); + .show(), 100, TimeUnit.MILLISECONDS); }; - isPlaceOfferSpinnerVisibleListener = (ov, oldValue, newValue) -> { - placeOfferSpinner.setProgress(newValue ? -1 : 0); - placeOfferSpinner.setVisible(newValue); + isSpinnerVisibleListener = (ov, oldValue, newValue) -> { + spinner.setProgress(newValue ? -1 : 0); + spinner.setVisible(newValue); }; feeFromFundingTxListener = (observable, oldValue, newValue) -> { @@ -503,29 +511,25 @@ public class CreateOfferView extends ActivatableViewAndModel { + placeOfferCompletedListener = (o, oldValue, newValue) -> { if (BitsquareApp.DEV_MODE) { - newValue = false; close(); navigation.navigateTo(MainView.class, PortfolioView.class, OpenOffersView.class); - } - - if (newValue) { - FxTimer.runLater(Duration.ofMillis(100), - () -> { - new Popup().headLine(BSResources.get("createOffer.success.headline")) - .feedback(BSResources.get("createOffer.success.info")) - .actionButtonText("Go to \"My open offers\"") - .onAction(() -> { - close(); - FxTimer.runLater(Duration.ofMillis(100), - () -> navigation.navigateTo(MainView.class, PortfolioView.class, OpenOffersView.class) - ); - }) - .onClose(() -> close()) - .show(); - } - ); + } else if (newValue) { + // We need a bit of delay to avoid issues with fade out/fade in of 2 popups + UserThread.runAfter(() -> + new Popup().headLine(BSResources.get("createOffer.success.headline")) + .feedback(BSResources.get("createOffer.success.info")) + .actionButtonText("Go to \"My open offers\"") + .onAction(() -> { + close(); + UserThread.runAfter(() -> + navigation.navigateTo(MainView.class, PortfolioView.class, OpenOffersView.class), + 100, TimeUnit.MILLISECONDS); + }) + .onClose(this::close) + .show(), + 100, TimeUnit.MILLISECONDS); } }; } @@ -544,10 +548,10 @@ public class CreateOfferView extends ActivatableViewAndModel placeOfferTuple = addButtonWithStatusAfterGroup(gridPane, ++gridRow, ""); - createOfferButton = placeOfferTuple.first; - createOfferButton.setVisible(false); - createOfferButton.setOnAction(e -> onPlaceOffer()); - createOfferButton.setMinHeight(40); - createOfferButton.setPadding(new Insets(0, 20, 0, 20)); + placeOfferButton = placeOfferTuple.first; + placeOfferButton.setVisible(false); + placeOfferButton.setOnAction(e -> onPlaceOffer()); + placeOfferButton.setMinHeight(40); + placeOfferButton.setPadding(new Insets(0, 20, 0, 20)); - placeOfferSpinner = placeOfferTuple.second; - placeOfferSpinner.setPrefSize(18, 18); - placeOfferSpinnerInfoLabel = placeOfferTuple.third; - placeOfferSpinnerInfoLabel.textProperty().bind(model.placeOfferSpinnerInfoText); - placeOfferSpinnerInfoLabel.setVisible(false); + spinner = placeOfferTuple.second; + spinner.setProgress(0); + spinner.setVisible(false); + spinner.setPrefSize(18, 18); + spinnerInfoLabel = placeOfferTuple.third; + spinnerInfoLabel.textProperty().bind(model.spinnerInfoText); + spinnerInfoLabel.setVisible(false); cancelButton2 = addButton(gridPane, ++gridRow, BSResources.get("shared.cancel")); cancelButton2.setOnAction(e -> close()); diff --git a/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferViewModel.java b/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferViewModel.java index 5a7f53bf5c..7efac69fd2 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferViewModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferViewModel.java @@ -18,6 +18,9 @@ package io.bitsquare.gui.main.offer.createoffer; import io.bitsquare.app.BitsquareApp; +import io.bitsquare.btc.FeePolicy; +import io.bitsquare.common.Timer; +import io.bitsquare.common.UserThread; import io.bitsquare.gui.common.model.ActivatableWithDataModel; import io.bitsquare.gui.common.model.ViewModel; import io.bitsquare.gui.util.BSFormatter; @@ -62,15 +65,16 @@ class CreateOfferViewModel extends ActivatableWithDataModel amountValidationResult = new SimpleObjectProperty<>(); final ObjectProperty minAmountValidationResult = new @@ -92,10 +96,10 @@ class CreateOfferViewModel extends ActivatableWithDataModel volumeAsFiatListener; private ChangeListener isWalletFundedListener; private ChangeListener feeFromFundingTxListener; - private ChangeListener requestPlaceOfferSuccessListener; private ChangeListener requestPlaceOfferErrorMessageListener; private ChangeListener errorMessageListener; private Offer offer; + private Timer timeoutTimer; /////////////////////////////////////////////////////////////////////////////////////////// @@ -156,6 +160,7 @@ class CreateOfferViewModel extends ActivatableWithDataModel { updateButtonDisableState(); - isPlaceOfferSpinnerVisible.set(true); - placeOfferSpinnerInfoText.set("Checking funding tx miner fee..."); + spinnerInfoText.set("Checking funding tx miner fee..."); }; feeFromFundingTxListener = (ov, oldValue, newValue) -> { updateButtonDisableState(); - if (newValue.isPositive()) { - isPlaceOfferSpinnerVisible.set(false); - placeOfferSpinnerInfoText.set(""); - } - }; - requestPlaceOfferSuccessListener = (ov, oldValue, newValue) -> { - if (newValue) { - isPlaceOfferButtonDisabled.set(newValue); - isPlaceOfferSpinnerVisible.set(false); - placeOfferSpinnerInfoText.set(""); + if (newValue.compareTo(FeePolicy.getMinRequiredFeeForFundingTx()) >= 0) { + isSpinnerVisible.set(false); + spinnerInfoText.set(""); } }; requestPlaceOfferErrorMessageListener = (ov, oldValue, newValue) -> { if (newValue != null) { - isPlaceOfferSpinnerVisible.set(false); - placeOfferSpinnerInfoText.set(""); + isSpinnerVisible.set(false); + spinnerInfoText.set(""); } }; } @@ -273,7 +270,6 @@ class CreateOfferViewModel extends ActivatableWithDataModel { + stopTimeoutTimer(); + isPlaceOfferButtonDisabled.set(false); + cancelButtonDisabled.set(false); + errorMessage.set("A timeout occurred at publishing the offer."); + resultHandler.run(); + }, 30); + } errorMessageListener = (observable, oldValue, newValue) -> { if (newValue != null) { + stopTimeoutTimer(); + isPlaceOfferButtonDisabled.set(false); + cancelButtonDisabled.set(false); if (offer.getState() == Offer.State.OFFER_FEE_PAID) - this.errorMessage.set(newValue + + errorMessage.set(newValue + "\n\nThe offer fee is already paid. In the worst case you have lost that fee. " + "We are sorry about that but keep in mind it is a very small amount.\n" + "Please try to restart you application and check your network connection to see if you can resolve the issue."); else - this.errorMessage.set(newValue); + errorMessage.set(newValue); + + resultHandler.run(); } }; offer.errorMessageProperty().addListener(errorMessageListener); - dataModel.onPlaceOffer(offer, transaction -> requestPlaceOfferSuccess.set(true)); + dataModel.onPlaceOffer(offer, transaction -> { + stopTimeoutTimer(); + placeOfferCompleted.set(true); + resultHandler.run(); + errorMessage.set(null); + }); + } + + private void stopTimeoutTimer() { + if (timeoutTimer != null) { + timeoutTimer.stop(); + timeoutTimer = null; + } } public void onPaymentAccountSelected(PaymentAccount paymentAccount) { diff --git a/gui/src/main/java/io/bitsquare/gui/main/offer/takeoffer/TakeOfferView.java b/gui/src/main/java/io/bitsquare/gui/main/offer/takeoffer/TakeOfferView.java index b0d574de81..24add3c591 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/offer/takeoffer/TakeOfferView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/offer/takeoffer/TakeOfferView.java @@ -21,6 +21,7 @@ import de.jensd.fx.fontawesome.AwesomeDude; import de.jensd.fx.fontawesome.AwesomeIcon; import io.bitsquare.app.BitsquareApp; import io.bitsquare.btc.FeePolicy; +import io.bitsquare.common.UserThread; import io.bitsquare.common.util.Tuple2; import io.bitsquare.common.util.Tuple3; import io.bitsquare.common.util.Utilities; @@ -59,10 +60,9 @@ import org.bitcoinj.core.Coin; import org.controlsfx.control.PopOver; import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.Subscription; -import org.reactfx.util.FxTimer; import javax.inject.Inject; -import java.time.Duration; +import java.util.concurrent.TimeUnit; import static io.bitsquare.gui.util.FormBuilder.*; import static javafx.beans.binding.Bindings.createStringBinding; @@ -223,21 +223,18 @@ public class TakeOfferView extends ActivatableViewAndModel { - new Popup().headLine(BSResources.get("takeOffer.success.headline")) - .feedback(BSResources.get("takeOffer.success.info")) - .actionButtonText("Go to \"Open trades\"") - .onAction(() -> { - close(); - FxTimer.runLater(Duration.ofMillis(100), - () -> navigation.navigateTo(MainView.class, PortfolioView.class, PendingTradesView.class) - ); - }) - .onClose(this::close) - .show(); - } - ); + UserThread.runAfter( + () -> new Popup().headLine(BSResources.get("takeOffer.success.headline")) + .feedback(BSResources.get("takeOffer.success.info")) + .actionButtonText("Go to \"Open trades\"") + .onAction(() -> { + close(); + UserThread.runAfter( + () -> navigation.navigateTo(MainView.class, PortfolioView.class, PendingTradesView.class) + , 100, TimeUnit.MILLISECONDS); + }) + .onClose(this::close) + .show(), 100, TimeUnit.MILLISECONDS); } }); diff --git a/gui/src/main/java/io/bitsquare/gui/main/overlays/Overlay.java b/gui/src/main/java/io/bitsquare/gui/main/overlays/Overlay.java index 7f63504884..83b2fb2797 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/overlays/Overlay.java +++ b/gui/src/main/java/io/bitsquare/gui/main/overlays/Overlay.java @@ -38,12 +38,11 @@ import javafx.stage.Stage; import javafx.stage.StageStyle; import javafx.stage.Window; import org.apache.commons.lang3.StringUtils; -import org.reactfx.util.FxTimer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.time.Duration; import java.util.Optional; +import java.util.concurrent.TimeUnit; import static io.bitsquare.gui.util.FormBuilder.addCheckBox; @@ -294,7 +293,7 @@ public abstract class Overlay { } protected void blurAgain() { - FxTimer.runLater(Duration.ofMillis(Transitions.DEFAULT_DURATION), MainView::blurLight); + UserThread.runAfter(MainView::blurLight, Transitions.DEFAULT_DURATION, TimeUnit.MILLISECONDS); } public void display() { @@ -479,7 +478,7 @@ public abstract class Overlay { closeButton = new Button(closeButtonText == null ? "Close" : closeButtonText); closeButton.setOnAction(event -> { hide(); - closeHandlerOptional.ifPresent(closeHandler -> closeHandler.run()); + closeHandlerOptional.ifPresent(Runnable::run); }); if (actionHandlerOptional.isPresent() || actionButtonText != null) { @@ -489,7 +488,7 @@ public abstract class Overlay { //actionButton.requestFocus(); actionButton.setOnAction(event -> { hide(); - actionHandlerOptional.ifPresent(actionHandler -> actionHandler.run()); + actionHandlerOptional.ifPresent(Runnable::run); }); Pane spacer = new Pane(); diff --git a/gui/src/main/java/io/bitsquare/gui/main/overlays/popups/Popup.java b/gui/src/main/java/io/bitsquare/gui/main/overlays/popups/Popup.java index 127f25d837..c14c937930 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/overlays/popups/Popup.java +++ b/gui/src/main/java/io/bitsquare/gui/main/overlays/popups/Popup.java @@ -21,7 +21,7 @@ import io.bitsquare.gui.main.overlays.Overlay; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class Popup extends Overlay { +public class Popup extends Overlay { protected final Logger log = LoggerFactory.getLogger(this.getClass()); public void onReadyForDisplay() { diff --git a/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/DisputeSummaryWindow.java b/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/DisputeSummaryWindow.java index fc9786da69..e364a6a9b3 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/DisputeSummaryWindow.java +++ b/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/DisputeSummaryWindow.java @@ -25,6 +25,7 @@ import io.bitsquare.btc.FeePolicy; import io.bitsquare.btc.TradeWalletService; import io.bitsquare.btc.WalletService; import io.bitsquare.btc.exceptions.TransactionVerificationException; +import io.bitsquare.common.UserThread; import io.bitsquare.common.util.Tuple2; import io.bitsquare.gui.main.overlays.Overlay; import io.bitsquare.gui.main.overlays.popups.Popup; @@ -44,14 +45,13 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import org.bitcoinj.core.AddressFormatException; import org.bitcoinj.core.Coin; -import org.reactfx.util.FxTimer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.inject.Inject; -import java.time.Duration; import java.util.Date; import java.util.Optional; +import java.util.concurrent.TimeUnit; import static io.bitsquare.gui.util.FormBuilder.*; @@ -389,8 +389,9 @@ public class DisputeSummaryWindow extends Overlay { disputeManager.sendDisputeResultMessage(disputeResult, dispute, text); if (!finalPeersDispute.isClosed()) - FxTimer.runLater(Duration.ofMillis(Transitions.DEFAULT_DURATION), () -> - new Popup().instruction("You need to close also the trading peers ticket!").show()); + UserThread.runAfter(() -> + new Popup().instruction("You need to close also the trading peers ticket!").show(), + Transitions.DEFAULT_DURATION, TimeUnit.MILLISECONDS); hide(); diff --git a/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/EmptyWalletWindow.java b/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/EmptyWalletWindow.java index dd0240918d..a84076853d 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/EmptyWalletWindow.java +++ b/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/EmptyWalletWindow.java @@ -19,6 +19,7 @@ package io.bitsquare.gui.main.overlays.windows; import io.bitsquare.btc.Restrictions; import io.bitsquare.btc.WalletService; +import io.bitsquare.common.UserThread; import io.bitsquare.common.util.Tuple2; import io.bitsquare.gui.components.InputTextField; import io.bitsquare.gui.main.overlays.Overlay; @@ -34,13 +35,12 @@ import javafx.scene.layout.HBox; import org.bitcoinj.core.AddressFormatException; import org.bitcoinj.core.Coin; import org.bitcoinj.core.InsufficientMoneyException; -import org.reactfx.util.FxTimer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.spongycastle.crypto.params.KeyParameter; import javax.inject.Inject; -import java.time.Duration; +import java.util.concurrent.TimeUnit; import static io.bitsquare.gui.util.FormBuilder.*; @@ -138,9 +138,9 @@ public class EmptyWalletWindow extends Overlay { addressTextField.setText(formatter.formatCoinWithCode(walletService.getAvailableBalance())); emptyWalletButton.setDisable(true); log.debug("wallet empty successful"); - FxTimer.runLater(Duration.ofMillis(Transitions.DEFAULT_DURATION), () -> new Popup() + UserThread.runAfter(() -> new Popup() .feedback("The balance of your wallet was successfully transferred.") - .onClose(() -> blurAgain()).show()); + .onClose(() -> blurAgain()).show(), Transitions.DEFAULT_DURATION, TimeUnit.MILLISECONDS); }, (errorMessage) -> { emptyWalletButton.setDisable(false); diff --git a/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/OfferDetailsWindow.java b/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/OfferDetailsWindow.java index ae9ac492b2..b91e01fd56 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/OfferDetailsWindow.java +++ b/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/OfferDetailsWindow.java @@ -19,7 +19,7 @@ package io.bitsquare.gui.main.overlays.windows; import com.google.common.base.Joiner; import io.bitsquare.common.crypto.KeyRing; -import io.bitsquare.common.util.Tuple2; +import io.bitsquare.common.util.Tuple3; import io.bitsquare.gui.Navigation; import io.bitsquare.gui.main.MainView; import io.bitsquare.gui.main.account.AccountView; @@ -36,9 +36,7 @@ import io.bitsquare.trade.offer.Offer; import io.bitsquare.user.Preferences; import io.bitsquare.user.User; import javafx.geometry.Insets; -import javafx.scene.control.Button; -import javafx.scene.control.TextField; -import javafx.scene.control.Tooltip; +import javafx.scene.control.*; import javafx.scene.image.ImageView; import org.bitcoinj.core.Coin; import org.jetbrains.annotations.NotNull; @@ -48,7 +46,6 @@ import org.slf4j.LoggerFactory; import javax.inject.Inject; import java.util.List; import java.util.Optional; -import java.util.function.Consumer; import static io.bitsquare.gui.util.FormBuilder.*; @@ -62,8 +59,9 @@ public class OfferDetailsWindow extends Overlay { private final Navigation navigation; private Offer offer; private Coin tradeAmount; - private Optional> placeOfferHandlerOptional = Optional.empty(); + private Optional placeOfferHandlerOptional = Optional.empty(); private Optional takeOfferHandlerOptional = Optional.empty(); + private ProgressIndicator spinner; /////////////////////////////////////////////////////////////////////////////////////////// @@ -100,7 +98,7 @@ public class OfferDetailsWindow extends Overlay { } - public OfferDetailsWindow onPlaceOffer(Consumer placeOfferHandler) { + public OfferDetailsWindow onPlaceOffer(Runnable placeOfferHandler) { this.placeOfferHandlerOptional = Optional.of(placeOfferHandler); return this; } @@ -111,7 +109,6 @@ public class OfferDetailsWindow extends Overlay { } - /////////////////////////////////////////////////////////////////////////////////////////// // Protected /////////////////////////////////////////////////////////////////////////////////////////// @@ -236,41 +233,57 @@ public class OfferDetailsWindow extends Overlay { boolean isBuyOffer = offer.getDirection() == Offer.Direction.BUY; boolean isBuyerRole = isPlaceOffer ? isBuyOffer : !isBuyOffer; - String placeOffer = isBuyerRole ? "Confirm place offer for buying bitcoin" : "Confirm place offer for selling bitcoin"; - String takeOffer = isBuyerRole ? "Confirm take offer for buying bitcoin" : "Confirm take offer for selling bitcoin"; - Tuple2 tuple = add2ButtonsAfterGroup(gridPane, - ++rowIndex, - isPlaceOffer ? placeOffer : takeOffer, - "Cancel"); - Button placeButton = tuple.first; + String placeOfferButtonText = isBuyerRole ? "Confirm place offer for buying bitcoin" : "Confirm place offer for selling bitcoin"; + String takeOfferButtonText = isBuyerRole ? "Confirm take offer for buying bitcoin" : "Confirm take offer for selling bitcoin"; ImageView iconView = new ImageView(); - iconView.setId(isBuyerRole ? "image-buy-white" : "image-sell-white"); - placeButton.setGraphicTextGap(10); - placeButton.setGraphic(iconView); + iconView.setId(isBuyOffer ? "image-buy-white" : "image-sell-white"); - placeButton.setId(isBuyerRole ? "buy-button" : "sell-button"); + Tuple3 placeOfferTuple = addButtonWithStatusAfterGroup(gridPane, ++rowIndex, isPlaceOffer ? placeOfferButtonText : takeOfferButtonText); - placeButton.setOnAction(e -> { + Button button = placeOfferTuple.first; + button.setGraphic(iconView); + button.setId(isBuyOffer ? "buy-button" : "sell-button"); + button.setText(isPlaceOffer ? placeOfferButtonText : takeOfferButtonText); + + spinner = placeOfferTuple.second; + spinner.setPrefSize(18, 18); + spinner.setVisible(false); + Label spinnerInfoLabel = placeOfferTuple.third; + + Button cancelButton = addButton(gridPane, ++rowIndex, BSResources.get("shared.cancel")); + cancelButton.setDefaultButton(false); + cancelButton.setId("cancel-button"); + cancelButton.setOnAction(e -> { + closeHandlerOptional.ifPresent(Runnable::run); + hide(); + }); + + button.setOnAction(e -> { if (user.getAcceptedArbitrators().size() > 0) { - if (isPlaceOffer) - placeOfferHandlerOptional.get().accept(offer); - else + button.setDisable(true); + cancelButton.setDisable(true); + spinner.setVisible(true); + spinner.setProgress(-1); + if (isPlaceOffer) { + spinnerInfoLabel.setText(BSResources.get("createOffer.fundsBox.placeOfferSpinnerInfo")); + placeOfferHandlerOptional.get().run(); + } else { + spinnerInfoLabel.setText("Take offer in progress..."); takeOfferHandlerOptional.get().run(); + } } else { new Popup().warning("You have no arbitrator selected.\n" + "Please select at least one arbitrator.").show(); navigation.navigateTo(MainView.class, AccountView.class, AccountSettingsView.class, ArbitratorSelectionView.class); } - hide(); - }); - - Button cancelButton = tuple.second; - cancelButton.setId("cancel-button"); - cancelButton.setOnAction(e -> { - closeHandlerOptional.ifPresent(Runnable::run); - hide(); }); } + + @Override + protected void onHidden() { + if (spinner != null) + spinner.setProgress(0); + } } diff --git a/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/WalletPasswordWindow.java b/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/WalletPasswordWindow.java index 8668ba038d..1d15cff415 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/WalletPasswordWindow.java +++ b/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/WalletPasswordWindow.java @@ -18,6 +18,7 @@ package io.bitsquare.gui.main.overlays.windows; import io.bitsquare.btc.WalletService; +import io.bitsquare.common.UserThread; import io.bitsquare.crypto.ScryptUtil; import io.bitsquare.gui.components.PasswordTextField; import io.bitsquare.gui.main.overlays.Overlay; @@ -32,13 +33,12 @@ import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; import org.bitcoinj.core.Wallet; import org.bitcoinj.crypto.KeyCrypterScrypt; -import org.reactfx.util.FxTimer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.spongycastle.crypto.params.KeyParameter; import javax.inject.Inject; -import java.time.Duration; +import java.util.concurrent.TimeUnit; public class WalletPasswordWindow extends Overlay { private static final Logger log = LoggerFactory.getLogger(WalletPasswordWindow.class); @@ -152,10 +152,10 @@ public class WalletPasswordWindow extends Overlay { hide(); } else { - FxTimer.runLater(Duration.ofMillis(Transitions.DEFAULT_DURATION), () -> new Popup() + UserThread.runAfter(() -> new Popup() .warning("You entered the wrong password.\n\n" + "Please try entering your password again, carefully checking for typos or spelling errors.") - .onClose(() -> blurAgain()).show()); + .onClose(this::blurAgain).show(), Transitions.DEFAULT_DURATION, TimeUnit.MILLISECONDS); } }); } else { diff --git a/gui/src/main/java/io/bitsquare/gui/main/settings/network/NetworkSettingsView.java b/gui/src/main/java/io/bitsquare/gui/main/settings/network/NetworkSettingsView.java index 0f0af78417..5a0d9dc571 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/settings/network/NetworkSettingsView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/settings/network/NetworkSettingsView.java @@ -21,6 +21,7 @@ import io.bitsquare.app.BitsquareApp; import io.bitsquare.btc.BitcoinNetwork; import io.bitsquare.btc.WalletService; import io.bitsquare.common.Clock; +import io.bitsquare.common.UserThread; import io.bitsquare.gui.common.model.Activatable; import io.bitsquare.gui.common.view.ActivatableViewAndModel; import io.bitsquare.gui.common.view.FxmlView; @@ -40,11 +41,10 @@ import javafx.util.StringConverter; import org.bitcoinj.core.Peer; import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.Subscription; -import org.reactfx.util.FxTimer; import javax.inject.Inject; -import java.time.Duration; import java.util.List; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @FxmlView @@ -137,7 +137,7 @@ public class NetworkSettingsView extends ActivatableViewAndModel { preferences.setUseTorForBitcoinJ(selected); - FxTimer.runLater(Duration.ofMillis(500), BitsquareApp.shutDownHandler::run); + UserThread.runAfter(BitsquareApp.shutDownHandler::run, 500, TimeUnit.MILLISECONDS); }) .closeButtonText("Cancel") .onClose(() -> useTorCheckBox.setSelected(!selected)) @@ -204,7 +204,7 @@ public class NetworkSettingsView extends ActivatableViewAndModel { preferences.setBitcoinNetwork(netWorkComboBox.getSelectionModel().getSelectedItem()); - FxTimer.runLater(Duration.ofMillis(500), BitsquareApp.shutDownHandler::run); + UserThread.runAfter(BitsquareApp.shutDownHandler::run, 500, TimeUnit.MILLISECONDS); }) .actionButtonText("Shut down") .closeButtonText("Cancel") diff --git a/gui/src/main/java/io/bitsquare/gui/util/FormBuilder.java b/gui/src/main/java/io/bitsquare/gui/util/FormBuilder.java index 3714be12d5..85009fe853 100644 --- a/gui/src/main/java/io/bitsquare/gui/util/FormBuilder.java +++ b/gui/src/main/java/io/bitsquare/gui/util/FormBuilder.java @@ -801,17 +801,16 @@ public class FormBuilder { double top) { HBox hBox = new HBox(); hBox.setSpacing(10); + Button button = new Button(buttonTitle); button.setDefaultButton(true); ProgressIndicator progressIndicator = new ProgressIndicator(0); progressIndicator.setPrefHeight(24); progressIndicator.setPrefWidth(24); - progressIndicator.setVisible(false); Label label = new Label(); - label.setPadding(new Insets(5, 0, 0, 0)); - + hBox.setAlignment(Pos.CENTER_LEFT); hBox.getChildren().addAll(button, progressIndicator, label); GridPane.setRowIndex(hBox, rowIndex); diff --git a/gui/src/main/resources/i18n/displayStrings.properties b/gui/src/main/resources/i18n/displayStrings.properties index c4b7c6b20b..b84e985971 100644 --- a/gui/src/main/resources/i18n/displayStrings.properties +++ b/gui/src/main/resources/i18n/displayStrings.properties @@ -63,7 +63,7 @@ createOffer.fundsBox.total=Total: createOffer.fundsBox.showAdvanced=Show advanced settings createOffer.fundsBox.hideAdvanced=Hide advanced settings createOffer.fundsBox.placeOffer=Place offer -createOffer.fundsBox.placeOfferSpinnerInfo=Offer fee payment is in progress... +createOffer.fundsBox.placeOfferSpinnerInfo=Offer publishing is in progress... createOffer.fundsBox.paymentLabel=Bitsquare trade with ID {0} createOffer.advancedBox.title=Advanced settings diff --git a/network/src/main/java/io/bitsquare/p2p/network/Connection.java b/network/src/main/java/io/bitsquare/p2p/network/Connection.java index b1ae06cd52..2e629646ef 100644 --- a/network/src/main/java/io/bitsquare/p2p/network/Connection.java +++ b/network/src/main/java/io/bitsquare/p2p/network/Connection.java @@ -61,8 +61,8 @@ public class Connection implements MessageListener { private static final int MAX_MSG_SIZE = 100 * 1024; // 100 kb of compressed data //TODO decrease limits again after testing - private static final int MSG_THROTTLE_PER_SEC = 10; // With MAX_MSG_SIZE of 100kb results in bandwidth of 10 mbit/sec - private static final int MSG_THROTTLE_PER_10_SEC = 100; // With MAX_MSG_SIZE of 100kb results in bandwidth of 100 mbit/sec for 10 sec + private static final int MSG_THROTTLE_PER_SEC = 50; // With MAX_MSG_SIZE of 100kb results in bandwidth of 5 mbit/sec + private static final int MSG_THROTTLE_PER_10_SEC = 500; // With MAX_MSG_SIZE of 100kb results in bandwidth of 50 mbit/sec for 10 sec private static final int SOCKET_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(60); public static int getMaxMsgSize() {