Refactor pending trades steps subviews

This commit is contained in:
Manfred Karrer 2016-02-07 09:51:13 +01:00
parent de79eba7f0
commit e2e5a6864f
28 changed files with 1398 additions and 1097 deletions

View File

@ -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<PendingTradesViewModel.BuyerState> 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();
}
}

View File

@ -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<Transaction> candidates = new ArrayList<>();
List<Transaction> 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() {

View File

@ -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<Coin> tradeAmountProperty() {
if (trade instanceof Trade)
return trade.tradeAmountProperty();
else
return trade.tradeAmountProperty();
return trade.tradeAmountProperty();
}
public ReadOnlyObjectProperty<Fiat> tradeVolumeProperty() {
if (trade instanceof Trade)
return trade.tradeVolumeProperty();
else
return trade.tradeVolumeProperty();
}
public Date getDate() {
return trade.getDate();
return trade.tradeVolumeProperty();
}
public String getId() {

View File

@ -18,7 +18,7 @@
-->
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.cell.*?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.VBox?>
<VBox fx:id="root" fx:controller="io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesView"
@ -34,11 +34,7 @@
<PropertyValueFactory property="id"/>
</cellValueFactory>
</TableColumn>
<TableColumn text="Date/Time" fx:id="dateColumn" minWidth="130">
<cellValueFactory>
<PropertyValueFactory property="date"/>
</cellValueFactory>
</TableColumn>
<TableColumn text="Date/Time" fx:id="dateColumn" minWidth="130"/>
<TableColumn text="Trade amount in BTC" fx:id="tradeAmountColumn" minWidth="130">
<cellValueFactory>
<PropertyValueFactory property="tradeAmount"/>

View File

@ -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<VBox, PendingTradesViewModel> {
@ -54,13 +53,9 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
@FXML
TableView<PendingTradesListItem> table;
@FXML
TableColumn<PendingTradesListItem, Fiat> priceColumn;
TableColumn<PendingTradesListItem, Fiat> priceColumn, tradeVolumeColumn;
@FXML
TableColumn<PendingTradesListItem, Fiat> tradeVolumeColumn;
@FXML
TableColumn<PendingTradesListItem, PendingTradesListItem> roleColumn, paymentMethodColumn, idColumn;
@FXML
TableColumn<PendingTradesListItem, Date> dateColumn;
TableColumn<PendingTradesListItem, PendingTradesListItem> roleColumn, paymentMethodColumn, idColumn, dateColumn;
@FXML
TableColumn<PendingTradesListItem, Coin> tradeAmountColumn;
@ -119,31 +114,35 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
currentTradeChangeListener = (observable, oldValue, newValue) -> {
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 ActivatableViewAndModel<VBox, PendingTrad
else
currentSubView = new BuyerSubView(model);
}
currentSubView.setMinHeight(420);
currentSubView.setMinHeight(430);
VBox.setVgrow(currentSubView, Priority.ALWAYS);
root.getChildren().add(1, currentSubView);
@ -249,18 +248,33 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
}
private void setDateColumnCellFactory() {
dateColumn.setCellFactory(TextFieldTableCell.<PendingTradesListItem, Date>forTableColumn(
new StringConverter<Date>() {
dateColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
dateColumn.setCellFactory(
new Callback<TableColumn<PendingTradesListItem, PendingTradesListItem>, TableCell<PendingTradesListItem,
PendingTradesListItem>>() {
@Override
public String toString(Date value) {
return model.formatDate(value);
public TableCell<PendingTradesListItem, PendingTradesListItem> call(
TableColumn<PendingTradesListItem, PendingTradesListItem> column) {
return new TableCell<PendingTradesListItem, PendingTradesListItem>() {
@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() {

View File

@ -167,7 +167,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
return sellerState;
}
public ReadOnlyStringProperty getTxId() {
public ReadOnlyStringProperty txIdProperty() {
return txId;
}
@ -244,6 +244,32 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
return formatter.formatFiatWithCode(value);
}
public String getRemainingTime() {
return formatter.getPeriodBetweenBlockHeights(getBestChainHeight(),
dataModel.getTrade().getOpenDisputeTimeAsBlockHeight());
}
public double getRemainingTimeAsPercentage() {
double remainingBlocks = dataModel.getTrade().getOpenDisputeTimeAsBlockHeight() - getBestChainHeight();
double maxPeriod = dataModel.getTrade().getOffer().getPaymentMethod().getMaxTradePeriod();
if (maxPeriod != 0)
return 1 - remainingBlocks / maxPeriod;
else
return 0;
}
String getDate(PendingTradesListItem item) {
return formatter.formatDateTime(item.getTrade().getDate());
}
public boolean showWarning(Trade trade) {
return getBestChainHeight() >= 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<PendingTrad
return dataModel.getCheckPaymentTimeAsBlockHeight();
}
public long getOpenDisputeTimeAsBlockHeight() {
private long getOpenDisputeTimeAsBlockHeight() {
return dataModel.getOpenDisputeTimeAsBlockHeight();
}
@ -297,8 +323,8 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
return dataModel.getBestChainHeight();
}
public String getDateFromBlocks(long missingBlocks) {
return formatter.getDateFromBlocks(missingBlocks);
public String getOpenDisputeTimeAsFormattedDate() {
return formatter.addBlocksToNowDateFormatted(getOpenDisputeTimeAsBlockHeight() - getBestChainHeight());
}
public String getReference() {

View File

@ -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.seller.*;
import javafx.beans.value.ChangeListener;
public class SellerSubView extends TradeSubView {
private TradeWizardItem waitTxInBlockchain;
private TradeWizardItem waitPaymentStarted;
private TradeWizardItem confirmPaymentReceived;
private TradeWizardItem waitPayoutUnlock;
private TradeWizardItem completed;
private TradeWizardItem step1;
private TradeWizardItem step2;
private TradeWizardItem step3;
private TradeWizardItem step4;
private TradeWizardItem step5;
private final ChangeListener<PendingTradesViewModel.SellerState> 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();
}
}

View File

@ -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<GridPane, TitledGroupBg, Label> 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<? extends TradeStepDetailsView> viewClass) {
private void createAndAddTradeStepView(Class<? extends TradeStepView> 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();
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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<StoredBlock> oldBlocks, List<StoredBlock> 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<Dispute> 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() {
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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<String> 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<GridPane, TitledGroupBg, Label> 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<Dispute> 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;
}
}
}
}

View File

@ -26,13 +26,13 @@ import javafx.scene.control.Button;
import javafx.scene.control.Label;
public class TradeWizardItem extends Button {
public Class<? extends TradeStepDetailsView> getViewClass() {
public Class<? extends TradeStepView> getViewClass() {
return viewClass;
}
private final Class<? extends TradeStepDetailsView> viewClass;
private final Class<? extends TradeStepView> viewClass;
public TradeWizardItem(Class<? extends TradeStepDetailsView> viewClass, String title) {
public TradeWizardItem(Class<? extends TradeStepView> viewClass, String title) {
this.viewClass = viewClass;
setMouseTransparent(true);

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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<String> 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);
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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);
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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);
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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<String> 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);
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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.";
}
}

View File

@ -15,24 +15,21 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
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<String> 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<Button, ProgressIndicator, Label> 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<Button, ProgressIndicator, Label> tuple3 = addButtonWithStatus(gridPane, ++gridRow, "Payment started");
paymentStartedButton = tuple3.first;
paymentStartedButton.setOnAction(this::onPaymentStarted);
statusProgressIndicator = tuple3.second;
statusLabel = tuple3.third;
GridPane.setRowSpan(accountTitledGroupBg, gridRow - 1);
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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() {
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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<StoredBlock> oldBlocks, List<StoredBlock> 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());
}
}

View File

@ -15,13 +15,14 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
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<Boolean> 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<Label, TextField> 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);
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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.";
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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() {
}
}

View File

@ -15,17 +15,15 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
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<String> 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);
}
}

View File

@ -15,35 +15,20 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
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();
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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() {
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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);
}
}

View File

@ -23,6 +23,11 @@ public abstract class TorNode<M extends OnionProxyManager, C extends OnionProxyC
private static final Logger log = LoggerFactory.getLogger(TorNode.class);
private final OnionProxyManager tor;
public Socks5Proxy getProxy() {
return proxy;
}
private final Socks5Proxy proxy;
public TorNode(M mgr) throws IOException {

View File

@ -26,6 +26,10 @@
<root level="TRACE">
<appender-ref ref="CONSOLE_APPENDER"/>
</root>
<logger name="io.bitsquare.storage.Storage" level="WARN"/>
<logger name="io.bitsquare.storage.FileManager" level="WARN"/>
<!-- <logger name="io.bitsquare.p2p.peers.PeerGroup" level="INFO"/>
<logger name="io.bitsquare.p2p.P2PService" level="INFO"/>
<logger name="io.bitsquare.p2p.storage.ProtectedExpirableDataStorage" level="INFO"/>