Simplify the trade complete summary dialog

This commit is contained in:
jmacxx 2021-12-24 14:22:59 -06:00
parent 670c5418ee
commit 1162060e28
No known key found for this signature in database
GPG key ID: 155297BABFE94A1B
2 changed files with 28 additions and 190 deletions

View file

@ -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

View file

@ -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();
completedTradeLabel.setText(Res.get("portfolio.pending.step5_buyer.groupTitle")); 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"));
}
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,49 +103,28 @@ 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());
addCompactTopLabelTextField(gridPane, gridRow, getBtcTradeAmountLabel(), model.getTradeVolume(), Layout.TWICE_FIRST_ROW_DISTANCE); if (trade.getDisputeState().isNotDisputed()) {
addCompactTopLabelTextField(gridPane, ++gridRow, getFiatTradeAmountLabel(), model.getFiatVolume()); addCompactTopLabelTextField(gridPane, gridRow, getBtcTradeAmountLabel(), model.getTradeVolume(), Layout.TWICE_FIRST_ROW_DISTANCE);
addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("portfolio.pending.step5_buyer.refunded"), model.getSecurityDeposit()); addCompactTopLabelTextField(gridPane, ++gridRow, getFiatTradeAmountLabel(), model.getFiatVolume());
addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("portfolio.pending.step5_buyer.tradeFee"), model.getTradeFee()); addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("portfolio.pending.step5_buyer.refunded"), model.getSecurityDeposit());
final String miningFee = model.dataModel.isMaker() ? addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("portfolio.pending.step5_buyer.tradeFee"), model.getTradeFee());
Res.get("portfolio.pending.step5_buyer.makersMiningFee") : final String miningFee = model.dataModel.isMaker() ?
Res.get("portfolio.pending.step5_buyer.takersMiningFee"); Res.get("portfolio.pending.step5_buyer.makersMiningFee") :
addCompactTopLabelTextField(gridPane, ++gridRow, miningFee, model.getTxFee()); Res.get("portfolio.pending.step5_buyer.takersMiningFee");
withdrawTitledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 1, Res.get("portfolio.pending.step5_buyer.withdrawBTC"), Layout.COMPACT_GROUP_DISTANCE); addCompactTopLabelTextField(gridPane, ++gridRow, miningFee, model.getTxFee());
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");
} }