mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-25 07:27:18 +01:00
Simplify the trade complete summary dialog
This commit is contained in:
parent
670c5418ee
commit
1162060e28
2 changed files with 28 additions and 190 deletions
|
@ -898,6 +898,8 @@ portfolio.pending.step3_seller.onPaymentReceived.signer=IMPORTANT: By confirming
|
||||||
you should delay confirmation of the payment as long as possible to reduce the risk of a chargeback.
|
you should delay confirmation of the payment as long as possible to reduce the risk of a chargeback.
|
||||||
|
|
||||||
portfolio.pending.step5_buyer.groupTitle=Summary of completed trade
|
portfolio.pending.step5_buyer.groupTitle=Summary of completed trade
|
||||||
|
portfolio.pending.step5_buyer.groupTitle.mediated=This trade was resolved by mediation
|
||||||
|
portfolio.pending.step5_buyer.groupTitle.arbitrated=This trade was resolved by arbitration
|
||||||
portfolio.pending.step5_buyer.tradeFee=Trade fee
|
portfolio.pending.step5_buyer.tradeFee=Trade fee
|
||||||
portfolio.pending.step5_buyer.makersMiningFee=Mining fee
|
portfolio.pending.step5_buyer.makersMiningFee=Mining fee
|
||||||
portfolio.pending.step5_buyer.takersMiningFee=Total mining fees
|
portfolio.pending.step5_buyer.takersMiningFee=Total mining fees
|
||||||
|
|
|
@ -18,8 +18,6 @@
|
||||||
package bisq.desktop.main.portfolio.pendingtrades.steps.buyer;
|
package bisq.desktop.main.portfolio.pendingtrades.steps.buyer;
|
||||||
|
|
||||||
import bisq.desktop.components.AutoTooltipButton;
|
import bisq.desktop.components.AutoTooltipButton;
|
||||||
import bisq.desktop.components.AutoTooltipLabel;
|
|
||||||
import bisq.desktop.components.InputTextField;
|
|
||||||
import bisq.desktop.components.TitledGroupBg;
|
import bisq.desktop.components.TitledGroupBg;
|
||||||
import bisq.desktop.main.MainView;
|
import bisq.desktop.main.MainView;
|
||||||
import bisq.desktop.main.overlays.notifications.Notification;
|
import bisq.desktop.main.overlays.notifications.Notification;
|
||||||
|
@ -31,26 +29,13 @@ import bisq.desktop.main.portfolio.pendingtrades.PendingTradesViewModel;
|
||||||
import bisq.desktop.main.portfolio.pendingtrades.steps.TradeStepView;
|
import bisq.desktop.main.portfolio.pendingtrades.steps.TradeStepView;
|
||||||
import bisq.desktop.util.Layout;
|
import bisq.desktop.util.Layout;
|
||||||
|
|
||||||
import bisq.core.btc.exceptions.AddressEntryException;
|
|
||||||
import bisq.core.btc.exceptions.InsufficientFundsException;
|
|
||||||
import bisq.core.btc.model.AddressEntry;
|
import bisq.core.btc.model.AddressEntry;
|
||||||
import bisq.core.btc.wallet.BtcWalletService;
|
|
||||||
import bisq.core.btc.wallet.Restrictions;
|
|
||||||
import bisq.core.locale.Res;
|
import bisq.core.locale.Res;
|
||||||
import bisq.core.trade.txproof.AssetTxProofResult;
|
import bisq.core.trade.txproof.AssetTxProofResult;
|
||||||
import bisq.core.user.DontShowAgainLookup;
|
import bisq.core.user.DontShowAgainLookup;
|
||||||
import bisq.core.util.coin.CoinFormatter;
|
|
||||||
import bisq.core.util.coin.CoinUtil;
|
|
||||||
import bisq.core.util.validation.BtcAddressValidator;
|
|
||||||
|
|
||||||
import bisq.common.UserThread;
|
import bisq.common.UserThread;
|
||||||
import bisq.common.app.DevEnv;
|
import bisq.common.app.DevEnv;
|
||||||
import bisq.common.handlers.FaultHandler;
|
|
||||||
import bisq.common.handlers.ResultHandler;
|
|
||||||
|
|
||||||
import org.bitcoinj.core.AddressFormatException;
|
|
||||||
import org.bitcoinj.core.Coin;
|
|
||||||
import org.bitcoinj.core.Transaction;
|
|
||||||
|
|
||||||
import com.jfoenix.controls.JFXBadge;
|
import com.jfoenix.controls.JFXBadge;
|
||||||
|
|
||||||
|
@ -63,20 +48,13 @@ import javafx.scene.layout.Priority;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
|
|
||||||
import org.bouncycastle.crypto.params.KeyParameter;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static bisq.desktop.util.FormBuilder.addCompactTopLabelTextField;
|
import static bisq.desktop.util.FormBuilder.addCompactTopLabelTextField;
|
||||||
import static bisq.desktop.util.FormBuilder.addInputTextField;
|
|
||||||
import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
|
|
||||||
|
|
||||||
public class BuyerStep4View extends TradeStepView {
|
public class BuyerStep4View extends TradeStepView {
|
||||||
// private final ChangeListener<Boolean> focusedPropertyListener;
|
|
||||||
|
|
||||||
private InputTextField withdrawAddressTextField, withdrawMemoTextField;
|
private Button closeButton;
|
||||||
private Button withdrawToExternalWalletButton, useSavingsWalletButton;
|
|
||||||
private TitledGroupBg withdrawTitledGroupBg;
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Constructor, Initialisation
|
// Constructor, Initialisation
|
||||||
|
@ -108,8 +86,13 @@ public class BuyerStep4View extends TradeStepView {
|
||||||
gridPane.getColumnConstraints().get(1).setHgrow(Priority.SOMETIMES);
|
gridPane.getColumnConstraints().get(1).setHgrow(Priority.SOMETIMES);
|
||||||
|
|
||||||
TitledGroupBg completedTradeLabel = new TitledGroupBg();
|
TitledGroupBg completedTradeLabel = new TitledGroupBg();
|
||||||
|
if (trade.getDisputeState().isMediated()) {
|
||||||
|
completedTradeLabel.setText(Res.get("portfolio.pending.step5_buyer.groupTitle.mediated"));
|
||||||
|
} else if (trade.getDisputeState().isArbitrated()) {
|
||||||
|
completedTradeLabel.setText(Res.get("portfolio.pending.step5_buyer.groupTitle.arbitrated"));
|
||||||
|
} else {
|
||||||
completedTradeLabel.setText(Res.get("portfolio.pending.step5_buyer.groupTitle"));
|
completedTradeLabel.setText(Res.get("portfolio.pending.step5_buyer.groupTitle"));
|
||||||
|
}
|
||||||
JFXBadge autoConfBadge = new JFXBadge(new Label(""), Pos.BASELINE_RIGHT);
|
JFXBadge autoConfBadge = new JFXBadge(new Label(""), Pos.BASELINE_RIGHT);
|
||||||
autoConfBadge.setText(Res.get("portfolio.pending.autoConf"));
|
autoConfBadge.setText(Res.get("portfolio.pending.autoConf"));
|
||||||
autoConfBadge.getStyleClass().add("auto-conf");
|
autoConfBadge.getStyleClass().add("auto-conf");
|
||||||
|
@ -120,6 +103,7 @@ public class BuyerStep4View extends TradeStepView {
|
||||||
GridPane.setRowSpan(hBox2, 5);
|
GridPane.setRowSpan(hBox2, 5);
|
||||||
autoConfBadge.setVisible(AssetTxProofResult.COMPLETED == trade.getAssetTxProofResult());
|
autoConfBadge.setVisible(AssetTxProofResult.COMPLETED == trade.getAssetTxProofResult());
|
||||||
|
|
||||||
|
if (trade.getDisputeState().isNotDisputed()) {
|
||||||
addCompactTopLabelTextField(gridPane, gridRow, getBtcTradeAmountLabel(), model.getTradeVolume(), Layout.TWICE_FIRST_ROW_DISTANCE);
|
addCompactTopLabelTextField(gridPane, gridRow, getBtcTradeAmountLabel(), model.getTradeVolume(), Layout.TWICE_FIRST_ROW_DISTANCE);
|
||||||
addCompactTopLabelTextField(gridPane, ++gridRow, getFiatTradeAmountLabel(), model.getFiatVolume());
|
addCompactTopLabelTextField(gridPane, ++gridRow, getFiatTradeAmountLabel(), model.getFiatVolume());
|
||||||
addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("portfolio.pending.step5_buyer.refunded"), model.getSecurityDeposit());
|
addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("portfolio.pending.step5_buyer.refunded"), model.getSecurityDeposit());
|
||||||
|
@ -128,41 +112,19 @@ public class BuyerStep4View extends TradeStepView {
|
||||||
Res.get("portfolio.pending.step5_buyer.makersMiningFee") :
|
Res.get("portfolio.pending.step5_buyer.makersMiningFee") :
|
||||||
Res.get("portfolio.pending.step5_buyer.takersMiningFee");
|
Res.get("portfolio.pending.step5_buyer.takersMiningFee");
|
||||||
addCompactTopLabelTextField(gridPane, ++gridRow, miningFee, model.getTxFee());
|
addCompactTopLabelTextField(gridPane, ++gridRow, miningFee, model.getTxFee());
|
||||||
withdrawTitledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 1, Res.get("portfolio.pending.step5_buyer.withdrawBTC"), Layout.COMPACT_GROUP_DISTANCE);
|
}
|
||||||
withdrawTitledGroupBg.getStyleClass().add("last");
|
|
||||||
addCompactTopLabelTextField(gridPane, gridRow, Res.get("portfolio.pending.step5_buyer.amount"), model.getPayoutAmount(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
|
||||||
|
|
||||||
withdrawAddressTextField = addInputTextField(gridPane, ++gridRow, Res.get("portfolio.pending.step5_buyer.withdrawToAddress"));
|
closeButton = new AutoTooltipButton(Res.get("shared.close"));
|
||||||
withdrawAddressTextField.setManaged(false);
|
closeButton.setDefaultButton(true);
|
||||||
withdrawAddressTextField.setVisible(false);
|
closeButton.getStyleClass().add("action-button");
|
||||||
|
GridPane.setRowIndex(closeButton, ++gridRow);
|
||||||
|
GridPane.setMargin(closeButton, new Insets(Layout.GROUP_DISTANCE, 10, 0, 0));
|
||||||
|
gridPane.getChildren().add(closeButton);
|
||||||
|
|
||||||
withdrawMemoTextField = addInputTextField(gridPane, ++gridRow,
|
closeButton.setOnAction(e -> {
|
||||||
Res.get("funds.withdrawal.memoLabel", Res.getBaseCurrencyCode()));
|
|
||||||
withdrawMemoTextField.setPromptText(Res.get("funds.withdrawal.memo"));
|
|
||||||
withdrawMemoTextField.setManaged(false);
|
|
||||||
withdrawMemoTextField.setVisible(false);
|
|
||||||
|
|
||||||
HBox hBox = new HBox();
|
|
||||||
hBox.setSpacing(10);
|
|
||||||
useSavingsWalletButton = new AutoTooltipButton(Res.get("portfolio.pending.step5_buyer.moveToBisqWallet"));
|
|
||||||
useSavingsWalletButton.setDefaultButton(true);
|
|
||||||
useSavingsWalletButton.getStyleClass().add("action-button");
|
|
||||||
Label label = new AutoTooltipLabel(Res.get("shared.OR"));
|
|
||||||
label.setPadding(new Insets(5, 0, 0, 0));
|
|
||||||
withdrawToExternalWalletButton = new AutoTooltipButton(Res.get("portfolio.pending.step5_buyer.withdrawExternal"));
|
|
||||||
withdrawToExternalWalletButton.setDefaultButton(false);
|
|
||||||
hBox.getChildren().addAll(useSavingsWalletButton, label, withdrawToExternalWalletButton);
|
|
||||||
GridPane.setRowIndex(hBox, ++gridRow);
|
|
||||||
GridPane.setMargin(hBox, new Insets(5, 10, 0, 0));
|
|
||||||
gridPane.getChildren().add(hBox);
|
|
||||||
|
|
||||||
useSavingsWalletButton.setOnAction(e -> {
|
|
||||||
handleTradeCompleted();
|
handleTradeCompleted();
|
||||||
model.dataModel.tradeManager.onTradeCompleted(trade);
|
model.dataModel.tradeManager.onTradeCompleted(trade);
|
||||||
});
|
});
|
||||||
withdrawToExternalWalletButton.setOnAction(e -> {
|
|
||||||
onWithdrawal();
|
|
||||||
});
|
|
||||||
|
|
||||||
String key = "tradeCompleted" + trade.getId();
|
String key = "tradeCompleted" + trade.getId();
|
||||||
if (!DevEnv.isDevMode() && DontShowAgainLookup.showAgain(key)) {
|
if (!DevEnv.isDevMode() && DontShowAgainLookup.showAgain(key)) {
|
||||||
|
@ -174,128 +136,8 @@ public class BuyerStep4View extends TradeStepView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onWithdrawal() {
|
|
||||||
withdrawAddressTextField.setManaged(true);
|
|
||||||
withdrawAddressTextField.setVisible(true);
|
|
||||||
withdrawMemoTextField.setManaged(true);
|
|
||||||
withdrawMemoTextField.setVisible(true);
|
|
||||||
GridPane.setRowSpan(withdrawTitledGroupBg, 3);
|
|
||||||
withdrawToExternalWalletButton.setDefaultButton(true);
|
|
||||||
useSavingsWalletButton.setDefaultButton(false);
|
|
||||||
withdrawToExternalWalletButton.getStyleClass().add("action-button");
|
|
||||||
useSavingsWalletButton.getStyleClass().remove("action-button");
|
|
||||||
|
|
||||||
withdrawToExternalWalletButton.setOnAction(e -> {
|
|
||||||
if (model.dataModel.isReadyForTxBroadcast()) {
|
|
||||||
reviewWithdrawal();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void reviewWithdrawal() {
|
|
||||||
Coin amount = trade.getPayoutAmount();
|
|
||||||
BtcWalletService walletService = model.dataModel.btcWalletService;
|
|
||||||
|
|
||||||
AddressEntry fromAddressesEntry = walletService.getOrCreateAddressEntry(trade.getId(), AddressEntry.Context.TRADE_PAYOUT);
|
|
||||||
String fromAddresses = fromAddressesEntry.getAddressString();
|
|
||||||
String toAddresses = withdrawAddressTextField.getText();
|
|
||||||
if (new BtcAddressValidator().validate(toAddresses).isValid) {
|
|
||||||
Coin balance = walletService.getBalanceForAddress(fromAddressesEntry.getAddress());
|
|
||||||
try {
|
|
||||||
Transaction feeEstimationTransaction = walletService.getFeeEstimationTransaction(fromAddresses, toAddresses, amount, AddressEntry.Context.TRADE_PAYOUT);
|
|
||||||
Coin fee = feeEstimationTransaction.getFee();
|
|
||||||
Coin receiverAmount = amount.subtract(fee);
|
|
||||||
if (balance.isZero()) {
|
|
||||||
new Popup().warning(Res.get("portfolio.pending.step5_buyer.alreadyWithdrawn")).show();
|
|
||||||
model.dataModel.tradeManager.onTradeCompleted(trade);
|
|
||||||
} else {
|
|
||||||
if (toAddresses.isEmpty()) {
|
|
||||||
validateWithdrawAddress();
|
|
||||||
} else if (Restrictions.isAboveDust(receiverAmount)) {
|
|
||||||
CoinFormatter formatter = model.btcFormatter;
|
|
||||||
int txVsize = feeEstimationTransaction.getVsize();
|
|
||||||
double feePerVbyte = CoinUtil.getFeePerVbyte(fee, txVsize);
|
|
||||||
double vkb = txVsize / 1000d;
|
|
||||||
String recAmount = formatter.formatCoinWithCode(receiverAmount);
|
|
||||||
new Popup().headLine(Res.get("portfolio.pending.step5_buyer.confirmWithdrawal"))
|
|
||||||
.confirmation(Res.get("shared.sendFundsDetailsWithFee",
|
|
||||||
formatter.formatCoinWithCode(amount),
|
|
||||||
fromAddresses,
|
|
||||||
toAddresses,
|
|
||||||
formatter.formatCoinWithCode(fee),
|
|
||||||
feePerVbyte,
|
|
||||||
vkb,
|
|
||||||
recAmount))
|
|
||||||
.actionButtonText(Res.get("shared.yes"))
|
|
||||||
.onAction(() -> doWithdrawal(amount, fee))
|
|
||||||
.closeButtonText(Res.get("shared.cancel"))
|
|
||||||
.onClose(() -> {
|
|
||||||
useSavingsWalletButton.setDisable(false);
|
|
||||||
withdrawToExternalWalletButton.setDisable(false);
|
|
||||||
})
|
|
||||||
.show();
|
|
||||||
} else {
|
|
||||||
new Popup().warning(Res.get("portfolio.pending.step5_buyer.amountTooLow")).show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (AddressFormatException e) {
|
|
||||||
validateWithdrawAddress();
|
|
||||||
} catch (AddressEntryException e) {
|
|
||||||
log.error(e.getMessage());
|
|
||||||
} catch (InsufficientFundsException e) {
|
|
||||||
log.error(e.getMessage());
|
|
||||||
e.printStackTrace();
|
|
||||||
new Popup().warning(e.getMessage()).show();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
new Popup().warning(Res.get("validation.btc.invalidAddress")).show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doWithdrawal(Coin amount, Coin fee) {
|
|
||||||
String toAddress = withdrawAddressTextField.getText();
|
|
||||||
ResultHandler resultHandler = this::handleTradeCompleted;
|
|
||||||
FaultHandler faultHandler = (errorMessage, throwable) -> {
|
|
||||||
useSavingsWalletButton.setDisable(false);
|
|
||||||
withdrawToExternalWalletButton.setDisable(false);
|
|
||||||
if (throwable != null && throwable.getMessage() != null)
|
|
||||||
new Popup().error(errorMessage + "\n\n" + throwable.getMessage()).show();
|
|
||||||
else
|
|
||||||
new Popup().error(errorMessage).show();
|
|
||||||
};
|
|
||||||
if (model.dataModel.btcWalletService.isEncrypted()) {
|
|
||||||
UserThread.runAfter(() -> model.dataModel.walletPasswordWindow.onAesKey(aesKey ->
|
|
||||||
doWithdrawRequest(toAddress, amount, fee, aesKey, resultHandler, faultHandler))
|
|
||||||
.show(), 300, TimeUnit.MILLISECONDS);
|
|
||||||
} else
|
|
||||||
doWithdrawRequest(toAddress, amount, fee, null, resultHandler, faultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doWithdrawRequest(String toAddress,
|
|
||||||
Coin amount,
|
|
||||||
Coin fee,
|
|
||||||
KeyParameter aesKey,
|
|
||||||
ResultHandler resultHandler,
|
|
||||||
FaultHandler faultHandler) {
|
|
||||||
useSavingsWalletButton.setDisable(true);
|
|
||||||
withdrawToExternalWalletButton.setDisable(true);
|
|
||||||
String memo = withdrawMemoTextField.getText();
|
|
||||||
if (memo.isEmpty()) {
|
|
||||||
memo = null;
|
|
||||||
}
|
|
||||||
model.dataModel.onWithdrawRequest(toAddress,
|
|
||||||
amount,
|
|
||||||
fee,
|
|
||||||
aesKey,
|
|
||||||
memo,
|
|
||||||
resultHandler,
|
|
||||||
faultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleTradeCompleted() {
|
private void handleTradeCompleted() {
|
||||||
useSavingsWalletButton.setDisable(true);
|
closeButton.setDisable(true);
|
||||||
withdrawToExternalWalletButton.setDisable(true);
|
|
||||||
model.dataModel.btcWalletService.swapTradeEntryToAvailableEntry(trade.getId(), AddressEntry.Context.TRADE_PAYOUT);
|
model.dataModel.btcWalletService.swapTradeEntryToAvailableEntry(trade.getId(), AddressEntry.Context.TRADE_PAYOUT);
|
||||||
|
|
||||||
openTradeFeedbackWindow();
|
openTradeFeedbackWindow();
|
||||||
|
@ -328,12 +170,6 @@ public class BuyerStep4View extends TradeStepView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateWithdrawAddress() {
|
|
||||||
withdrawAddressTextField.setValidator(model.btcAddressValidator);
|
|
||||||
withdrawAddressTextField.requestFocus();
|
|
||||||
useSavingsWalletButton.requestFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String getBtcTradeAmountLabel() {
|
protected String getBtcTradeAmountLabel() {
|
||||||
return Res.get("portfolio.pending.step5_buyer.bought");
|
return Res.get("portfolio.pending.step5_buyer.bought");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue