diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/BuyerSubView.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/BuyerSubView.java index 3b60750293..25f5ad0f60 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/BuyerSubView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/BuyerSubView.java @@ -17,16 +17,16 @@ package io.bitsquare.gui.main.portfolio.pendingtrades; -import io.bitsquare.gui.main.portfolio.pendingtrades.steps.*; -import io.bitsquare.locale.BSResources; +import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeWizardItem; +import io.bitsquare.gui.main.portfolio.pendingtrades.steps.buyer.*; import javafx.beans.value.ChangeListener; public class BuyerSubView extends TradeSubView { - private TradeWizardItem waitTxInBlockchain; - private TradeWizardItem startPayment; - private TradeWizardItem waitPaymentReceived; - private TradeWizardItem waitPayoutUnlock; - private TradeWizardItem completed; + private TradeWizardItem step1; + private TradeWizardItem step2; + private TradeWizardItem step3; + private TradeWizardItem step4; + private TradeWizardItem step5; private final ChangeListener stateChangeListener; @@ -55,16 +55,16 @@ public class BuyerSubView extends TradeSubView { @Override protected void addWizards() { - waitTxInBlockchain = new TradeWizardItem(WaitTxInBlockchainView.class, "Wait for blockchain confirmation"); - startPayment = new TradeWizardItem(StartPaymentView.class, "Start payment"); - waitPaymentReceived = new TradeWizardItem(WaitPaymentReceivedView.class, "Wait until payment arrived"); - waitPayoutUnlock = new TradeWizardItem(WaitPayoutLockTimeView.class, "Wait for payout unlock"); - completed = new TradeWizardItem(CompletedView.class, "Completed"); + step1 = new TradeWizardItem(BuyerStep1View.class, "Wait for blockchain confirmation"); + step2 = new TradeWizardItem(BuyerStep2View.class, "Start payment"); + step3 = new TradeWizardItem(BuyerStep3View.class, "Wait until payment arrived"); + step4 = new TradeWizardItem(BuyerStep4View.class, "Wait for payout unlock"); + step5 = new TradeWizardItem(BuyerStep5View.class, "Completed"); if (model.getLockTime() > 0) - leftVBox.getChildren().setAll(waitTxInBlockchain, startPayment, waitPaymentReceived, waitPayoutUnlock, completed); + leftVBox.getChildren().setAll(step1, step2, step3, step4, step5); else - leftVBox.getChildren().setAll(waitTxInBlockchain, startPayment, waitPaymentReceived, completed); + leftVBox.getChildren().setAll(step1, step2, step3, step5); } @@ -72,17 +72,17 @@ public class BuyerSubView extends TradeSubView { // State /////////////////////////////////////////////////////////////////////////////////////////// - protected void applyState(PendingTradesViewModel.BuyerState state) { + private void applyState(PendingTradesViewModel.BuyerState state) { log.debug("applyState " + state); - waitTxInBlockchain.setDisabled(); - startPayment.setDisabled(); - waitPaymentReceived.setDisabled(); - waitPayoutUnlock.setDisabled(); - completed.setDisabled(); + step1.setDisabled(); + step2.setDisabled(); + step3.setDisabled(); + step4.setDisabled(); + step5.setDisabled(); - if (tradeStepDetailsView != null) - tradeStepDetailsView.doDeactivate(); + if (tradeStepView != null) + tradeStepView.doDeactivate(); switch (state) { case UNDEFINED: @@ -90,58 +90,48 @@ public class BuyerSubView extends TradeSubView { leftVBox.getChildren().clear(); break; case WAIT_FOR_BLOCKCHAIN_CONFIRMATION: - showItem(waitTxInBlockchain); - - ((WaitTxInBlockchainView) tradeStepDetailsView).setInfoLabelText("Deposit transaction has been published. You need to wait for at least " + - "one blockchain confirmation."); + showItem(step1); break; case REQUEST_START_FIAT_PAYMENT: - waitTxInBlockchain.setCompleted(); - showItem(startPayment); + step1.setCompleted(); + showItem(step2); break; case WAIT_FOR_FIAT_PAYMENT_RECEIPT: - waitTxInBlockchain.setCompleted(); - startPayment.setCompleted(); - showItem(waitPaymentReceived); - - ((WaitPaymentReceivedView) tradeStepDetailsView).setInfoLabelText(BSResources.get("Waiting for the bitcoin sellers confirmation " + - "that the {0} payment has arrived.", - model.getCurrencyCode())); + step1.setCompleted(); + step2.setCompleted(); + showItem(step3); break; case WAIT_FOR_UNLOCK_PAYOUT: if (model.getLockTime() > 0) { - waitTxInBlockchain.setCompleted(); - startPayment.setCompleted(); - waitPaymentReceived.setCompleted(); - showItem(waitPayoutUnlock); - - ((WaitPayoutLockTimeView) tradeStepDetailsView).setInfoLabelText("The payout transaction is signed and finalized by both parties." + - "\nFor reducing bank charge back risks you need to wait until the payout gets unlocked to transfer your bitcoin."); + step1.setCompleted(); + step2.setCompleted(); + step3.setCompleted(); + showItem(step4); } break; case REQUEST_WITHDRAWAL: - waitTxInBlockchain.setCompleted(); - startPayment.setCompleted(); - waitPaymentReceived.setCompleted(); - waitPayoutUnlock.setCompleted(); - showItem(completed); + step1.setCompleted(); + step2.setCompleted(); + step3.setCompleted(); + step4.setCompleted(); + showItem(step5); - CompletedView completedView = (CompletedView) tradeStepDetailsView; - completedView.setBtcTradeAmountLabelText("You have bought:"); - completedView.setFiatTradeAmountLabelText("You have paid:"); - completedView.setBtcTradeAmountTextFieldText(model.getTradeVolume()); - completedView.setFiatTradeAmountTextFieldText(model.getFiatVolume()); - completedView.setFeesTextFieldText(model.getTotalFees()); - completedView.setSecurityDepositTextFieldText(model.getSecurityDeposit()); - completedView.setWithdrawAmountTextFieldText(model.getPayoutAmount()); + BuyerStep5View buyerStep5View = (BuyerStep5View) tradeStepView; + buyerStep5View.setBtcTradeAmountLabelText("You have bought:"); + buyerStep5View.setFiatTradeAmountLabelText("You have paid:"); + buyerStep5View.setBtcTradeAmountTextFieldText(model.getTradeVolume()); + buyerStep5View.setFiatTradeAmountTextFieldText(model.getFiatVolume()); + buyerStep5View.setFeesTextFieldText(model.getTotalFees()); + buyerStep5View.setSecurityDepositTextFieldText(model.getSecurityDeposit()); + buyerStep5View.setWithdrawAmountTextFieldText(model.getPayoutAmount()); break; default: log.warn("unhandled buyerState " + state); break; } - if (tradeStepDetailsView != null) - tradeStepDetailsView.doActivate(); + if (tradeStepView != null) + tradeStepView.doActivate(); } } diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesDataModel.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesDataModel.java index 2a6ceab902..c49d6b977a 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesDataModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesDataModel.java @@ -49,7 +49,6 @@ import javafx.collections.ObservableList; import org.bitcoinj.core.BlockChainListener; import org.bitcoinj.core.Coin; import org.bitcoinj.core.Transaction; -import org.bitcoinj.core.TransactionOutput; import org.spongycastle.crypto.params.KeyParameter; import java.util.ArrayList; @@ -208,6 +207,19 @@ public class PendingTradesDataModel extends ActivatableDataModel { List candidates = new ArrayList<>(); List transactions = walletService.getWallet().getRecentTransactions(100, true); transactions.stream().forEach(transaction -> { + Coin valueSentFromMe = transaction.getValueSentFromMe(walletService.getWallet()); + if (!valueSentFromMe.isZero()) { + // spending tx + // MS tx + candidates.addAll(transaction.getOutputs().stream() + .filter(transactionOutput -> !transactionOutput.isMine(walletService.getWallet())) + .filter(transactionOutput -> transactionOutput.getScriptPubKey().isPayToScriptHash()) + .map(transactionOutput -> transaction) + .collect(Collectors.toList())); + } + }); + + /*transactions.stream().forEach(transaction -> { Coin valueSentFromMe = transaction.getValueSentFromMe(walletService.getWallet()); if (!valueSentFromMe.isZero()) { // spending tx @@ -220,15 +232,13 @@ public class PendingTradesDataModel extends ActivatableDataModel { } } } - }); + });*/ if (candidates.size() == 1) doOpenDispute(isSupportTicket, candidates.get(0)); else if (candidates.size() > 1) new SelectDepositTxPopup().transactions(candidates) - .onSelect(transaction -> { - doOpenDispute(isSupportTicket, transaction); - }) + .onSelect(transaction -> doOpenDispute(isSupportTicket, transaction)) .closeButtonText("Cancel") .show(); else @@ -365,7 +375,10 @@ public class PendingTradesDataModel extends ActivatableDataModel { } public PaymentAccountContractData getSellersPaymentAccountContractData() { - return trade.getContract().getSellerPaymentAccountContractData(); + if (trade.getContract() != null) + return trade.getContract().getSellerPaymentAccountContractData(); + else + return null; } public String getReference() { diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesListItem.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesListItem.java index d91c05e766..0135f15298 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesListItem.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesListItem.java @@ -22,8 +22,6 @@ import javafx.beans.property.ReadOnlyObjectProperty; import org.bitcoinj.core.Coin; import org.bitcoinj.utils.Fiat; -import java.util.Date; - /** * We could remove that wrapper if it is not needed for additional UI only fields. */ @@ -31,39 +29,20 @@ public class PendingTradesListItem { private final Trade trade; - - /////////////////////////////////////////////////////////////////////////////////////////// - // Constructor - /////////////////////////////////////////////////////////////////////////////////////////// - public PendingTradesListItem(Trade trade) { this.trade = trade; } - /////////////////////////////////////////////////////////////////////////////////////////// - // Getters - /////////////////////////////////////////////////////////////////////////////////////////// - public Trade getTrade() { return trade; } public ReadOnlyObjectProperty tradeAmountProperty() { - if (trade instanceof Trade) - return trade.tradeAmountProperty(); - else - return trade.tradeAmountProperty(); + return trade.tradeAmountProperty(); } public ReadOnlyObjectProperty tradeVolumeProperty() { - if (trade instanceof Trade) - return trade.tradeVolumeProperty(); - else - return trade.tradeVolumeProperty(); - } - - public Date getDate() { - return trade.getDate(); + return trade.tradeVolumeProperty(); } public String getId() { diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesView.fxml b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesView.fxml index 3eec879a2c..eb36e40ed5 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesView.fxml +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesView.fxml @@ -18,7 +18,7 @@ --> - + - - - - - + diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesView.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesView.java index 9e316c2171..b1a091a688 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesView.java @@ -45,7 +45,6 @@ import org.bitcoinj.core.Coin; import org.bitcoinj.utils.Fiat; import javax.inject.Inject; -import java.util.Date; @FxmlView public class PendingTradesView extends ActivatableViewAndModel { @@ -54,13 +53,9 @@ public class PendingTradesView extends ActivatableViewAndModel table; @FXML - TableColumn priceColumn; + TableColumn priceColumn, tradeVolumeColumn; @FXML - TableColumn tradeVolumeColumn; - @FXML - TableColumn roleColumn, paymentMethodColumn, idColumn; - @FXML - TableColumn dateColumn; + TableColumn roleColumn, paymentMethodColumn, idColumn, dateColumn; @FXML TableColumn tradeAmountColumn; @@ -119,31 +114,35 @@ public class PendingTradesView extends ActivatableViewAndModel { log.debug("currentTradeChangeListener {} ", newValue); - setNewSubView(newValue); + // setNewSubView(newValue); }; // we use a hidden emergency shortcut to open support ticket keyEventEventHandler = event -> { if (new KeyCodeCombination(KeyCode.O, KeyCombination.SHORTCUT_DOWN).match(event)) - new OpenEmergencyTicketPopup().onOpenTicket(() -> model.dataModel.onOpenSupportTicket()).show(); + new OpenEmergencyTicketPopup().onOpenTicket(model.dataModel::onOpenSupportTicket).show(); }; } @Override protected void activate() { scene = root.getScene(); - appFocusProperty = scene.getWindow().focusedProperty(); + if (scene != null) { + appFocusProperty = scene.getWindow().focusedProperty(); + scene.addEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler); + } + appFocusProperty.addListener(appFocusChangeListener); model.currentTrade().addListener(currentTradeChangeListener); //setNewSubView(model.currentTrade().get()); table.setItems(model.getList()); table.getSelectionModel().selectedItemProperty().addListener(selectedItemChangeListener); - updateSelectedItem(); if (model.getSelectedItem() == null) model.getList().addListener(listChangeListener); - scene.addEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler); + + updateSelectedItem(); } private void updateSelectedItem() { @@ -204,7 +203,7 @@ public class PendingTradesView extends ActivatableViewAndModelforTableColumn( - new StringConverter() { + dateColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); + dateColumn.setCellFactory( + new Callback, TableCell>() { @Override - public String toString(Date value) { - return model.formatDate(value); + public TableCell call( + TableColumn column) { + return new TableCell() { + @Override + public void updateItem(final PendingTradesListItem item, boolean empty) { + super.updateItem(item, empty); + if (item != null && !empty) { + if (model.showDispute(item.getTrade())) { + setStyle("-fx-text-fill: -bs-error-red"); + } else if (model.showWarning(item.getTrade())) { + setStyle("-fx-text-fill: -bs-orange"); + } else { + setId("-fx-text-fill: black"); + } + setText(model.getDate(item)); + } else { + setText(null); + } + } + }; } - - @Override - public Date fromString(String string) { - return null; - } - })); + }); } private void setAmountColumnCellFactory() { diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesViewModel.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesViewModel.java index c6d0cacb71..bf7f28b8f5 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesViewModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesViewModel.java @@ -167,7 +167,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel= trade.getCheckPaymentTimeAsBlockHeight(); + } + + public boolean showDispute(Trade trade) { + return getBestChainHeight() >= trade.getOpenDisputeTimeAsBlockHeight(); + } + String getMyRole(PendingTradesListItem item) { Trade trade = item.getTrade(); Contract contract = trade.getContract(); @@ -288,7 +314,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel stateChangeListener; @@ -55,16 +55,16 @@ public class SellerSubView extends TradeSubView { @Override protected void addWizards() { - waitTxInBlockchain = new TradeWizardItem(WaitTxInBlockchainView.class, "Wait for blockchain confirmation"); - waitPaymentStarted = new TradeWizardItem(WaitPaymentStartedView.class, "Wait until payment has started"); - confirmPaymentReceived = new TradeWizardItem(ConfirmPaymentReceivedView.class, "Confirm payment received"); - waitPayoutUnlock = new TradeWizardItem(WaitPayoutLockTimeView.class, "Wait for payout unlock"); - completed = new TradeWizardItem(CompletedView.class, "Completed"); + step1 = new TradeWizardItem(SellerStep1View.class, "Wait for blockchain confirmation"); + step2 = new TradeWizardItem(SellerStep2View.class, "Wait until payment has started"); + step3 = new TradeWizardItem(SellerStep3View.class, "Confirm payment received"); + step4 = new TradeWizardItem(SellerStep4aView.class, "Wait for payout unlock"); + step5 = new TradeWizardItem(SellerStep5View.class, "Completed"); if (model.getLockTime() > 0) - leftVBox.getChildren().setAll(waitTxInBlockchain, waitPaymentStarted, confirmPaymentReceived, waitPayoutUnlock, completed); + leftVBox.getChildren().setAll(step1, step2, step3, step4, step5); else - leftVBox.getChildren().setAll(waitTxInBlockchain, waitPaymentStarted, confirmPaymentReceived, completed); + leftVBox.getChildren().setAll(step1, step2, step3, step5); } @@ -75,14 +75,14 @@ public class SellerSubView extends TradeSubView { private void applyState(PendingTradesViewModel.SellerState viewState) { log.debug("applyState " + viewState); - waitTxInBlockchain.setDisabled(); - waitPaymentStarted.setDisabled(); - confirmPaymentReceived.setDisabled(); - waitPayoutUnlock.setDisabled(); - completed.setDisabled(); + step1.setDisabled(); + step2.setDisabled(); + step3.setDisabled(); + step4.setDisabled(); + step5.setDisabled(); - if (tradeStepDetailsView != null) - tradeStepDetailsView.doDeactivate(); + if (tradeStepView != null) + tradeStepView.doDeactivate(); switch (viewState) { case UNDEFINED: @@ -90,83 +90,57 @@ public class SellerSubView extends TradeSubView { leftVBox.getChildren().clear(); break; case WAIT_FOR_BLOCKCHAIN_CONFIRMATION: - showItem(waitTxInBlockchain); - - ((WaitTxInBlockchainView) tradeStepDetailsView).setInfoLabelText("Deposit transaction has been published. " + - "The bitcoin buyer need to wait for at least one blockchain confirmation."); + showItem(step1); break; case WAIT_FOR_FIAT_PAYMENT_STARTED: - waitTxInBlockchain.setCompleted(); - showItem(waitPaymentStarted); - - ((WaitTxInBlockchainView) tradeStepDetailsView).setInfoLabelText(BSResources.get("Deposit transaction has at least one blockchain " + - "confirmation. " + - "Waiting that the bitcoin buyer starts the {0} payment.", - model.getCurrencyCode())); + step1.setCompleted(); + showItem(step2); break; case REQUEST_CONFIRM_FIAT_PAYMENT_RECEIVED: - waitTxInBlockchain.setCompleted(); - waitPaymentStarted.setCompleted(); - showItem(confirmPaymentReceived); - - if (model.isBlockChainMethod()) { - ((ConfirmPaymentReceivedView) tradeStepDetailsView).setInfoLabelText(BSResources.get("The bitcoin buyer has started the {0} payment. " + - "Check your Altcoin wallet or Block explorer and confirm when you have received the payment.", - model.getCurrencyCode())); - } else { - ((ConfirmPaymentReceivedView) tradeStepDetailsView).setInfoLabelText(BSResources.get("The bitcoin buyer has started the {0} payment. " + - "Check your payment account and confirm when you have received the payment.", - model.getCurrencyCode())); - } - + step1.setCompleted(); + step2.setCompleted(); + showItem(step3); break; case WAIT_FOR_PAYOUT_TX: - waitTxInBlockchain.setCompleted(); - waitPaymentStarted.setCompleted(); - confirmPaymentReceived.setCompleted(); - showItem(waitPayoutUnlock); + step1.setCompleted(); + step2.setCompleted(); + step3.setCompleted(); + showItem(step4); // We don't use a wizard for that step as it only gets displayed in case the other peer is offline - tradeStepDetailsView = new WaitPayoutFinalizedView(model); - contentPane.getChildren().setAll(tradeStepDetailsView); - - ((WaitPayoutFinalizedView) tradeStepDetailsView).setInfoLabelText("We requested the trading peer to sign and finalize the payout " + - "transaction.\n" + - "It might be that the other peer is offline, so we need to wait until he finalize the transaction when he goes online again."); + tradeStepView = new SellerStep4bView(model); + contentPane.getChildren().setAll(tradeStepView); break; case WAIT_FOR_UNLOCK_PAYOUT: - waitTxInBlockchain.setCompleted(); - waitPaymentStarted.setCompleted(); - confirmPaymentReceived.setCompleted(); - showItem(waitPayoutUnlock); - - ((WaitPayoutLockTimeView) tradeStepDetailsView).setInfoLabelText("The payout transaction is signed and finalized by both parties." + - "\nFor reducing bank charge back risks you need to wait until the payout gets unlocked to transfer your bitcoin."); + step1.setCompleted(); + step2.setCompleted(); + step3.setCompleted(); + showItem(step4); break; case REQUEST_WITHDRAWAL: - waitTxInBlockchain.setCompleted(); - waitPaymentStarted.setCompleted(); - confirmPaymentReceived.setCompleted(); - waitPayoutUnlock.setCompleted(); - showItem(completed); + step1.setCompleted(); + step2.setCompleted(); + step3.setCompleted(); + step4.setCompleted(); + showItem(step5); - CompletedView completedView = (CompletedView) tradeStepDetailsView; - completedView.setBtcTradeAmountLabelText("You have sold:"); - completedView.setFiatTradeAmountLabelText("You have received:"); - completedView.setBtcTradeAmountTextFieldText(model.getTradeVolume()); - completedView.setFiatTradeAmountTextFieldText(model.getFiatVolume()); - completedView.setFeesTextFieldText(model.getTotalFees()); - completedView.setSecurityDepositTextFieldText(model.getSecurityDeposit()); + SellerStep5View sellerStep5View = (SellerStep5View) tradeStepView; + sellerStep5View.setBtcTradeAmountLabelText("You have sold:"); + sellerStep5View.setFiatTradeAmountLabelText("You have received:"); + sellerStep5View.setBtcTradeAmountTextFieldText(model.getTradeVolume()); + sellerStep5View.setFiatTradeAmountTextFieldText(model.getFiatVolume()); + sellerStep5View.setFeesTextFieldText(model.getTotalFees()); + sellerStep5View.setSecurityDepositTextFieldText(model.getSecurityDeposit()); - completedView.setWithdrawAmountTextFieldText(model.getPayoutAmount()); + sellerStep5View.setWithdrawAmountTextFieldText(model.getPayoutAmount()); break; default: log.warn("unhandled viewState " + viewState); break; } - if (tradeStepDetailsView != null) - tradeStepDetailsView.doActivate(); + if (tradeStepView != null) + tradeStepView.doActivate(); } } diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/TradeSubView.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/TradeSubView.java index 8becb18659..c1b70208ad 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/TradeSubView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/TradeSubView.java @@ -17,23 +17,31 @@ package io.bitsquare.gui.main.portfolio.pendingtrades; -import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeStepDetailsView; +import io.bitsquare.common.util.Tuple3; +import io.bitsquare.gui.components.TitledGroupBg; +import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeStepView; import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeWizardItem; import io.bitsquare.gui.util.Layout; -import javafx.scene.layout.AnchorPane; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Priority; -import javafx.scene.layout.VBox; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.layout.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static io.bitsquare.gui.util.FormBuilder.addMultilineLabel; +import static io.bitsquare.gui.util.FormBuilder.addTitledGroupBg; + public abstract class TradeSubView extends HBox { protected final Logger log = LoggerFactory.getLogger(this.getClass()); protected final PendingTradesViewModel model; protected VBox leftVBox; protected AnchorPane contentPane; - protected TradeStepDetailsView tradeStepDetailsView; + protected TradeStepView tradeStepView; + private Button openDisputeButton; + private Tuple3 notificationTuple; /////////////////////////////////////////////////////////////////////////////////////////// @@ -48,24 +56,48 @@ public abstract class TradeSubView extends HBox { } protected void activate() { - // don't call tradeStepDetailsView.activate() as that will be called when state is set } protected void deactivate() { - if (tradeStepDetailsView != null) - tradeStepDetailsView.doDeactivate(); + if (tradeStepView != null) + tradeStepView.doDeactivate(); + + if (openDisputeButton != null) + leftVBox.getChildren().remove(openDisputeButton); + if (notificationTuple != null) + leftVBox.getChildren().remove(notificationTuple.first); } - - /////////////////////////////////////////////////////////////////////////////////////////// - // Misc - /////////////////////////////////////////////////////////////////////////////////////////// - - private void buildViews() { addLeftBox(); addContentPane(); addWizards(); + + openDisputeButton = new Button("Open Dispute"); + openDisputeButton.setPrefHeight(40); + openDisputeButton.setPrefWidth(360); + openDisputeButton.setPadding(new Insets(0, 20, 0, 10)); + openDisputeButton.setAlignment(Pos.CENTER); + openDisputeButton.setDefaultButton(true); + openDisputeButton.setId("open-dispute-button"); + openDisputeButton.setVisible(false); + openDisputeButton.setManaged(false); + leftVBox.getChildren().add(openDisputeButton); + VBox.setMargin(openDisputeButton, new Insets(10, 0, 0, 0)); + + // notification fields + GridPane gridPane = new GridPane(); + gridPane.setPrefWidth(340); + VBox.setMargin(gridPane, new Insets(10, 10, 10, 10)); + gridPane.setHgap(Layout.GRID_GAP); + gridPane.setVgap(Layout.GRID_GAP); + gridPane.setVisible(false); + gridPane.setManaged(false); + leftVBox.getChildren().add(gridPane); + + TitledGroupBg titledGroupBg = addTitledGroupBg(gridPane, 0, 4, "Important notice", 20); + Label label = addMultilineLabel(gridPane, 0, Layout.FIRST_ROW_DISTANCE + 20); + notificationTuple = new Tuple3<>(gridPane, titledGroupBg, label); } protected void showItem(TradeWizardItem item) { @@ -75,10 +107,13 @@ public abstract class TradeSubView extends HBox { abstract protected void addWizards(); - private void createAndAddTradeStepView(Class viewClass) { + private void createAndAddTradeStepView(Class viewClass) { try { - tradeStepDetailsView = viewClass.getDeclaredConstructor(PendingTradesViewModel.class).newInstance(model); - contentPane.getChildren().setAll(tradeStepDetailsView); + tradeStepView = viewClass.getDeclaredConstructor(PendingTradesViewModel.class).newInstance(model); + contentPane.getChildren().setAll(tradeStepView); + + tradeStepView.setNotificationFields(notificationTuple); + tradeStepView.setOpenDisputeButton(openDisputeButton); } catch (Exception e) { e.printStackTrace(); } diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/TradeStepDetailsView.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/TradeStepDetailsView.java deleted file mode 100644 index 1bb68bd63f..0000000000 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/TradeStepDetailsView.java +++ /dev/null @@ -1,295 +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 . - */ - -package io.bitsquare.gui.main.portfolio.pendingtrades.steps; - -import io.bitsquare.arbitration.Dispute; -import io.bitsquare.gui.components.TitledGroupBg; -import io.bitsquare.gui.main.help.Help; -import io.bitsquare.gui.main.help.HelpId; -import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel; -import io.bitsquare.gui.popups.Popup; -import io.bitsquare.gui.util.Layout; -import io.bitsquare.trade.Trade; -import javafx.geometry.HPos; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.layout.AnchorPane; -import javafx.scene.layout.GridPane; -import org.bitcoinj.core.*; -import org.fxmisc.easybind.EasyBind; -import org.fxmisc.easybind.Subscription; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.List; -import java.util.Optional; - -import static io.bitsquare.gui.util.FormBuilder.*; - -public abstract class TradeStepDetailsView extends AnchorPane { - protected final Logger log = LoggerFactory.getLogger(this.getClass()); - protected final PendingTradesViewModel model; - protected final GridPane gridPane; - protected int gridRow = 0; - private final BlockChainListener blockChainListener; - - private long checkPaymentTimeInBlocks; - protected long openDisputeTimeInBlocks; - protected Label infoLabel; - protected TitledGroupBg infoTitledGroupBg; - protected Button openDisputeButton; - protected Button openSupportTicketButton; - - private Trade trade; - private Subscription errorMessageSubscription; - private Subscription disputeStateSubscription; - private Subscription tradePeriodStateSubscription; - - - /////////////////////////////////////////////////////////////////////////////////////////// - // Constructor, Initialisation - /////////////////////////////////////////////////////////////////////////////////////////// - - public TradeStepDetailsView(PendingTradesViewModel model) { - this.model = model; - - AnchorPane.setLeftAnchor(this, 0d); - AnchorPane.setRightAnchor(this, 0d); - AnchorPane.setTopAnchor(this, -10d); - AnchorPane.setBottomAnchor(this, 0d); - - gridPane = addGridPane(this); - - buildGridEntries(); - - blockChainListener = new BlockChainListener() { - @Override - public void notifyNewBestBlock(StoredBlock block) throws VerificationException { - setDateFromBlocks(block.getHeight()); - } - - @Override - public void reorganize(StoredBlock splitPoint, List oldBlocks, List newBlocks) throws VerificationException { - setDateFromBlocks(model.getBestChainHeight()); - } - - @Override - public boolean isTransactionRelevant(Transaction tx) throws ScriptException { - return false; - } - - @Override - public void receiveFromBlock(Transaction tx, StoredBlock block, AbstractBlockChain.NewBlockType blockType, int relativityOffset) throws - VerificationException { - } - - @Override - public boolean notifyTransactionIsInBlock(Sha256Hash txHash, StoredBlock block, AbstractBlockChain.NewBlockType blockType, int relativityOffset) - throws VerificationException { - return false; - } - }; - } - - // That is called at every state change! - public void doActivate() { - trade = model.getTrade(); - - errorMessageSubscription = EasyBind.subscribe(trade.errorMessageProperty(), newValue -> { - if (newValue != null) { - addErrorLabel(); - } - }); - - disputeStateSubscription = EasyBind.subscribe(trade.disputeStateProperty(), newValue -> { - if (newValue != null) { - updateDisputeState(newValue); - } - }); - - tradePeriodStateSubscription = EasyBind.subscribe(trade.getTradePeriodStateProperty(), newValue -> { - if (newValue != null) { - updateTradePeriodState(newValue); - } - }); - - setDateFromBlocks(model.getBestChainHeight()); - - // first call updateTradePeriodState as there is the dispute button created in case we are in period over time - updateTradePeriodState(trade.getTradePeriodState()); - updateDisputeState(trade.getDisputeState()); - - model.addBlockChainListener(blockChainListener); - } - - public void doDeactivate() { - model.removeBlockChainListener(blockChainListener); - - if (errorMessageSubscription != null) - errorMessageSubscription.unsubscribe(); - if (disputeStateSubscription != null) - disputeStateSubscription.unsubscribe(); - if (tradePeriodStateSubscription != null) - tradePeriodStateSubscription.unsubscribe(); - - if (openDisputeButton != null) - openDisputeButton.setOnAction(null); - if (openSupportTicketButton != null) - openSupportTicketButton.setOnAction(null); - } - - protected void disputeInProgress() { - if (openDisputeButton != null) - openDisputeButton.setDisable(true); - - addDisputeInfoLabel(); - } - - protected void addDisputeInfoLabel() { - if (infoLabel == null) { - infoTitledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 1, "Information", Layout.GROUP_DISTANCE); - infoLabel = addMultilineLabel(gridPane, gridRow, Layout.FIRST_ROW_AND_GROUP_DISTANCE); - } - infoLabel.setStyle(" -fx-text-fill: -bs-error-red;"); - } - - protected void addOpenDisputeButton() { - if (openDisputeButton == null) { - openDisputeButton = addButtonAfterGroup(gridPane, ++gridRow, "Open a dispute with arbitrator"); - GridPane.setColumnIndex(openDisputeButton, 0); - GridPane.setHalignment(openDisputeButton, HPos.LEFT); - openDisputeButton.setOnAction(e -> { - openDisputeButton.setDisable(true); - disputeInProgress(); - model.dataModel.onOpenDispute(); - }); - } - } - - private void addErrorLabel() { - new Popup().warning(trade.errorMessageProperty().getValue() - + "\n\nPlease report the problem to your arbitrator. He will forward it to the developers to investigate the problem.\n" + - "After the problem has be analysed you will get back all the funds you paid in.\n" + - "There will be no arbitration fee charged if it was a technical error.").show(); - - /*if (infoLabel == null) { - infoTitledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 1, "Error", Layout.GROUP_DISTANCE); - infoLabel = addMultilineLabel(gridPane, gridRow, Layout.FIRST_ROW_AND_GROUP_DISTANCE); - } - infoTitledGroupBg.setText("Error message"); - infoLabel.setText(trade.errorMessageProperty().getValue() - + "\n\nPlease report the problem to your arbitrator. He will forward it to the developers to investigate the problem.\n" + - "After the problem has be analysed you will get back all the funds you paid in.\n" + - "There will be no arbitration fee charged if it was a technical error."); - infoLabel.setStyle(" -fx-text-fill: -bs-error-red;");*/ - - if (openSupportTicketButton == null) { - openSupportTicketButton = addButton(gridPane, ++gridRow, "Request support"); - GridPane.setHalignment(openSupportTicketButton, HPos.LEFT); - openSupportTicketButton.setOnAction(e -> model.dataModel.onOpenSupportTicket()); - } - } - - - private void updateDisputeState(Trade.DisputeState disputeState) { - Optional ownDispute = model.dataModel.getDisputeManager().findOwnDispute(trade.getId()); - - switch (disputeState) { - case NONE: - break; - case DISPUTE_REQUESTED: - disputeInProgress(); - ownDispute.ifPresent(dispute -> { - String msg; - if (dispute.isSupportTicket()) - msg = "You opened already a support ticket.\n" + - "Please communicate in the support section with the arbitrator."; - else - msg = "You opened already a dispute.\n" + - "Please communicate in the support section with the arbitrator."; - - infoLabel.setText(msg); - }); - - break; - case DISPUTE_STARTED_BY_PEER: - disputeInProgress(); - ownDispute.ifPresent(dispute -> { - String msg; - if (dispute.isSupportTicket()) - msg = "Your trading peer opened a support ticket due technical problems.\n" + - "Please communicate in the support section with the arbitrator."; - else - msg = "Your trading peer opened a dispute.\n" + - "Please communicate in the support section with the arbitrator."; - - infoLabel.setText(msg); - }); - break; - case DISPUTE_CLOSED: - break; - } - } - - - private void updateTradePeriodState(Trade.TradePeriodState tradePeriodState) { - switch (tradePeriodState) { - case NORMAL: - break; - case HALF_REACHED: - displayRequestCheckPayment(); - break; - case TRADE_PERIOD_OVER: - displayOpenForDisputeForm(); - break; - } - } - - private void setDateFromBlocks(long bestBlocKHeight) { - checkPaymentTimeInBlocks = model.getCheckPaymentTimeAsBlockHeight() - bestBlocKHeight; - openDisputeTimeInBlocks = model.getOpenDisputeTimeAsBlockHeight() - bestBlocKHeight; - updateDateFromBlocks(bestBlocKHeight); - } - - protected void updateDateFromBlocks(long bestBlocKHeight) { - } - - - /////////////////////////////////////////////////////////////////////////////////////////// - // UI Handlers - /////////////////////////////////////////////////////////////////////////////////////////// - - protected void onOpenHelp() { - Help.openWindow(model.isOfferer() ? HelpId.PENDING_TRADE_OFFERER : HelpId.PENDING_TRADE_TAKER); - } - - - /////////////////////////////////////////////////////////////////////////////////////////// - // Build view - /////////////////////////////////////////////////////////////////////////////////////////// - - abstract void buildGridEntries(); - - protected void displayRequestCheckPayment() { - } - - protected void displayOpenForDisputeForm() { - } - - -} diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/TradeStepView.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/TradeStepView.java new file mode 100644 index 0000000000..86003f643c --- /dev/null +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/TradeStepView.java @@ -0,0 +1,402 @@ +/* + * 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 . + */ + +package io.bitsquare.gui.main.portfolio.pendingtrades.steps; + +import io.bitsquare.arbitration.Dispute; +import io.bitsquare.common.util.Tuple3; +import io.bitsquare.gui.components.TitledGroupBg; +import io.bitsquare.gui.components.TxIdTextField; +import io.bitsquare.gui.components.paymentmethods.PaymentMethodForm; +import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel; +import io.bitsquare.gui.popups.Popup; +import io.bitsquare.gui.util.Layout; +import io.bitsquare.trade.Trade; +import io.bitsquare.user.Preferences; +import javafx.beans.value.ChangeListener; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.ProgressBar; +import javafx.scene.control.TextField; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.GridPane; +import org.fxmisc.easybind.EasyBind; +import org.fxmisc.easybind.Subscription; +import org.reactfx.util.FxTimer; +import org.reactfx.util.Timer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.Duration; +import java.util.Optional; + +import static io.bitsquare.gui.util.FormBuilder.*; + +public abstract class TradeStepView extends AnchorPane { + protected final Logger log = LoggerFactory.getLogger(this.getClass()); + + protected final PendingTradesViewModel model; + private final Trade trade; + protected final Preferences preferences; + protected final GridPane gridPane; + private final ChangeListener txIdChangeListener; + + private Subscription errorMessageSubscription; + private Subscription disputeStateSubscription; + private Subscription tradePeriodStateSubscription; + private Timer timer; + protected int gridRow = 0; + protected TitledGroupBg tradeInfoTitledGroupBg; + private TextField timeLeftTextField; + private ProgressBar timeLeftProgressBar; + private GridPane notificationGridPane; + private Label notificationLabel; + private TitledGroupBg notificationTitledGroupBg; + protected Button openDisputeButton; + private TxIdTextField txIdTextField; + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor, Initialisation + /////////////////////////////////////////////////////////////////////////////////////////// + + protected TradeStepView(PendingTradesViewModel model) { + this.model = model; + preferences = model.dataModel.getPreferences(); + trade = model.getTrade(); + + gridPane = addGridPane(this); + + AnchorPane.setLeftAnchor(this, 0d); + AnchorPane.setRightAnchor(this, 0d); + AnchorPane.setTopAnchor(this, -10d); + AnchorPane.setBottomAnchor(this, 0d); + + txIdChangeListener = (ov, oldValue, newValue) -> txIdTextField.setup(newValue); + + addContent(); + } + + public void doActivate() { + if (txIdTextField != null) { + txIdTextField.setup(model.txIdProperty().get()); + + model.txIdProperty().addListener(txIdChangeListener); + } + + errorMessageSubscription = EasyBind.subscribe(trade.errorMessageProperty(), newValue -> { + if (newValue != null) { + showSupportFields(); + } + }); + + disputeStateSubscription = EasyBind.subscribe(trade.disputeStateProperty(), newValue -> { + if (newValue != null) { + updateDisputeState(newValue); + } + }); + + timer = FxTimer.runPeriodically(Duration.ofSeconds(1), this::updateTimeLeft); + + tradePeriodStateSubscription = EasyBind.subscribe(trade.getTradePeriodStateProperty(), newValue -> { + if (newValue != null) { + updateTradePeriodState(newValue); + } + }); + } + + public void doDeactivate() { + if (txIdTextField != null) { + txIdTextField.cleanup(); + + model.txIdProperty().removeListener(txIdChangeListener); + } + + if (errorMessageSubscription != null) + errorMessageSubscription.unsubscribe(); + + if (disputeStateSubscription != null) + disputeStateSubscription.unsubscribe(); + + if (tradePeriodStateSubscription != null) + tradePeriodStateSubscription.unsubscribe(); + + if (openDisputeButton != null) + openDisputeButton.setOnAction(null); + + if (timer != null) + timer.stop(); + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // Content + /////////////////////////////////////////////////////////////////////////////////////////// + + protected void addContent() { + addTradeInfoBlock(); + addInfoBlock(); + } + + protected void addTradeInfoBlock() { + tradeInfoTitledGroupBg = addTitledGroupBg(gridPane, gridRow, 4, "Trade information"); + txIdTextField = addLabelTxIdTextField(gridPane, gridRow, "Deposit transaction ID:", Layout.FIRST_ROW_DISTANCE).second; + + //TODO + PaymentMethodForm.addAllowedPeriod(gridPane, ++gridRow, model.dataModel.getSellersPaymentAccountContractData(), + model.getOpenDisputeTimeAsFormattedDate()); + + timeLeftTextField = addLabelTextField(gridPane, ++gridRow, "Remaining time:").second; + + timeLeftProgressBar = new ProgressBar(0); + timeLeftProgressBar.setOpacity(0.7); + timeLeftProgressBar.setMinHeight(9); + timeLeftProgressBar.setMaxHeight(9); + timeLeftProgressBar.setMaxWidth(Double.MAX_VALUE); + + GridPane.setRowIndex(timeLeftProgressBar, ++gridRow); + GridPane.setColumnIndex(timeLeftProgressBar, 1); + GridPane.setFillWidth(timeLeftProgressBar, true); + gridPane.getChildren().add(timeLeftProgressBar); + + updateTimeLeft(); + } + + protected void addInfoBlock() { + addTitledGroupBg(gridPane, ++gridRow, 1, getInfoBlockTitle(), Layout.GROUP_DISTANCE); + addMultilineLabel(gridPane, gridRow, getInfoText(), Layout.FIRST_ROW_AND_GROUP_DISTANCE); + } + + protected String getInfoText() { + return ""; + } + + protected String getInfoBlockTitle() { + return ""; + } + + private void updateTimeLeft() { + if (timeLeftTextField != null) { + String remainingTime = model.getRemainingTime(); + timeLeftProgressBar.setProgress(model.getRemainingTimeAsPercentage()); + if (remainingTime != null) { + timeLeftTextField.setText(remainingTime); + if (model.showWarning(model.getTrade()) || model.showDispute(model.getTrade())) { + timeLeftTextField.setStyle("-fx-text-fill: -bs-error-red"); + timeLeftProgressBar.setStyle("-fx-accent: -bs-error-red;"); + } + } else { + timeLeftTextField.setText("Trade not completed in time (" + model.getOpenDisputeTimeAsFormattedDate() + ")"); + timeLeftTextField.setStyle("-fx-text-fill: -bs-error-red"); + timeLeftProgressBar.setStyle("-fx-accent: -bs-error-red;"); + } + } + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // Dispute/warning label and button + /////////////////////////////////////////////////////////////////////////////////////////// + + // We have the dispute button and text field on the left side, but we handle the content here as it + // is trade state specific + public void setNotificationFields(Tuple3 notificationTuple) { + this.notificationGridPane = notificationTuple.first; + this.notificationTitledGroupBg = notificationTuple.second; + this.notificationLabel = notificationTuple.third; + } + + public void setOpenDisputeButton(Button openDisputeButton) { + this.openDisputeButton = openDisputeButton; + } + + private void showDisputeInfoLabel() { + if (notificationGridPane != null) { + notificationGridPane.setVisible(true); + notificationGridPane.setManaged(true); + } + } + + private void showOpenDisputeButton() { + if (openDisputeButton != null) { + openDisputeButton.setVisible(true); + openDisputeButton.setManaged(true); + openDisputeButton.setOnAction(e -> { + openDisputeButton.setDisable(true); + onDisputeOpened(); + setDisputeState(); + model.dataModel.onOpenDispute(); + }); + } + } + + protected void setWarningState() { + if (notificationGridPane != null) { + notificationTitledGroupBg.setText("Warning"); + //notificationGridPane.setId("trade-notification-warning"); + } + } + + protected void setInformationState() { + if (notificationGridPane != null) { + notificationTitledGroupBg.setText("Notification"); + notificationTitledGroupBg.setId("titled-group-bg-warn"); + notificationTitledGroupBg.getLabel().setId("titled-group-bg-label-warn"); + //notificationLabel.setId("titled-group-bg-label-warn"); + } + } + + protected void setDisputeState() { + if (notificationGridPane != null) { + notificationTitledGroupBg.setText("Dispute opened"); + //notificationGridPane.setId("trade-notification-dispute"); + } + } + + protected void setSupportState() { + if (notificationGridPane != null) { + notificationTitledGroupBg.setText("Support ticket opened"); + //notificationGridPane.setId("trade-notification-support"); + } + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // Support + /////////////////////////////////////////////////////////////////////////////////////////// + + private void showSupportFields() { + if (openDisputeButton != null) { + openDisputeButton.setText("Request support"); + openDisputeButton.setId("open-support-button"); + openDisputeButton.setOnAction(e -> model.dataModel.onOpenSupportTicket()); + } + new Popup().warning(trade.errorMessageProperty().getValue() + + "\n\nPlease report the problem to your arbitrator.\n\n" + + "He will forward teh information to the developers to investigate the problem.\n" + + "After the problem has be analyzed you will get back all the funds if they are locked.\n" + + "There will be no arbitration fee charged in case of a software bug.") + .show(); + + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Warning + /////////////////////////////////////////////////////////////////////////////////////////// + + private void showWarning() { + showDisputeInfoLabel(); + + if (notificationLabel != null) + notificationLabel.setText(getWarningText()); + } + + protected String getWarningText() { + return ""; + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Dispute + /////////////////////////////////////////////////////////////////////////////////////////// + + private void onOpenForDispute() { + showDisputeInfoLabel(); + showOpenDisputeButton(); + + if (notificationLabel != null) + notificationLabel.setText(getOpenForDisputeText()); + } + + private void onDisputeOpened() { + showDisputeInfoLabel(); + showOpenDisputeButton(); + applyOnDisputeOpened(); + + + if (openDisputeButton != null) + openDisputeButton.setDisable(true); + } + + protected String getOpenForDisputeText() { + return ""; + } + + protected void applyOnDisputeOpened() { + } + + private void updateDisputeState(Trade.DisputeState disputeState) { + Optional ownDispute; + switch (disputeState) { + case NONE: + break; + case DISPUTE_REQUESTED: + onDisputeOpened(); + ownDispute = model.dataModel.getDisputeManager().findOwnDispute(trade.getId()); + ownDispute.ifPresent(dispute -> { + String msg; + if (dispute.isSupportTicket()) { + setSupportState(); + msg = "You opened already a support ticket.\n" + + "Please communicate in the support section with the arbitrator."; + } else { + setDisputeState(); + msg = "You opened already a dispute.\n" + + "Please communicate in the support section with the arbitrator."; + } + if (notificationLabel != null) + notificationLabel.setText(msg); + }); + + break; + case DISPUTE_STARTED_BY_PEER: + onDisputeOpened(); + ownDispute = model.dataModel.getDisputeManager().findOwnDispute(trade.getId()); + ownDispute.ifPresent(dispute -> { + String msg; + if (dispute.isSupportTicket()) { + setSupportState(); + msg = "Your trading peer opened a support ticket due technical problems.\n" + + "Please communicate in the support section with the arbitrator."; + } else { + setDisputeState(); + msg = "Your trading peer opened a dispute.\n" + + "Please communicate in the support section with the arbitrator."; + } + if (notificationLabel != null) + notificationLabel.setText(msg); + }); + break; + case DISPUTE_CLOSED: + break; + } + } + + private void updateTradePeriodState(Trade.TradePeriodState tradePeriodState) { + if (trade.getDisputeState() != Trade.DisputeState.DISPUTE_REQUESTED && + trade.getDisputeState() != Trade.DisputeState.DISPUTE_STARTED_BY_PEER) { + switch (tradePeriodState) { + case NORMAL: + break; + case HALF_REACHED: + showWarning(); + break; + case TRADE_PERIOD_OVER: + onOpenForDispute(); + break; + } + } + } +} diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/TradeWizardItem.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/TradeWizardItem.java index f41a093d40..a0860b6667 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/TradeWizardItem.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/TradeWizardItem.java @@ -26,13 +26,13 @@ import javafx.scene.control.Button; import javafx.scene.control.Label; public class TradeWizardItem extends Button { - public Class getViewClass() { + public Class getViewClass() { return viewClass; } - private final Class viewClass; + private final Class viewClass; - public TradeWizardItem(Class viewClass, String title) { + public TradeWizardItem(Class viewClass, String title) { this.viewClass = viewClass; setMouseTransparent(true); diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/WaitPaymentReceivedView.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/WaitPaymentReceivedView.java deleted file mode 100644 index 114b2f2285..0000000000 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/WaitPaymentReceivedView.java +++ /dev/null @@ -1,109 +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 . - */ - -package io.bitsquare.gui.main.portfolio.pendingtrades.steps; - -import io.bitsquare.gui.components.TxIdTextField; -import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel; -import io.bitsquare.gui.util.Layout; -import javafx.beans.value.ChangeListener; - -import static io.bitsquare.gui.util.FormBuilder.*; - -public class WaitPaymentReceivedView extends TradeStepDetailsView { - private final ChangeListener txIdChangeListener; - private TxIdTextField txIdTextField; - - /////////////////////////////////////////////////////////////////////////////////////////// - // Constructor, Initialisation - /////////////////////////////////////////////////////////////////////////////////////////// - - public WaitPaymentReceivedView(PendingTradesViewModel model) { - super(model); - - txIdChangeListener = (ov, oldValue, newValue) -> txIdTextField.setup(newValue); - } - - @Override - public void doActivate() { - super.doActivate(); - - model.getTxId().addListener(txIdChangeListener); - txIdTextField.setup(model.getTxId().get()); - } - - @Override - public void doDeactivate() { - super.doDeactivate(); - - model.getTxId().removeListener(txIdChangeListener); - txIdTextField.cleanup(); - } - - - @Override - protected void displayRequestCheckPayment() { - infoLabel.setStyle(" -fx-text-fill: -bs-error-red;"); - infoLabel.setText("The seller still has not confirmed your payment!\n" + - "Please check at your payment processor/bank/blockchain if the payment succeeded.\n" + - "If the seller has not confirmed the receipt of your payment until " + - model.getDateFromBlocks(openDisputeTimeInBlocks) + - " the trade will be investigated by the arbitrator."); - } - - @Override - protected void displayOpenForDisputeForm() { - infoLabel.setStyle(" -fx-text-fill: -bs-error-red;"); - infoLabel.setText("The seller has not confirmed your payment!\n" + - "The max. period for the trade has elapsed (" + - model.getDateFromBlocks(openDisputeTimeInBlocks) + - ") and you need to contact now the arbitrator to investigate the problem."); - - addOpenDisputeButton(); - } - - @Override - protected void disputeInProgress() { - super.disputeInProgress(); - } - - - /////////////////////////////////////////////////////////////////////////////////////////// - // Setters - /////////////////////////////////////////////////////////////////////////////////////////// - - public void setInfoLabelText(String text) { - if (infoLabel != null) - infoLabel.setText(text); - } - - - /////////////////////////////////////////////////////////////////////////////////////////// - // Build view - /////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void buildGridEntries() { - addTitledGroupBg(gridPane, gridRow, 1, "Blockchain confirmation"); - txIdTextField = addLabelTxIdTextField(gridPane, gridRow, "Deposit transaction ID:", Layout.FIRST_ROW_DISTANCE).second; - - infoTitledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 1, "Information", Layout.GROUP_DISTANCE); - infoLabel = addMultilineLabel(gridPane, gridRow, Layout.FIRST_ROW_AND_GROUP_DISTANCE); - } -} - - diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/WaitPayoutFinalizedView.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/WaitPayoutFinalizedView.java deleted file mode 100644 index 21dba0665d..0000000000 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/WaitPayoutFinalizedView.java +++ /dev/null @@ -1,84 +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 . - */ - -package io.bitsquare.gui.main.portfolio.pendingtrades.steps; - -import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel; -import io.bitsquare.gui.util.Layout; - -import static io.bitsquare.gui.util.FormBuilder.addMultilineLabel; -import static io.bitsquare.gui.util.FormBuilder.addTitledGroupBg; - -public class WaitPayoutFinalizedView extends TradeStepDetailsView { - - /////////////////////////////////////////////////////////////////////////////////////////// - // Constructor, Initialisation - /////////////////////////////////////////////////////////////////////////////////////////// - - public WaitPayoutFinalizedView(PendingTradesViewModel model) { - super(model); - } - - @Override - public void doActivate() { - super.doActivate(); - } - - @Override - public void doDeactivate() { - super.doDeactivate(); - } - - public void setInfoLabelText(String text) { - if (infoLabel != null) - infoLabel.setText(text); - } - - @Override - protected void displayRequestCheckPayment() { - // we cannot do anything here, beside restart in case of software bugs - } - - @Override - protected void displayOpenForDisputeForm() { - infoLabel.setStyle(" -fx-text-fill: -bs-error-red;"); - infoLabel.setText("The trading peer has not finalized the payout transaction!\n" + - "The max. period for the trade has elapsed (" + - model.getDateFromBlocks(openDisputeTimeInBlocks) + ")." + - "\nPlease contact now the arbitrator for opening a dispute."); - - addOpenDisputeButton(); - } - - @Override - protected void disputeInProgress() { - super.disputeInProgress(); - } - - - /////////////////////////////////////////////////////////////////////////////////////////// - // Build view - /////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void buildGridEntries() { - infoTitledGroupBg = addTitledGroupBg(gridPane, gridRow, 1, "Information"); - infoLabel = addMultilineLabel(gridPane, gridRow, Layout.FIRST_ROW_DISTANCE); - } -} - - diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/WaitPayoutLockTimeView.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/WaitPayoutLockTimeView.java deleted file mode 100644 index d17dc93187..0000000000 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/WaitPayoutLockTimeView.java +++ /dev/null @@ -1,82 +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 . - */ - -package io.bitsquare.gui.main.portfolio.pendingtrades.steps; - -import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel; -import io.bitsquare.gui.util.Layout; -import javafx.scene.control.TextField; - -import static io.bitsquare.gui.util.FormBuilder.*; - -public class WaitPayoutLockTimeView extends TradeStepDetailsView { - private TextField blockTextField; - private TextField timeTextField; - - - /////////////////////////////////////////////////////////////////////////////////////////// - // Constructor, Initialisation - /////////////////////////////////////////////////////////////////////////////////////////// - - public WaitPayoutLockTimeView(PendingTradesViewModel model) { - super(model); - } - - @Override - public void doActivate() { - super.doActivate(); - } - - @Override - public void doDeactivate() { - super.doDeactivate(); - } - - @Override - protected void updateDateFromBlocks(long bestBlocKHeight) { - long missingBlocks = model.getLockTime() - bestBlocKHeight; - blockTextField.setText(String.valueOf(missingBlocks)); - timeTextField.setText(model.getDateFromBlocks(missingBlocks)); - } - - - /////////////////////////////////////////////////////////////////////////////////////////// - // Setters - /////////////////////////////////////////////////////////////////////////////////////////// - - public void setInfoLabelText(String text) { - if (infoLabel != null) - infoLabel.setText(text); - } - - - /////////////////////////////////////////////////////////////////////////////////////////// - // Build view - /////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void buildGridEntries() { - addTitledGroupBg(gridPane, gridRow, 2, "Payout transaction lock time"); - blockTextField = addLabelTextField(gridPane, gridRow, "Block(s) to wait until unlock:", "", Layout.FIRST_ROW_DISTANCE).second; - timeTextField = addLabelTextField(gridPane, ++gridRow, "Approx. date when payout gets unlocked:").second; - - infoTitledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 1, "Information", Layout.GROUP_DISTANCE); - infoLabel = addMultilineLabel(gridPane, gridRow, Layout.FIRST_ROW_AND_GROUP_DISTANCE); - } -} - - diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/WaitTxInBlockchainView.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/WaitTxInBlockchainView.java deleted file mode 100644 index 8ebe459759..0000000000 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/WaitTxInBlockchainView.java +++ /dev/null @@ -1,83 +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 . - */ - -package io.bitsquare.gui.main.portfolio.pendingtrades.steps; - -import io.bitsquare.gui.components.TxIdTextField; -import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel; -import io.bitsquare.gui.util.Layout; -import javafx.beans.value.ChangeListener; - -import static io.bitsquare.gui.util.FormBuilder.*; - -public class WaitTxInBlockchainView extends TradeStepDetailsView { - private final ChangeListener txIdChangeListener; - private TxIdTextField txIdTextField; - - - /////////////////////////////////////////////////////////////////////////////////////////// - // Constructor, Initialisation - /////////////////////////////////////////////////////////////////////////////////////////// - - public WaitTxInBlockchainView(PendingTradesViewModel model) { - super(model); - - txIdChangeListener = (ov, oldValue, newValue) -> txIdTextField.setup(newValue); - } - - @Override - public void doActivate() { - super.doActivate(); - - model.getTxId().addListener(txIdChangeListener); - txIdTextField.setup(model.getTxId().get()); - } - - @Override - public void doDeactivate() { - super.doDeactivate(); - - model.getTxId().removeListener(txIdChangeListener); - txIdTextField.cleanup(); - } - - - /////////////////////////////////////////////////////////////////////////////////////////// - // Setters - /////////////////////////////////////////////////////////////////////////////////////////// - - public void setInfoLabelText(String text) { - if (infoLabel != null) - infoLabel.setText(text); - } - - - /////////////////////////////////////////////////////////////////////////////////////////// - // Build view - /////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void buildGridEntries() { - addTitledGroupBg(gridPane, gridRow, 1, "Blockchain confirmation"); - txIdTextField = addLabelTxIdTextField(gridPane, gridRow, "Deposit transaction ID:", Layout.FIRST_ROW_DISTANCE).second; - - infoTitledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 1, "Information", Layout.GROUP_DISTANCE); - infoLabel = addMultilineLabel(gridPane, gridRow, Layout.FIRST_ROW_AND_GROUP_DISTANCE); - } -} - - diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep1View.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep1View.java new file mode 100644 index 0000000000..a21e1a50dd --- /dev/null +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep1View.java @@ -0,0 +1,50 @@ +/* + * 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 . + */ + +package io.bitsquare.gui.main.portfolio.pendingtrades.steps.buyer; + +import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel; +import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeStepView; + +public class BuyerStep1View extends TradeStepView { + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor, Initialisation + /////////////////////////////////////////////////////////////////////////////////////////// + + public BuyerStep1View(PendingTradesViewModel model) { + super(model); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Info + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected String getInfoBlockTitle() { + return "Wait for blockchain confirmation"; + } + + @Override + protected String getInfoText() { + return "Deposit transaction has been published.\n" + + "You need to wait for at least one blockchain confirmation."; + } +} + + diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/StartPaymentView.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java similarity index 68% rename from gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/StartPaymentView.java rename to gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java index 6a8a061917..4ff332e292 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/StartPaymentView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java @@ -15,24 +15,21 @@ * along with Bitsquare. If not, see . */ -package io.bitsquare.gui.main.portfolio.pendingtrades.steps; +package io.bitsquare.gui.main.portfolio.pendingtrades.steps.buyer; import io.bitsquare.app.BitsquareApp; import io.bitsquare.common.util.Tuple3; import io.bitsquare.gui.components.TextFieldWithCopyIcon; import io.bitsquare.gui.components.TitledGroupBg; -import io.bitsquare.gui.components.TxIdTextField; import io.bitsquare.gui.components.paymentmethods.*; import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel; +import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeStepView; import io.bitsquare.gui.popups.Popup; import io.bitsquare.gui.util.Layout; +import io.bitsquare.locale.BSResources; import io.bitsquare.payment.PaymentAccountContractData; import io.bitsquare.payment.PaymentMethod; import io.bitsquare.user.PopupId; -import io.bitsquare.user.Preferences; -import javafx.beans.value.ChangeListener; -import javafx.event.ActionEvent; -import javafx.geometry.Insets; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.ProgressIndicator; @@ -40,43 +37,33 @@ import javafx.scene.layout.GridPane; import static io.bitsquare.gui.util.FormBuilder.*; -public class StartPaymentView extends TradeStepDetailsView { - private final Preferences preferences; - private TxIdTextField txIdTextField; +public class BuyerStep2View extends TradeStepView { private Button paymentStartedButton; private Label statusLabel; - - private final ChangeListener txIdChangeListener; private ProgressIndicator statusProgressIndicator; - private TitledGroupBg txConfirmationGroup; - /////////////////////////////////////////////////////////////////////////////////////////// // Constructor, Initialisation /////////////////////////////////////////////////////////////////////////////////////////// - public StartPaymentView(PendingTradesViewModel model) { + public BuyerStep2View(PendingTradesViewModel model) { super(model); - txIdChangeListener = (ov, oldValue, newValue) -> txIdTextField.setup(newValue); - preferences = model.dataModel.getPreferences(); } @Override public void doActivate() { super.doActivate(); - model.getTxId().addListener(txIdChangeListener); - txIdTextField.setup(model.getTxId().get()); - - String key = PopupId.SEND_PAYMENT_INFO; - if (preferences.showAgain(key) && !BitsquareApp.DEV_MODE) { + String id = PopupId.SEND_PAYMENT_INFO; + if (preferences.showAgain(id) && !BitsquareApp.DEV_MODE) { + //TODO use payment method and trade values new Popup().information("You need to transfer now the agreed amount to your trading partner.\n" + "Please take care that you use the exact data presented here, including the reference text\n" + "Please do not click the \"Payment started\" button before you have completed the transfer.\n" + "Make sure that you make the transfer soon to not exceed the trading period.") - .onClose(() -> preferences.dontShowAgain(key)) + .onClose(() -> preferences.dontShowAgain(id)) .show(); } } @@ -85,62 +72,100 @@ public class StartPaymentView extends TradeStepDetailsView { public void doDeactivate() { super.doDeactivate(); - model.getTxId().removeListener(txIdChangeListener); - txIdTextField.cleanup(); removeStatusProgressIndicator(); } - @Override - protected void displayRequestCheckPayment() { - addDisputeInfoLabel(); - infoLabel.setText("You still have not done your payment!\n" + - "If the seller does not receive your payment until " + - model.getDateFromBlocks(openDisputeTimeInBlocks) + - " the trade will be investigated by the arbitrator." - ); - } + /////////////////////////////////////////////////////////////////////////////////////////// + // Content + /////////////////////////////////////////////////////////////////////////////////////////// @Override - protected void displayOpenForDisputeForm() { - addDisputeInfoLabel(); - infoLabel.setText("You have not completed your payment!\n" + + protected void addContent() { + addTradeInfoBlock(); + + PaymentAccountContractData paymentAccountContractData = model.dataModel.getSellersPaymentAccountContractData(); + String paymentMethodName = paymentAccountContractData.getPaymentMethodName(); + TitledGroupBg accountTitledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 1, + "Start payment using " + BSResources.get(paymentAccountContractData.getPaymentMethodName()), + Layout.GROUP_DISTANCE); + TextFieldWithCopyIcon field = addLabelTextFieldWithCopyIcon(gridPane, gridRow, "Amount to transfer:", + model.getFiatAmount(), + Layout.FIRST_ROW_AND_GROUP_DISTANCE).second; + field.setCopyWithoutCurrencyPostFix(true); + + switch (paymentMethodName) { + case PaymentMethod.OK_PAY_ID: + gridRow = OKPayForm.addFormForBuyer(gridPane, gridRow, paymentAccountContractData); + break; + case PaymentMethod.PERFECT_MONEY_ID: + gridRow = PerfectMoneyForm.addFormForBuyer(gridPane, gridRow, paymentAccountContractData); + break; + case PaymentMethod.SEPA_ID: + gridRow = SepaForm.addFormForBuyer(gridPane, gridRow, paymentAccountContractData); + break; + case PaymentMethod.SWISH_ID: + gridRow = SwishForm.addFormForBuyer(gridPane, gridRow, paymentAccountContractData); + break; + case PaymentMethod.ALI_PAY_ID: + gridRow = AliPayForm.addFormForBuyer(gridPane, gridRow, paymentAccountContractData); + break; + case PaymentMethod.BLOCK_CHAINS_ID: + gridRow = BlockChainForm.addFormForBuyer(gridPane, gridRow, paymentAccountContractData); + break; + default: + log.error("Not supported PaymentMethod: " + paymentMethodName); + } + + addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Reference text:", model.getReference()); + + GridPane.setRowSpan(accountTitledGroupBg, gridRow - 3); + + Tuple3 tuple3 = addButtonWithStatus(gridPane, ++gridRow, "Payment started"); + paymentStartedButton = tuple3.first; + paymentStartedButton.setOnAction(e -> onPaymentStarted()); + statusProgressIndicator = tuple3.second; + statusLabel = tuple3.third; + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Warning + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected String getWarningText() { + setWarningState(); + return "You still have not done your " + model.getCurrencyCode() + " payment!\n" + + "Please not that the trade has to be completed until " + + model.getOpenDisputeTimeAsFormattedDate() + + " otherwise the trade will be investigated by the arbitrator."; + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Dispute + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected String getOpenForDisputeText() { + return "You have not completed your payment!\n" + "The max. period for the trade has elapsed (" + - model.getDateFromBlocks(openDisputeTimeInBlocks) + ")." + - "\nPlease contact now the arbitrator for opening a dispute."); - - addOpenDisputeButton(); - GridPane.setMargin(openDisputeButton, new Insets(0, 0, 0, 0)); - GridPane.setColumnIndex(openDisputeButton, 1); + model.getOpenDisputeTimeAsFormattedDate() + ")." + + "\nPlease contact now the arbitrator for opening a dispute."; } @Override - protected void disputeInProgress() { - super.disputeInProgress(); - + protected void applyOnDisputeOpened() { paymentStartedButton.setDisable(true); } - @Override - protected void addDisputeInfoLabel() { - if (infoLabel == null) { - // we replace tx id field as there is not enough space - gridPane.getChildren().removeAll(txConfirmationGroup, txIdTextField); - - infoTitledGroupBg = addTitledGroupBg(gridPane, 0, 1, "Information"); - infoLabel = addMultilineLabel(gridPane, 0, Layout.FIRST_ROW_DISTANCE); - infoLabel.setStyle(" -fx-text-fill: -bs-error-red;"); - // grid does not auto update layout correctly - infoLabel.setMinHeight(70); - } - } /////////////////////////////////////////////////////////////////////////////////////////// // UI Handlers /////////////////////////////////////////////////////////////////////////////////////////// - private void onPaymentStarted(ActionEvent actionEvent) { - log.debug("onPaymentStarted"); + private void onPaymentStarted() { if (model.isBootstrapped()) { String key = PopupId.PAYMENT_SENT; if (preferences.showAgain(key) && !BitsquareApp.DEV_MODE) { @@ -149,7 +174,7 @@ public class StartPaymentView extends TradeStepDetailsView { .dontShowAgainId(key, preferences) .actionButtonText("Yes I have started the payment") .closeButtonText("No") - .onAction(() -> confirmPaymentStarted()) + .onAction(this::confirmPaymentStarted) .show(); } else { confirmPaymentStarted(); @@ -180,9 +205,9 @@ public class StartPaymentView extends TradeStepDetailsView { // In case the first send failed we got the support button displayed. // If it succeeds at a second try we remove the support button again. - if (openSupportTicketButton != null) { - gridPane.getChildren().remove(openSupportTicketButton); - openSupportTicketButton = null; + if (openDisputeButton != null) { + openDisputeButton.setVisible(false); + openDisputeButton.setManaged(false); } }, errorMessage -> { removeStatusProgressIndicator(); @@ -198,55 +223,4 @@ public class StartPaymentView extends TradeStepDetailsView { statusProgressIndicator.setManaged(false); } - - /////////////////////////////////////////////////////////////////////////////////////////// - // Build view - /////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void buildGridEntries() { - txConfirmationGroup = addTitledGroupBg(gridPane, gridRow, 1, "Blockchain confirmation"); - txIdTextField = addLabelTxIdTextField(gridPane, gridRow, "Deposit transaction ID:", Layout.FIRST_ROW_DISTANCE).second; - - TitledGroupBg accountTitledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 1, "Payments details", Layout.GROUP_DISTANCE); - TextFieldWithCopyIcon field = addLabelTextFieldWithCopyIcon(gridPane, gridRow, "Amount to transfer:", model.getFiatAmount(), - Layout.FIRST_ROW_AND_GROUP_DISTANCE).second; - field.setCopyWithoutCurrencyPostFix(true); - PaymentAccountContractData paymentAccountContractData = model.dataModel.getSellersPaymentAccountContractData(); - - String paymentMethodName = paymentAccountContractData.getPaymentMethodName(); - switch (paymentMethodName) { - case PaymentMethod.OK_PAY_ID: - gridRow = OKPayForm.addFormForBuyer(gridPane, gridRow, paymentAccountContractData); - break; - case PaymentMethod.PERFECT_MONEY_ID: - gridRow = PerfectMoneyForm.addFormForBuyer(gridPane, gridRow, paymentAccountContractData); - break; - case PaymentMethod.SEPA_ID: - gridRow = SepaForm.addFormForBuyer(gridPane, gridRow, paymentAccountContractData); - break; - case PaymentMethod.SWISH_ID: - gridRow = SwishForm.addFormForBuyer(gridPane, gridRow, paymentAccountContractData); - break; - case PaymentMethod.ALI_PAY_ID: - gridRow = AliPayForm.addFormForBuyer(gridPane, gridRow, paymentAccountContractData); - break; - case PaymentMethod.BLOCK_CHAINS_ID: - gridRow = BlockChainForm.addFormForBuyer(gridPane, gridRow, paymentAccountContractData); - break; - default: - log.error("Not supported PaymentMethod: " + paymentMethodName); - } - - - addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Reference:", model.getReference()); - - Tuple3 tuple3 = addButtonWithStatus(gridPane, ++gridRow, "Payment started"); - paymentStartedButton = tuple3.first; - paymentStartedButton.setOnAction(this::onPaymentStarted); - statusProgressIndicator = tuple3.second; - statusLabel = tuple3.third; - - GridPane.setRowSpan(accountTitledGroupBg, gridRow - 1); - } } diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep3View.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep3View.java new file mode 100644 index 0000000000..bfc63bf4b0 --- /dev/null +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep3View.java @@ -0,0 +1,87 @@ +/* + * 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 . + */ + +package io.bitsquare.gui.main.portfolio.pendingtrades.steps.buyer; + +import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel; +import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeStepView; +import io.bitsquare.locale.BSResources; + +public class BuyerStep3View extends TradeStepView { + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor, Initialisation + /////////////////////////////////////////////////////////////////////////////////////////// + + public BuyerStep3View(PendingTradesViewModel model) { + super(model); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Info + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected String getInfoBlockTitle() { + return "Wait for seller's payment confirmation"; + } + + @Override + protected String getInfoText() { + return BSResources.get("Waiting for the bitcoin seller's confirmation " + + "for the receipt of the {0} payment.", + model.getCurrencyCode()); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Warning + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected String getWarningText() { + setInformationState(); + String substitute = model.isBlockChainMethod() ? + "on the " + model.getCurrencyCode() + "blockchain" : + "at your payment provider (e.g. bank)"; + return "The seller still has not confirmed your payment!\n" + + "Please check " + substitute + " if the payment sending was successful.\n" + + "If the seller does not confirm the receipt of your payment until " + + model.getOpenDisputeTimeAsFormattedDate() + + " the trade will be investigated by the arbitrator."; + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Dispute + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected String getOpenForDisputeText() { + return "The seller has not confirmed your payment!\n" + + "The max. period for the trade has elapsed (" + + model.getOpenDisputeTimeAsFormattedDate() + + ") and you need to contact now the arbitrator to investigate the problem."; + } + + @Override + protected void applyOnDisputeOpened() { + } +} + + diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep4View.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep4View.java new file mode 100644 index 0000000000..0d6a588a8d --- /dev/null +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep4View.java @@ -0,0 +1,148 @@ +/* + * 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 . + */ + +package io.bitsquare.gui.main.portfolio.pendingtrades.steps.buyer; + +import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel; +import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeStepView; +import io.bitsquare.gui.util.Layout; +import javafx.scene.control.TextField; +import javafx.scene.layout.GridPane; +import org.bitcoinj.core.*; + +import java.util.List; + +import static io.bitsquare.gui.util.FormBuilder.addLabelTextField; + +public class BuyerStep4View extends TradeStepView { + + private TextField blockTextField; + private TextField timeTextField; + private final BlockChainListener blockChainListener; + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor, Initialisation + /////////////////////////////////////////////////////////////////////////////////////////// + + public BuyerStep4View(PendingTradesViewModel model) { + super(model); + + blockChainListener = new BlockChainListener() { + @Override + public void notifyNewBestBlock(StoredBlock block) throws VerificationException { + updateDateFromBlockHeight(block.getHeight()); + } + + @Override + public void reorganize(StoredBlock splitPoint, List oldBlocks, List newBlocks) throws VerificationException { + updateDateFromBlockHeight(model.getBestChainHeight()); + } + + @Override + public boolean isTransactionRelevant(Transaction tx) throws ScriptException { + return false; + } + + @Override + public void receiveFromBlock(Transaction tx, StoredBlock block, AbstractBlockChain.NewBlockType blockType, int relativityOffset) throws + VerificationException { + } + + @Override + public boolean notifyTransactionIsInBlock(Sha256Hash txHash, StoredBlock block, AbstractBlockChain.NewBlockType blockType, int relativityOffset) + throws VerificationException { + return false; + } + }; + } + + @Override + public void doActivate() { + super.doActivate(); + + model.addBlockChainListener(blockChainListener); + } + + @Override + public void doDeactivate() { + super.doDeactivate(); + + model.removeBlockChainListener(blockChainListener); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Content + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected void addContent() { + addTradeInfoBlock(); + blockTextField = addLabelTextField(gridPane, gridRow, "Block(s) to wait until lock time elapsed:", "", Layout.FIRST_ROW_DISTANCE).second; + timeTextField = addLabelTextField(gridPane, ++gridRow, "Approx. date when payout gets unlocked:").second; + GridPane.setRowSpan(tradeInfoTitledGroupBg, 4); + + addInfoBlock(); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Info + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected String getInfoBlockTitle() { + return "Wait until payout lock time is over"; + } + + @Override + protected String getInfoText() { + return "The payout transaction is signed and finalized by both parties.\n" + + "For reducing bank chargeback risks the payout transaction is blocked by a lock time.\n" + + "After that lock time is over the payout transaction gets published and you receive " + + "your bitcoin."; + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Warning + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected String getWarningText() { + setInformationState(); + return "The payout transaction is still blocked by the lock time!\n" + + "If the trade has not been completed on " + + model.getOpenDisputeTimeAsFormattedDate() + + " the arbitrator will investigate."; + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // Private + /////////////////////////////////////////////////////////////////////////////////////////// + + private void updateDateFromBlockHeight(long bestBlocKHeight) { + long missingBlocks = model.getLockTime() - bestBlocKHeight; + blockTextField.setText(String.valueOf(missingBlocks)); + timeTextField.setText(model.getOpenDisputeTimeAsFormattedDate()); + } + + +} + + diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/CompletedView.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep5View.java similarity index 85% rename from gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/CompletedView.java rename to gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep5View.java index eb415bb463..23fad8af68 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/CompletedView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep5View.java @@ -15,13 +15,14 @@ * along with Bitsquare. If not, see . */ -package io.bitsquare.gui.main.portfolio.pendingtrades.steps; +package io.bitsquare.gui.main.portfolio.pendingtrades.steps.buyer; import io.bitsquare.app.BitsquareApp; import io.bitsquare.common.UserThread; import io.bitsquare.common.util.Tuple2; import io.bitsquare.gui.components.InputTextField; import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel; +import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeStepView; import io.bitsquare.gui.util.Layout; import javafx.beans.value.ChangeListener; import javafx.scene.control.Button; @@ -30,7 +31,7 @@ import javafx.scene.control.TextField; import static io.bitsquare.gui.util.FormBuilder.*; -public class CompletedView extends TradeStepDetailsView { +public class BuyerStep5View extends TradeStepView { private final ChangeListener focusedPropertyListener; private Label btcTradeAmountLabel; @@ -48,7 +49,7 @@ public class CompletedView extends TradeStepDetailsView { // Constructor, Initialisation /////////////////////////////////////////////////////////////////////////////////////////// - public CompletedView(PendingTradesViewModel model) { + public BuyerStep5View(PendingTradesViewModel model) { super(model); focusedPropertyListener = (ov, oldValue, newValue) -> { @@ -87,12 +88,12 @@ public class CompletedView extends TradeStepDetailsView { /////////////////////////////////////////////////////////////////////////////////////////// - // Build view + // Content /////////////////////////////////////////////////////////////////////////////////////////// @Override - protected void buildGridEntries() { - addTitledGroupBg(gridPane, gridRow, 4, "Summary", 0); + protected void addContent() { + addTitledGroupBg(gridPane, gridRow, 4, "Summary of completed trade ", 0); Tuple2 btcTradeAmountPair = addLabelTextField(gridPane, gridRow, "You have bought:", "", Layout.FIRST_ROW_DISTANCE); btcTradeAmountLabel = btcTradeAmountPair.first; btcTradeAmountTextField = btcTradeAmountPair.second; @@ -120,6 +121,21 @@ public class CompletedView extends TradeStepDetailsView { withdrawAddressTextField.setText("mxAkWWaQBqwqcYstKzqLku3kzR6pbu2zHq"); } + /////////////////////////////////////////////////////////////////////////////////////////// + // Warning + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected String getWarningText() { + setInformationState(); + return "The trade took a bit longer as expected but has been completed successfully in the allowed trade period."; + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Setters + /////////////////////////////////////////////////////////////////////////////////////////// + public void setBtcTradeAmountLabelText(String text) { btcTradeAmountLabel.setText(text); } diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep1View.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep1View.java new file mode 100644 index 0000000000..4bc411c3db --- /dev/null +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep1View.java @@ -0,0 +1,51 @@ +/* + * 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 . + */ + +package io.bitsquare.gui.main.portfolio.pendingtrades.steps.seller; + +import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel; +import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeStepView; + +public class SellerStep1View extends TradeStepView { + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor, Initialisation + /////////////////////////////////////////////////////////////////////////////////////////// + + public SellerStep1View(PendingTradesViewModel model) { + super(model); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Info + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected String getInfoBlockTitle() { + return "Wait for blockchain confirmation"; + } + + @Override + protected String getInfoText() { + return "Deposit transaction has been published.\n" + + "The bitcoin buyer need to wait for at least one blockchain confirmation before " + + "starting the payment."; + } +} + + diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep2View.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep2View.java new file mode 100644 index 0000000000..b82996b78a --- /dev/null +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep2View.java @@ -0,0 +1,84 @@ +/* + * 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 . + */ + +package io.bitsquare.gui.main.portfolio.pendingtrades.steps.seller; + +import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel; +import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeStepView; +import io.bitsquare.locale.BSResources; + +public class SellerStep2View extends TradeStepView { + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor, Initialisation + /////////////////////////////////////////////////////////////////////////////////////////// + + public SellerStep2View(PendingTradesViewModel model) { + super(model); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Info + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected String getInfoBlockTitle() { + return "Wait for blockchain confirmation"; + } + + @Override + protected String getInfoText() { + return BSResources.get( + "The deposit transaction has at least one blockchain confirmation.\n" + + "You need to wait until that the bitcoin buyer starts the {0} payment.", + model.getCurrencyCode()); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Warning + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected String getWarningText() { + setInformationState(); + return "The buyer still has not done the " + model.getCurrencyCode() + " payment!\n" + + "You need to wait until he starts the payment.\n" + + "If the trade has not been completed on " + + model.getOpenDisputeTimeAsFormattedDate() + + " the arbitrator will investigate."; + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // Dispute + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected String getOpenForDisputeText() { + return "The buyer has not started his payment!\n" + + "The max. allowed period for the trade has elapsed.\n" + + "Please contact the arbitrator for opening a dispute."; + } + + @Override + protected void applyOnDisputeOpened() { + } + +} + + diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/ConfirmPaymentReceivedView.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java similarity index 66% rename from gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/ConfirmPaymentReceivedView.java rename to gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java index 122f72aace..f4a3410686 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/ConfirmPaymentReceivedView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java @@ -15,17 +15,15 @@ * along with Bitsquare. If not, see . */ -package io.bitsquare.gui.main.portfolio.pendingtrades.steps; +package io.bitsquare.gui.main.portfolio.pendingtrades.steps.seller; import io.bitsquare.app.BitsquareApp; -import io.bitsquare.gui.components.TxIdTextField; import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel; +import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeStepView; import io.bitsquare.gui.popups.Popup; -import io.bitsquare.gui.util.Layout; +import io.bitsquare.locale.BSResources; import io.bitsquare.user.PopupId; import io.bitsquare.user.Preferences; -import javafx.beans.value.ChangeListener; -import javafx.event.ActionEvent; import javafx.geometry.HPos; import javafx.geometry.Insets; import javafx.scene.control.Button; @@ -34,12 +32,8 @@ import javafx.scene.control.ProgressIndicator; import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; -import static io.bitsquare.gui.util.FormBuilder.*; +public class SellerStep3View extends TradeStepView { -public class ConfirmPaymentReceivedView extends TradeStepDetailsView { - private final ChangeListener txIdChangeListener; - - private TxIdTextField txIdTextField; private Button confirmFiatReceivedButton; private Label statusLabel; private ProgressIndicator statusProgressIndicator; @@ -49,63 +43,120 @@ public class ConfirmPaymentReceivedView extends TradeStepDetailsView { // Constructor, Initialisation /////////////////////////////////////////////////////////////////////////////////////////// - public ConfirmPaymentReceivedView(PendingTradesViewModel model) { + public SellerStep3View(PendingTradesViewModel model) { super(model); - txIdChangeListener = (ov, oldValue, newValue) -> txIdTextField.setup(newValue); } @Override public void doActivate() { super.doActivate(); - - model.getTxId().addListener(txIdChangeListener); - txIdTextField.setup(model.getTxId().get()); } @Override public void doDeactivate() { super.doDeactivate(); - model.getTxId().removeListener(txIdChangeListener); - txIdTextField.cleanup(); statusProgressIndicator.setProgress(0); } + /////////////////////////////////////////////////////////////////////////////////////////// + // Content + /////////////////////////////////////////////////////////////////////////////////////////// + @Override - protected void displayRequestCheckPayment() { - infoLabel.setStyle(" -fx-text-fill: -bs-error-red;"); - infoLabel.setText("You still have not confirmed the receipt of the payment!\n" + - "Please check you payment processor or bank account to see if the payment has arrived.\n" + + protected void addContent() { + super.addContent(); + + HBox hBox = new HBox(); + hBox.setSpacing(10); + confirmFiatReceivedButton = new Button("Confirm payment receipt"); + confirmFiatReceivedButton.setDefaultButton(true); + confirmFiatReceivedButton.setOnAction(e -> onPaymentReceived()); + + statusProgressIndicator = new ProgressIndicator(0); + statusProgressIndicator.setPrefHeight(24); + statusProgressIndicator.setPrefWidth(24); + statusProgressIndicator.setVisible(false); + + statusLabel = new Label(); + statusLabel.setPadding(new Insets(5, 0, 0, 0)); + + hBox.getChildren().addAll(confirmFiatReceivedButton, statusProgressIndicator, statusLabel); + GridPane.setRowIndex(hBox, ++gridRow); + GridPane.setColumnIndex(hBox, 0); + GridPane.setHalignment(hBox, HPos.LEFT); + GridPane.setMargin(hBox, new Insets(15, 0, 0, 0)); + gridPane.getChildren().add(hBox); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Info + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected String getInfoBlockTitle() { + return "Confirm payment receipt"; + } + + @Override + protected String getInfoText() { + if (model.isBlockChainMethod()) { + return BSResources.get("The bitcoin buyer has started the {0} payment.\n" + + "Check for blockchain confirmations at your Altcoin wallet or block explorer and " + + "confirm the payment when you have sufficient blockchain confirmations.", + model.getCurrencyCode()); + } else { + return BSResources.get("The bitcoin buyer has started the {0} payment.\n" + + "Check at your payment account (e.g. bank account) and confirm when you have " + + "received the payment.", + model.getCurrencyCode()); + } + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Warning + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected String getWarningText() { + setWarningState(); + String substitute = model.isBlockChainMethod() ? + "on the " + model.getCurrencyCode() + "blockchain" : + "at your payment provider (e.g. bank)"; + return "You still have not confirmed the receipt of the payment!\n" + + "Please check " + substitute + " if you have received the payment.\n" + "If you do not confirm receipt until " + - model.getDateFromBlocks(openDisputeTimeInBlocks) + - " the trade will be investigated by the arbitrator."); + model.getOpenDisputeTimeAsFormattedDate() + + " the trade will be investigated by the arbitrator."; } + + /////////////////////////////////////////////////////////////////////////////////////////// + // Dispute + /////////////////////////////////////////////////////////////////////////////////////////// + @Override - protected void displayOpenForDisputeForm() { - infoLabel.setStyle(" -fx-text-fill: -bs-error-red;"); - infoLabel.setText("You have not confirmed the receipt of the payment!\n" + + protected String getOpenForDisputeText() { + return "You have not confirmed the receipt of the payment!\n" + "The max. period for the trade has elapsed (" + - model.getDateFromBlocks(openDisputeTimeInBlocks) + ")." + - "\nPlease contact now the arbitrator for opening a dispute."); - - addOpenDisputeButton(); - GridPane.setMargin(openDisputeButton, new Insets(0, 0, 0, 0)); + model.getOpenDisputeTimeAsFormattedDate() + ")." + + "\nPlease contact now the arbitrator for opening a dispute."; } @Override - protected void disputeInProgress() { - super.disputeInProgress(); - + protected void applyOnDisputeOpened() { confirmFiatReceivedButton.setDisable(true); } + //////////////////////////////////////////////////////////////////////////////////////// // UI Handlers /////////////////////////////////////////////////////////////////////////////////////////// - private void onPaymentReceived(ActionEvent actionEvent) { + private void onPaymentReceived() { log.debug("onPaymentReceived"); if (model.isBootstrapped()) { Preferences preferences = model.dataModel.getPreferences(); @@ -118,7 +169,7 @@ public class ConfirmPaymentReceivedView extends TradeStepDetailsView { .dontShowAgainId(key, preferences) .actionButtonText("Yes I have received the payment") .closeButtonText("No") - .onAction(() -> confirmPaymentReceived()) + .onAction(this::confirmPaymentReceived) .show(); } else { confirmPaymentReceived(); @@ -138,51 +189,6 @@ public class ConfirmPaymentReceivedView extends TradeStepDetailsView { model.fiatPaymentReceived(); } - - - /////////////////////////////////////////////////////////////////////////////////////////// - // Setters - /////////////////////////////////////////////////////////////////////////////////////////// - - public void setInfoLabelText(String text) { - if (infoLabel != null) - infoLabel.setText(text); - } - - - /////////////////////////////////////////////////////////////////////////////////////////// - // Build view - /////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void buildGridEntries() { - addTitledGroupBg(gridPane, gridRow, 1, "Blockchain confirmation"); - txIdTextField = addLabelTxIdTextField(gridPane, gridRow, "Deposit transaction ID:", Layout.FIRST_ROW_DISTANCE).second; - - infoTitledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 1, "Information", Layout.GROUP_DISTANCE); - infoLabel = addMultilineLabel(gridPane, gridRow, Layout.FIRST_ROW_AND_GROUP_DISTANCE); - - HBox hBox = new HBox(); - hBox.setSpacing(10); - confirmFiatReceivedButton = new Button("Confirm payment receipt"); - confirmFiatReceivedButton.setDefaultButton(true); - confirmFiatReceivedButton.setOnAction(this::onPaymentReceived); - - statusProgressIndicator = new ProgressIndicator(0); - statusProgressIndicator.setPrefHeight(24); - statusProgressIndicator.setPrefWidth(24); - statusProgressIndicator.setVisible(false); - - statusLabel = new Label(); - statusLabel.setPadding(new Insets(5, 0, 0, 0)); - - hBox.getChildren().addAll(confirmFiatReceivedButton, statusProgressIndicator, statusLabel); - GridPane.setRowIndex(hBox, ++gridRow); - GridPane.setColumnIndex(hBox, 0); - GridPane.setHalignment(hBox, HPos.LEFT); - GridPane.setMargin(hBox, new Insets(15, 0, 0, 0)); - gridPane.getChildren().add(hBox); - } } diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/WaitPaymentStartedView.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep4aView.java similarity index 50% rename from gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/WaitPaymentStartedView.java rename to gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep4aView.java index 2f38794046..91c96d1f6a 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/WaitPaymentStartedView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep4aView.java @@ -15,35 +15,20 @@ * along with Bitsquare. If not, see . */ -package io.bitsquare.gui.main.portfolio.pendingtrades.steps; +package io.bitsquare.gui.main.portfolio.pendingtrades.steps.seller; import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel; +import io.bitsquare.gui.main.portfolio.pendingtrades.steps.buyer.BuyerStep4View; -public class WaitPaymentStartedView extends WaitTxInBlockchainView { - public WaitPaymentStartedView(PendingTradesViewModel model) { +public class SellerStep4aView extends BuyerStep4View { + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor, Initialisation + /////////////////////////////////////////////////////////////////////////////////////////// + + public SellerStep4aView(PendingTradesViewModel model) { super(model); } - - @Override - public void doActivate() { - super.doActivate(); - } - - @Override - protected void displayRequestCheckPayment() { - // does not make sense to warn here - } - - @Override - protected void displayOpenForDisputeForm() { - addDisputeInfoLabel(); - infoLabel.setText("The buyer has not started his payment!\n" + - "The max. period for the trade has elapsed (" + - model.getDateFromBlocks(openDisputeTimeInBlocks) + ")." + - "\nPlease contact the arbitrator for opening a dispute."); - - addOpenDisputeButton(); - } } diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep4bView.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep4bView.java new file mode 100644 index 0000000000..33e58ed87a --- /dev/null +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep4bView.java @@ -0,0 +1,83 @@ +/* + * 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 . + */ + +package io.bitsquare.gui.main.portfolio.pendingtrades.steps.seller; + +import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel; +import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeStepView; + +public class SellerStep4bView extends TradeStepView { + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor, Initialisation + /////////////////////////////////////////////////////////////////////////////////////////// + + public SellerStep4bView(PendingTradesViewModel model) { + super(model); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Info + /////////////////////////////////////////////////////////////////////////////////////////// + + + @Override + protected String getInfoBlockTitle() { + return "Wait until peer finalizes the payout transaction"; + } + + @Override + protected String getInfoText() { + return "We requested from the trading peer to sign and finalize the payout transaction.\n" + + "It might be that the other peer is offline, so we need to wait until he finalize the " + + "transaction when he goes online again."; + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // Warning + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected String getWarningText() { + setInformationState(); + return "The trading peer has not finalized the payout transaction!\n" + + "He might be offline. You need to wait until he finalizes the payout transaction.\n" + + "If the trade has not been completed on " + + model.getOpenDisputeTimeAsFormattedDate() + + " the arbitrator will investigate."; + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Dispute + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected String getOpenForDisputeText() { + return "The trading peer has not finalized the payout transaction!\n" + + "The max. period for the trade has elapsed (" + + model.getOpenDisputeTimeAsFormattedDate() + ").\n" + + "Please contact now the arbitrator for opening a dispute."; + } + + @Override + protected void applyOnDisputeOpened() { + } +} + + diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep5View.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep5View.java new file mode 100644 index 0000000000..0c02014f9f --- /dev/null +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep5View.java @@ -0,0 +1,32 @@ +/* + * 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 . + */ + +package io.bitsquare.gui.main.portfolio.pendingtrades.steps.seller; + +import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel; +import io.bitsquare.gui.main.portfolio.pendingtrades.steps.buyer.BuyerStep5View; + +public class SellerStep5View extends BuyerStep5View { + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor, Initialisation + /////////////////////////////////////////////////////////////////////////////////////////// + + public SellerStep5View(PendingTradesViewModel model) { + super(model); + } +} diff --git a/jtorproxy/src/main/java/io/nucleo/net/TorNode.java b/jtorproxy/src/main/java/io/nucleo/net/TorNode.java index 9ab8688df5..ebe5e55397 100644 --- a/jtorproxy/src/main/java/io/nucleo/net/TorNode.java +++ b/jtorproxy/src/main/java/io/nucleo/net/TorNode.java @@ -23,6 +23,11 @@ public abstract class TorNode + + + +