mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-24 15:10:44 +01:00
Remove handling of failed trades. If a trade is in an invalid state (tx missing) or has an error message set we show in the pending trades view a red trash icon for moving the trade to failed trades.
The info icon next to the trade ID is then a warning icon (should be red but css is not my best friend) and if opening trade details window we also color the missing txs red with a warn icon and tooltip. When clicking the trash button a popup is displayed with detail info. At failed trades there is a "undo" icon for reverting the trade back to pending (if user wants to open mediation, etc). All the automatic handling of the failed trades and popups are removed as it never worked well and just confused users... In next commits we will add more instructions what a user should/can do for diff. error cases. TradeManger: - Remove all the failed checks at initPendingTrade. - Remove tradesWithoutDepositTx - Remove tradesForStatistics as it was never read - Remove cleanUpAddressEntries - Rename addTradeToClosedTrades to onTradeCompleted TxIdTextField accepts a null for tx ID and shows then red colored N/A and a warning icon. HyperlinkWithIcon exposed the icon to be accessible for style change. DebugWindow was updated for one variation of the trade protocol (other is missing still). Trade detail window show now always all 4 mandatory txs. Beside that this commit has some cleanups and null pointer fixes (when testing error scenarios i got those NP).
This commit is contained in:
parent
03023567a8
commit
f6eefef1ae
25 changed files with 375 additions and 251 deletions
|
@ -267,8 +267,11 @@ public class AccountAgeWitnessService {
|
|||
|
||||
private Optional<AccountAgeWitness> findTradePeerWitness(Trade trade) {
|
||||
TradingPeer tradingPeer = trade.getProcessModel().getTradingPeer();
|
||||
return (tradingPeer.getPaymentAccountPayload() == null || tradingPeer.getPubKeyRing() == null) ?
|
||||
Optional.empty() : findWitness(tradingPeer.getPaymentAccountPayload(), tradingPeer.getPubKeyRing());
|
||||
return (tradingPeer == null ||
|
||||
tradingPeer.getPaymentAccountPayload() == null ||
|
||||
tradingPeer.getPubKeyRing() == null) ?
|
||||
Optional.empty() :
|
||||
findWitness(tradingPeer.getPaymentAccountPayload(), tradingPeer.getPubKeyRing());
|
||||
}
|
||||
|
||||
private Optional<AccountAgeWitness> getWitnessByHash(byte[] hash) {
|
||||
|
|
|
@ -767,7 +767,6 @@ public class BisqSetup {
|
|||
rejectedTxErrorMessageHandler.accept(Res.get("popup.warning.trade.txRejected",
|
||||
finalDetails, trade.getShortId(), txId));
|
||||
}
|
||||
tradeManager.addTradeToFailedTrades(trade);
|
||||
}, 1);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -61,7 +61,6 @@ import org.bouncycastle.crypto.params.KeyParameter;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
|
|
@ -37,8 +37,8 @@ import bisq.core.support.messages.SupportMessage;
|
|||
import bisq.core.trade.Trade;
|
||||
import bisq.core.trade.TradeManager;
|
||||
import bisq.core.trade.closed.ClosedTradableManager;
|
||||
import bisq.core.trade.protocol.MediationProtocol;
|
||||
import bisq.core.trade.protocol.ProcessModel;
|
||||
import bisq.core.trade.protocol.TradeProtocol;
|
||||
|
||||
import bisq.network.p2p.AckMessageSourceType;
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
|
@ -234,7 +234,7 @@ public final class MediationManager extends DisputeManager<MediationDisputeList>
|
|||
ProcessModel processModel = trade.getProcessModel();
|
||||
processModel.setBuyerPayoutAmountFromMediation(buyerPayoutAmount.value);
|
||||
processModel.setSellerPayoutAmountFromMediation(sellerPayoutAmount.value);
|
||||
TradeProtocol tradeProtocol = trade.getTradeProtocol();
|
||||
MediationProtocol tradeProtocol = (MediationProtocol) trade.getTradeProtocol();
|
||||
|
||||
trade.setMediationResultState(MediationResultState.MEDIATION_RESULT_ACCEPTED);
|
||||
|
||||
|
|
|
@ -403,6 +403,8 @@ public abstract class Trade implements Tradable, Model {
|
|||
transient protected TradeProtocol tradeProtocol;
|
||||
@Nullable
|
||||
transient private Transaction depositTx;
|
||||
@Getter
|
||||
transient private boolean isInitialized;
|
||||
|
||||
// Added in v1.2.0
|
||||
@Nullable
|
||||
|
@ -704,6 +706,8 @@ public abstract class Trade implements Tradable, Model {
|
|||
// Clone to avoid ConcurrentModificationException. We remove items at the applyMailboxMessage call...
|
||||
HashSet<DecryptedMessageWithPubKey> set = new HashSet<>(decryptedMessageWithPubKeySet);
|
||||
set.forEach(msg -> tradeProtocol.applyMailboxMessage(msg));
|
||||
|
||||
isInitialized = true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -744,8 +748,14 @@ public abstract class Trade implements Tradable, Model {
|
|||
|
||||
@Nullable
|
||||
public Transaction getDelayedPayoutTx() {
|
||||
return getDelayedPayoutTx(processModel.getBtcWalletService());
|
||||
}
|
||||
|
||||
// If called from a not initialized trade (or a closed or failed trade)
|
||||
// we need to pass the btcWalletService
|
||||
@Nullable
|
||||
public Transaction getDelayedPayoutTx(BtcWalletService btcWalletService) {
|
||||
if (delayedPayoutTx == null) {
|
||||
BtcWalletService btcWalletService = processModel.getBtcWalletService();
|
||||
if (btcWalletService == null) {
|
||||
log.warn("btcWalletService is null. You might call that method before the tradeManager has " +
|
||||
"initialized all trades");
|
||||
|
@ -944,16 +954,20 @@ public abstract class Trade implements Tradable, Model {
|
|||
|
||||
@Nullable
|
||||
public Volume getTradeVolume() {
|
||||
if (getTradeAmount() != null && getTradePrice() != null) {
|
||||
Volume volumeByAmount = getTradePrice().getVolumeByAmount(getTradeAmount());
|
||||
if (offer != null) {
|
||||
if (offer.getPaymentMethod().getId().equals(PaymentMethod.HAL_CASH_ID))
|
||||
volumeByAmount = OfferUtil.getAdjustedVolumeForHalCash(volumeByAmount);
|
||||
else if (CurrencyUtil.isFiatCurrency(offer.getCurrencyCode()))
|
||||
volumeByAmount = OfferUtil.getRoundedFiatVolume(volumeByAmount);
|
||||
try {
|
||||
if (getTradeAmount() != null && getTradePrice() != null) {
|
||||
Volume volumeByAmount = getTradePrice().getVolumeByAmount(getTradeAmount());
|
||||
if (offer != null) {
|
||||
if (offer.getPaymentMethod().getId().equals(PaymentMethod.HAL_CASH_ID))
|
||||
volumeByAmount = OfferUtil.getAdjustedVolumeForHalCash(volumeByAmount);
|
||||
else if (CurrencyUtil.isFiatCurrency(offer.getCurrencyCode()))
|
||||
volumeByAmount = OfferUtil.getRoundedFiatVolume(volumeByAmount);
|
||||
}
|
||||
return volumeByAmount;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return volumeByAmount;
|
||||
} else {
|
||||
} catch (Throwable ignore) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,15 +82,12 @@ import javafx.beans.property.LongProperty;
|
|||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleLongProperty;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
import org.bouncycastle.crypto.params.KeyParameter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
@ -137,14 +134,11 @@ public class TradeManager implements PersistedDataHost {
|
|||
private TradableList<Trade> tradableList;
|
||||
@Getter
|
||||
private final BooleanProperty pendingTradesInitialized = new SimpleBooleanProperty();
|
||||
private List<Trade> tradesForStatistics;
|
||||
@Setter
|
||||
@Nullable
|
||||
private ErrorMessageHandler takeOfferRequestErrorMessageHandler;
|
||||
@Getter
|
||||
private final LongProperty numPendingTrades = new SimpleLongProperty();
|
||||
@Getter
|
||||
private final ObservableList<Trade> tradesWithoutDepositTx = FXCollections.observableArrayList();
|
||||
private final DumpDelayedPayoutTx dumpDelayedPayoutTx;
|
||||
@Getter
|
||||
private final boolean allowFaultyDelayedTxs;
|
||||
|
@ -283,65 +277,16 @@ public class TradeManager implements PersistedDataHost {
|
|||
}
|
||||
|
||||
private void initPendingTrades() {
|
||||
List<Trade> addTradeToFailedTradesList = new ArrayList<>();
|
||||
List<Trade> removePreparedTradeList = new ArrayList<>();
|
||||
tradesForStatistics = new ArrayList<>();
|
||||
tradableList.forEach(trade -> {
|
||||
if (trade.isDepositPublished() ||
|
||||
(trade.isTakerFeePublished() && !trade.hasFailed())) {
|
||||
initPendingTrade(trade);
|
||||
} else if (trade.isTakerFeePublished() && !trade.isFundsLockedIn()) {
|
||||
addTradeToFailedTradesList.add(trade);
|
||||
trade.appendErrorMessage("Invalid state: trade.isTakerFeePublished() && !trade.isFundsLockedIn()");
|
||||
} else {
|
||||
removePreparedTradeList.add(trade);
|
||||
}
|
||||
|
||||
if (trade.getDepositTx() == null) {
|
||||
log.warn("Deposit tx for trader with ID {} is null at initPendingTrades. " +
|
||||
"This can happen for valid transaction in rare cases (e.g. after a SPV resync). " +
|
||||
"We leave it to the user to move the trade to failed trades if the problem persists.",
|
||||
trade.getId());
|
||||
tradesWithoutDepositTx.add(trade);
|
||||
}
|
||||
|
||||
try {
|
||||
TradeDataValidation.validatePayoutTx(trade,
|
||||
trade.getDelayedPayoutTx(),
|
||||
daoFacade,
|
||||
btcWalletService);
|
||||
} catch (TradeDataValidation.ValidationException e) {
|
||||
log.warn("Delayed payout tx exception, trade {}, exception {}", trade.getId(), e.getMessage());
|
||||
if (!allowFaultyDelayedTxs) {
|
||||
// We move it to failed trades so it cannot be continued.
|
||||
log.warn("We move the trade with ID '{}' to failed trades", trade.getId());
|
||||
addTradeToFailedTradesList.add(trade);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// If we have a closed trade where the deposit tx is still not confirmed we move it to failed trades as the
|
||||
// payout tx cannot be valid as well in this case. As the trade do not progress without confirmation of the
|
||||
// deposit tx this should normally not happen. If we detect such a trade at start up (done in BisqSetup) we
|
||||
// show a popup telling the user to do a SPV resync.
|
||||
closedTradableManager.getClosedTradables().stream()
|
||||
.filter(tradable -> tradable instanceof Trade)
|
||||
.map(tradable -> (Trade) tradable)
|
||||
.filter(Trade::isFundsLockedIn)
|
||||
.forEach(addTradeToFailedTradesList::add);
|
||||
|
||||
addTradeToFailedTradesList.forEach(closedTradableManager::remove);
|
||||
|
||||
addTradeToFailedTradesList.forEach(this::addTradeToFailedTrades);
|
||||
|
||||
removePreparedTradeList.forEach(this::removePreparedTrade);
|
||||
|
||||
cleanUpAddressEntries();
|
||||
|
||||
tradableList.forEach(this::initPendingTrade);
|
||||
pendingTradesInitialized.set(true);
|
||||
}
|
||||
|
||||
private void initPendingTrade(Trade trade) {
|
||||
initTrade(trade, trade.getProcessModel().isUseSavingsWallet(),
|
||||
trade.getProcessModel().getFundsNeededForTrade());
|
||||
|
||||
trade.updateDepositTxFromWallet();
|
||||
}
|
||||
|
||||
public void onUserConfirmedFiatPaymentReceived(SellerTrade sellerTrade,
|
||||
ResultHandler resultHandler,
|
||||
|
@ -349,32 +294,10 @@ public class TradeManager implements PersistedDataHost {
|
|||
sellerTrade.onFiatPaymentReceived(resultHandler, errorMessageHandler);
|
||||
}
|
||||
|
||||
private void initPendingTrade(Trade trade) {
|
||||
initTrade(trade, trade.getProcessModel().isUseSavingsWallet(),
|
||||
trade.getProcessModel().getFundsNeededForTrade());
|
||||
trade.updateDepositTxFromWallet();
|
||||
tradesForStatistics.add(trade);
|
||||
}
|
||||
|
||||
private void onTradesChanged() {
|
||||
this.numPendingTrades.set(tradableList.getList().size());
|
||||
}
|
||||
|
||||
private void cleanUpAddressEntries() {
|
||||
// We check if we have address entries which are not in our pending trades and clean up those entries.
|
||||
// They might be either from closed or failed trades or from trades we do not have at all in our data base files.
|
||||
Set<String> activeTrades = getTradableList().stream()
|
||||
.map(Tradable::getId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
btcWalletService.getAddressEntriesForTrade().stream()
|
||||
.filter(e -> !activeTrades.contains(e.getOfferId()))
|
||||
.forEach(e -> {
|
||||
log.warn("We found an outdated addressEntry for trade {}: entry={}", e.getOfferId(), e);
|
||||
btcWalletService.resetAddressEntriesForPendingTrade(e.getOfferId());
|
||||
});
|
||||
}
|
||||
|
||||
private void handlePayDepositRequest(InputsForDepositTxRequest inputsForDepositTxRequest, NodeAddress peer) {
|
||||
log.info("Received PayDepositRequest from {} with tradeId {} and uid {}",
|
||||
peer, inputsForDepositTxRequest.getTradeId(), inputsForDepositTxRequest.getUid());
|
||||
|
@ -421,8 +344,6 @@ public class TradeManager implements PersistedDataHost {
|
|||
});
|
||||
} else {
|
||||
// TODO respond
|
||||
//(RequestDepositTxInputsMessage)message.
|
||||
// messageService.sendEncryptedMessage(peerAddress,messageWithPubKey.getMessage().);
|
||||
log.debug("We received a take offer request but don't have that offer anymore.");
|
||||
}
|
||||
}
|
||||
|
@ -581,7 +502,7 @@ public class TradeManager implements PersistedDataHost {
|
|||
public void onSuccess(@javax.annotation.Nullable Transaction transaction) {
|
||||
if (transaction != null) {
|
||||
log.debug("onWithdraw onSuccess tx ID:" + transaction.getTxId().toString());
|
||||
addTradeToClosedTrades(trade);
|
||||
onTradeCompleted(trade);
|
||||
trade.setState(Trade.State.WITHDRAW_COMPLETED);
|
||||
trade.getTradeProtocol().onWithdrawCompleted();
|
||||
resultHandler.handleResult();
|
||||
|
@ -605,20 +526,26 @@ public class TradeManager implements PersistedDataHost {
|
|||
}
|
||||
|
||||
// If trade was completed (closed without fault but might be closed by a dispute) we move it to the closed trades
|
||||
public void addTradeToClosedTrades(Trade trade) {
|
||||
public void onTradeCompleted(Trade trade) {
|
||||
removeTrade(trade);
|
||||
closedTradableManager.add(trade);
|
||||
|
||||
cleanUpAddressEntries();
|
||||
// TODO The address entry should have been removed already. Check and if its the case remove that.
|
||||
btcWalletService.resetAddressEntriesForPendingTrade(trade.getId());
|
||||
}
|
||||
|
||||
// If trade is in already in critical state (if taker role: taker fee; both roles: after deposit published)
|
||||
// we move the trade to failedTradesManager
|
||||
public void addTradeToFailedTrades(Trade trade) {
|
||||
public void moveTradeToFailedTrades(Trade trade) {
|
||||
removeTrade(trade);
|
||||
failedTradesManager.add(trade);
|
||||
}
|
||||
|
||||
cleanUpAddressEntries();
|
||||
public void addFailedTradeToPending(Trade trade) {
|
||||
if (!trade.isInitialized()) {
|
||||
initPendingTrade(trade);
|
||||
}
|
||||
tradableList.add(trade);
|
||||
}
|
||||
|
||||
// If trade still has funds locked up it might come back from failed trades
|
||||
|
@ -652,15 +579,6 @@ public class TradeManager implements PersistedDataHost {
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
// If trade is in preparation (if taker role: before taker fee is paid; both roles: before deposit published)
|
||||
// we just remove the trade from our list. We don't store those trades.
|
||||
public void removePreparedTrade(Trade trade) {
|
||||
removeTrade(trade);
|
||||
|
||||
cleanUpAddressEntries();
|
||||
}
|
||||
|
||||
private void removeTrade(Trade trade) {
|
||||
tradableList.remove(trade);
|
||||
}
|
||||
|
@ -675,7 +593,7 @@ public class TradeManager implements PersistedDataHost {
|
|||
if (tradeOptional.isPresent()) {
|
||||
Trade trade = tradeOptional.get();
|
||||
trade.setDisputeState(disputeState);
|
||||
addTradeToClosedTrades(trade);
|
||||
onTradeCompleted(trade);
|
||||
btcWalletService.swapTradeEntryToAvailableEntry(trade.getId(), AddressEntry.Context.TRADE_PAYOUT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,15 +26,12 @@ import bisq.core.trade.TradableList;
|
|||
import bisq.core.trade.Trade;
|
||||
import bisq.core.trade.TradeUtils;
|
||||
|
||||
import bisq.common.config.Config;
|
||||
import bisq.common.crypto.KeyRing;
|
||||
import bisq.common.proto.persistable.PersistedDataHost;
|
||||
import bisq.common.storage.Storage;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
import java.util.Optional;
|
||||
|
@ -90,6 +87,10 @@ public class FailedTradesManager implements PersistedDataHost {
|
|||
}
|
||||
}
|
||||
|
||||
public void removeTrade(Trade trade) {
|
||||
failedTrades.remove(trade);
|
||||
}
|
||||
|
||||
public boolean wasMyOffer(Offer offer) {
|
||||
return offer.isMyOffer(keyRing);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
package bisq.core.trade.protocol;
|
||||
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.trade.TradeManager;
|
||||
import bisq.core.trade.messages.CounterCurrencyTransferStartedMessage;
|
||||
import bisq.core.trade.messages.DepositTxAndDelayedPayoutTxMessage;
|
||||
import bisq.core.trade.messages.TradeMessage;
|
||||
|
@ -162,6 +161,12 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener {
|
|||
}
|
||||
|
||||
protected void sendAckMessage(TradeMessage message, boolean result, @Nullable String errorMessage) {
|
||||
PubKeyRing peersPubKeyRing = processModel.getTradingPeer().getPubKeyRing();
|
||||
if (peersPubKeyRing == null) {
|
||||
log.error("We cannot send the ACK message as peersPubKeyRing is null");
|
||||
return;
|
||||
}
|
||||
|
||||
String tradeId = message.getTradeId();
|
||||
String sourceUid = message.getUid();
|
||||
AckMessage ackMessage = new AckMessage(processModel.getMyNodeAddress(),
|
||||
|
@ -180,7 +185,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener {
|
|||
ackMessage.getSourceMsgClassName(), peer, tradeId, sourceUid);
|
||||
processModel.getP2PService().sendEncryptedMailboxMessage(
|
||||
peer,
|
||||
processModel.getTradingPeer().getPubKeyRing(),
|
||||
peersPubKeyRing,
|
||||
ackMessage,
|
||||
new SendMailboxMessageListener() {
|
||||
@Override
|
||||
|
@ -216,7 +221,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener {
|
|||
log.error("Timeout reached. TradeID={}, state={}, timeoutSec={}",
|
||||
trade.getId(), trade.stateProperty().get(), timeoutSec);
|
||||
trade.setErrorMessage("Timeout reached. Protocol did not complete in " + timeoutSec + " sec.");
|
||||
cleanupTradeOnFault();
|
||||
cleanup();
|
||||
}, timeoutSec);
|
||||
}
|
||||
|
||||
|
@ -284,7 +289,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener {
|
|||
if (message != null) {
|
||||
sendAckMessage(message, false, errorMessage);
|
||||
}
|
||||
cleanupTradeOnFault();
|
||||
cleanup();
|
||||
}
|
||||
|
||||
|
||||
|
@ -292,28 +297,4 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener {
|
|||
stopTimeout();
|
||||
processModel.getP2PService().removeDecryptedDirectMessageListener(this);
|
||||
}
|
||||
|
||||
//todo
|
||||
private void cleanupTradeOnFault() {
|
||||
cleanup();
|
||||
|
||||
log.warn("cleanupTradableOnFault tradeState={}", trade.getState());
|
||||
TradeManager tradeManager = processModel.getTradeManager();
|
||||
if (trade.isInPreparation()) {
|
||||
// no funds left. we just clean up the trade list
|
||||
tradeManager.removePreparedTrade(trade);
|
||||
} else if (!trade.isFundsLockedIn()) {
|
||||
// No deposit tx published yet
|
||||
if (processModel.getPreparedDepositTx() == null) {
|
||||
if (trade.isTakerFeePublished()) {
|
||||
tradeManager.addTradeToFailedTrades(trade);
|
||||
} else {
|
||||
tradeManager.addTradeToClosedTrades(trade);
|
||||
}
|
||||
} else {
|
||||
log.error("We have already sent the prepared deposit tx to the peer but we did not received the reply " +
|
||||
"about the deposit tx nor saw it in the network. tradeId={}, tradeState={}", trade.getId(), trade.getState());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -831,10 +831,10 @@ portfolio.pending.timeLockNotOver=You have to wait until ≈{0} ({1} more blocks
|
|||
portfolio.pending.error.depositTxNull=The deposit transaction is null. You cannot open a dispute \
|
||||
without a valid deposit transaction. Please go to \"Settings/Network info\" and do a SPV resync.\n\n\
|
||||
For further help please contact the Bisq support channel at the Bisq Keybase team.
|
||||
portfolio.pending.mediationResult.error.depositTxNull=The deposit transaction is null. The trade gets moved to the \
|
||||
failed trades section.
|
||||
portfolio.pending.mediationResult.error.delayedPayoutTxNull=The delayed payout transaction is null. The trade gets \
|
||||
moved to the failed trades section.
|
||||
portfolio.pending.mediationResult.error.depositTxNull=The deposit transaction is null. You can move the \
|
||||
trade to the failed trades screen by clicking the trash can icon.
|
||||
portfolio.pending.mediationResult.error.delayedPayoutTxNull=The delayed payout transaction is null. You can move the \
|
||||
trade to the failed trades screen by clicking the trash can icon.
|
||||
portfolio.pending.error.depositTxNotConfirmed=The deposit transaction is not confirmed. You can not open an arbitration dispute \
|
||||
with an unconfirmed deposit transaction. Please wait until it is confirmed or go to \"Settings/Network info\" and do a SPV resync.\n\n\
|
||||
For further help please contact the Bisq support channel at the Bisq Keybase team.
|
||||
|
@ -904,6 +904,17 @@ portfolio.pending.mediationResult.popup.selfAccepted.lockTimeOver=You have accep
|
|||
portfolio.pending.mediationResult.popup.openArbitration=Reject and request arbitration
|
||||
portfolio.pending.mediationResult.popup.alreadyAccepted=You've already accepted
|
||||
|
||||
portfolio.pending.moveToFailed.popup=This trade has an invalid state.\n\n\
|
||||
Do you want to move the trade to failed trades?\n\n\
|
||||
You cannot open mediation or arbitration from the failed trades view, but you can move it back to the open \
|
||||
trades screen any time.\n\n\
|
||||
Reason for the invalid trade state:\n{0}
|
||||
portfolio.pending.moveTradeToFailed=Move trade to failed trades
|
||||
portfolio.failed.revertToPending.popup=Do you want to move the trade to open trades?
|
||||
portfolio.failed.revertToPending=Move trade to open trades
|
||||
trade.error.delayedPayoutTxIsNull=Delayed payout transaction is null
|
||||
trade.error.depositTxIsNull=Deposit transaction is null
|
||||
|
||||
portfolio.closed.completed=Completed
|
||||
portfolio.closed.ticketClosed=Arbitrated
|
||||
portfolio.closed.mediationTicketClosed=Mediated
|
||||
|
@ -914,8 +925,8 @@ portfolio.failed.unfail=Before proceeding, make sure you have a backup of your d
|
|||
This is a way to unlock funds stuck in a failed trade.
|
||||
portfolio.failed.cantUnfail=This trade cannot be moved back to pending trades at the moment. \n\
|
||||
Try again after completion of trade(s) {0}
|
||||
portfolio.failed.depositTxNull=The trade cannot be reverted to a pending trade. Deposit transaction is null.
|
||||
portfolio.failed.delayedPayoutTxNull=The trade cannot be reverted to a pending trade. Delayed payout transaction is null.
|
||||
portfolio.failed.depositTxNull=The trade cannot be reverted to a open trade. Deposit transaction is null.
|
||||
portfolio.failed.delayedPayoutTxNull=The trade cannot be reverted to a open trade. Delayed payout transaction is null.
|
||||
|
||||
|
||||
####################################################################
|
||||
|
@ -2948,6 +2959,7 @@ peerInfoIcon.tooltip.age=Payment account created {0} ago.
|
|||
peerInfoIcon.tooltip.unknownAge=Payment account age not known.
|
||||
|
||||
tooltip.openPopupForDetails=Open popup for details
|
||||
tooltip.invalidTradeState.warning=This trade is in an invalid state. Open the details window for more information
|
||||
tooltip.openBlockchainForAddress=Open external blockchain explorer for address: {0}
|
||||
tooltip.openBlockchainForTx=Open external blockchain explorer for transaction: {0}
|
||||
|
||||
|
@ -2972,7 +2984,8 @@ addressTextField.openWallet.failed=Opening a default Bitcoin wallet application
|
|||
peerInfoIcon.tooltip={0}\nTag: {1}
|
||||
|
||||
txIdTextField.copyIcon.tooltip=Copy transaction ID to clipboard
|
||||
txIdTextField.blockExplorerIcon.tooltip=Open a blockchain explorer with that transactions ID
|
||||
txIdTextField.blockExplorerIcon.tooltip=Open a blockchain explorer with that transaction ID
|
||||
txIdTextField.missingTx.warning.tooltip=Missing required transaction
|
||||
|
||||
|
||||
####################################################################
|
||||
|
|
|
@ -85,6 +85,11 @@
|
|||
-fx-fill: -bs-color-gray-6;
|
||||
}
|
||||
|
||||
.error-icon {
|
||||
-fx-text-fill: -bs-rd-error-red;
|
||||
-fx-fill: -bs-rd-error-red;
|
||||
}
|
||||
|
||||
.zero-decimals {
|
||||
-fx-text-fill: -bs-color-gray-3;
|
||||
}
|
||||
|
@ -903,6 +908,11 @@ textfield */
|
|||
-fx-fill: -fx-accent;
|
||||
}
|
||||
|
||||
.hyperlink.error {
|
||||
-fx-text-fill: -bs-rd-error-red;
|
||||
-fx-fill: -bs-rd-error-red;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Table *
|
||||
|
@ -1393,6 +1403,12 @@ textfield */
|
|||
-fx-text-fill: -bs-text-color;
|
||||
}
|
||||
|
||||
#address-text-field-error {
|
||||
-fx-cursor: hand;
|
||||
-fx-text-fill: -bs-rd-error-red;
|
||||
-fx-prompt-text-fill: -bs-text-color;
|
||||
}
|
||||
|
||||
/* Account setup */
|
||||
#wizard-item-background-deactivated {
|
||||
-fx-body-color: linear-gradient(to bottom, -bs-content-background-gray, -bs-color-gray-aaa);
|
||||
|
|
|
@ -31,7 +31,11 @@ import javafx.scene.text.Text;
|
|||
|
||||
import javafx.geometry.Insets;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
public class HyperlinkWithIcon extends Hyperlink {
|
||||
@Getter
|
||||
private Node icon;
|
||||
|
||||
public HyperlinkWithIcon(String text) {
|
||||
this(text, AwesomeIcon.INFO_SIGN);
|
||||
|
@ -77,6 +81,7 @@ public class HyperlinkWithIcon extends Hyperlink {
|
|||
}
|
||||
|
||||
private void setIcon(Node icon) {
|
||||
this.icon = icon;
|
||||
setGraphic(icon);
|
||||
|
||||
setContentDisplay(ContentDisplay.RIGHT);
|
||||
|
|
|
@ -40,8 +40,11 @@ import javafx.scene.control.TextField;
|
|||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class TxIdTextField extends AnchorPane {
|
||||
private static Preferences preferences;
|
||||
|
||||
|
@ -55,11 +58,11 @@ public class TxIdTextField extends AnchorPane {
|
|||
TxIdTextField.walletService = walletService;
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final TextField textField;
|
||||
private final Tooltip progressIndicatorTooltip;
|
||||
private final TxConfidenceIndicator txConfidenceIndicator;
|
||||
private final Label copyIcon;
|
||||
private final Label blockExplorerIcon;
|
||||
private final Label copyIcon, blockExplorerIcon, missingTxWarningIcon;
|
||||
private TxConfidenceListener txConfidenceListener;
|
||||
@Setter
|
||||
private boolean isBsq;
|
||||
|
@ -99,6 +102,16 @@ public class TxIdTextField extends AnchorPane {
|
|||
AnchorPane.setRightAnchor(blockExplorerIcon, 52.0);
|
||||
AnchorPane.setTopAnchor(blockExplorerIcon, 4.0);
|
||||
|
||||
missingTxWarningIcon = new Label();
|
||||
missingTxWarningIcon.getStyleClass().addAll("icon", "error-icon");
|
||||
AwesomeDude.setIcon(missingTxWarningIcon, AwesomeIcon.WARNING_SIGN);
|
||||
missingTxWarningIcon.setTooltip(new Tooltip(Res.get("txIdTextField.missingTx.warning.tooltip")));
|
||||
missingTxWarningIcon.setMinWidth(20);
|
||||
AnchorPane.setRightAnchor(missingTxWarningIcon, 52.0);
|
||||
AnchorPane.setTopAnchor(missingTxWarningIcon, 4.0);
|
||||
missingTxWarningIcon.setVisible(false);
|
||||
missingTxWarningIcon.setManaged(false);
|
||||
|
||||
textField = new JFXTextField();
|
||||
textField.setId("address-text-field");
|
||||
textField.setEditable(false);
|
||||
|
@ -106,13 +119,26 @@ public class TxIdTextField extends AnchorPane {
|
|||
AnchorPane.setRightAnchor(textField, 80.0);
|
||||
AnchorPane.setLeftAnchor(textField, 0.0);
|
||||
textField.focusTraversableProperty().set(focusTraversableProperty().get());
|
||||
getChildren().addAll(textField, copyIcon, blockExplorerIcon, txConfidenceIndicator);
|
||||
getChildren().addAll(textField, missingTxWarningIcon, blockExplorerIcon, copyIcon, txConfidenceIndicator);
|
||||
}
|
||||
|
||||
public void setup(String txId) {
|
||||
public void setup(@Nullable String txId) {
|
||||
if (txConfidenceListener != null)
|
||||
walletService.removeTxConfidenceListener(txConfidenceListener);
|
||||
|
||||
if (txId == null) {
|
||||
textField.setText(Res.get("shared.na"));
|
||||
textField.setId("address-text-field-error");
|
||||
blockExplorerIcon.setVisible(false);
|
||||
blockExplorerIcon.setManaged(false);
|
||||
copyIcon.setVisible(false);
|
||||
copyIcon.setManaged(false);
|
||||
txConfidenceIndicator.setVisible(false);
|
||||
missingTxWarningIcon.setVisible(true);
|
||||
missingTxWarningIcon.setManaged(true);
|
||||
return;
|
||||
}
|
||||
|
||||
txConfidenceListener = new TxConfidenceListener(txId) {
|
||||
@Override
|
||||
public void onTransactionConfidenceChanged(TransactionConfidence confidence) {
|
||||
|
|
|
@ -56,7 +56,6 @@ import bisq.core.presentation.SupportTicketsPresentation;
|
|||
import bisq.core.presentation.TradePresentation;
|
||||
import bisq.core.provider.fee.FeeService;
|
||||
import bisq.core.provider.price.PriceFeedService;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.trade.TradeManager;
|
||||
import bisq.core.user.DontShowAgainLookup;
|
||||
import bisq.core.user.Preferences;
|
||||
|
@ -86,7 +85,6 @@ import javafx.beans.property.SimpleDoubleProperty;
|
|||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -407,20 +405,6 @@ public class MainViewModel implements ViewModel, BisqSetup.BisqSetupListener {
|
|||
.warning(Res.get("popup.error.takeOfferRequestFailed", errorMessage))
|
||||
.show());
|
||||
|
||||
tradeManager.getTradesWithoutDepositTx().addListener((ListChangeListener<Trade>) c -> {
|
||||
c.next();
|
||||
if (c.wasAdded()) {
|
||||
c.getAddedSubList().forEach(trade ->
|
||||
new Popup().warning(Res.get("popup.warning.trade.depositTxNull", trade.getShortId()))
|
||||
.actionButtonText(Res.get("popup.warning.trade.depositTxNull.shutDown"))
|
||||
.onAction(() -> BisqApp.getShutDownHandler().run())
|
||||
.secondaryActionButtonText(Res.get("popup.warning.trade.depositTxNull.moveToFailedTrades"))
|
||||
.onSecondaryAction(() -> tradeManager.addTradeToFailedTrades(trade))
|
||||
.show()
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
bisqSetup.getBtcSyncProgress().addListener((observable, oldValue, newValue) -> updateBtcSyncProgress());
|
||||
daoPresentation.getBsqSyncProgress().addListener((observable, oldValue, newValue) -> updateBtcSyncProgress());
|
||||
|
||||
|
|
|
@ -28,26 +28,43 @@ import bisq.core.offer.placeoffer.tasks.CreateMakerFeeTx;
|
|||
import bisq.core.offer.placeoffer.tasks.ValidateOffer;
|
||||
import bisq.core.trade.protocol.tasks.ApplyFilter;
|
||||
import bisq.core.trade.protocol.tasks.PublishTradeStatistics;
|
||||
import bisq.core.trade.protocol.tasks.VerifyPeersAccountAgeWitness;
|
||||
import bisq.core.trade.protocol.tasks.buyer.BuyerProcessDelayedPayoutTxSignatureRequest;
|
||||
import bisq.core.trade.protocol.tasks.buyer.BuyerProcessDepositTxAndDelayedPayoutTxMessage;
|
||||
import bisq.core.trade.protocol.tasks.buyer.BuyerProcessPayoutTxPublishedMessage;
|
||||
import bisq.core.trade.protocol.tasks.buyer.BuyerSendCounterCurrencyTransferStartedMessage;
|
||||
import bisq.core.trade.protocol.tasks.buyer.BuyerSendsDelayedPayoutTxSignatureResponse;
|
||||
import bisq.core.trade.protocol.tasks.buyer.BuyerSetupDepositTxListener;
|
||||
import bisq.core.trade.protocol.tasks.buyer.BuyerSetupPayoutTxListener;
|
||||
import bisq.core.trade.protocol.tasks.buyer.BuyerSignPayoutTx;
|
||||
import bisq.core.trade.protocol.tasks.buyer.BuyerSignsDelayedPayoutTx;
|
||||
import bisq.core.trade.protocol.tasks.buyer.BuyerVerifiesFinalDelayedPayoutTx;
|
||||
import bisq.core.trade.protocol.tasks.buyer.BuyerVerifiesPreparedDelayedPayoutTx;
|
||||
import bisq.core.trade.protocol.tasks.buyer_as_maker.BuyerAsMakerCreatesAndSignsDepositTx;
|
||||
import bisq.core.trade.protocol.tasks.buyer_as_maker.BuyerAsMakerSendsInputsForDepositTxResponse;
|
||||
import bisq.core.trade.protocol.tasks.buyer_as_taker.BuyerAsTakerCreatesDepositTxInputs;
|
||||
import bisq.core.trade.protocol.tasks.buyer_as_taker.BuyerAsTakerSignsDepositTx;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerCreateAndSignContract;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerProcessesInputsForDepositTxRequest;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerSetsLockTime;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerVerifyTakerFeePayment;
|
||||
import bisq.core.trade.protocol.tasks.seller.SellerBroadcastPayoutTx;
|
||||
import bisq.core.trade.protocol.tasks.seller.SellerCreatesDelayedPayoutTx;
|
||||
import bisq.core.trade.protocol.tasks.seller.SellerFinalizesDelayedPayoutTx;
|
||||
import bisq.core.trade.protocol.tasks.seller.SellerProcessCounterCurrencyTransferStartedMessage;
|
||||
import bisq.core.trade.protocol.tasks.seller.SellerProcessDelayedPayoutTxSignatureResponse;
|
||||
import bisq.core.trade.protocol.tasks.seller.SellerPublishesDepositTx;
|
||||
import bisq.core.trade.protocol.tasks.seller.SellerSendDelayedPayoutTxSignatureRequest;
|
||||
import bisq.core.trade.protocol.tasks.seller.SellerSendPayoutTxPublishedMessage;
|
||||
import bisq.core.trade.protocol.tasks.seller.SellerSendsDepositTxAndDelayedPayoutTxMessage;
|
||||
import bisq.core.trade.protocol.tasks.seller.SellerSignAndFinalizePayoutTx;
|
||||
import bisq.core.trade.protocol.tasks.seller.SellerSignsDelayedPayoutTx;
|
||||
import bisq.core.trade.protocol.tasks.seller_as_maker.SellerAsMakerCreatesUnsignedDepositTx;
|
||||
import bisq.core.trade.protocol.tasks.seller_as_taker.SellerAsTakerCreatesDepositTxInputs;
|
||||
import bisq.core.trade.protocol.tasks.seller_as_taker.SellerAsTakerSignsDepositTx;
|
||||
import bisq.core.trade.protocol.tasks.taker.CreateTakerFeeTx;
|
||||
import bisq.core.trade.protocol.tasks.taker.TakerProcessesInputsForDepositTxResponse;
|
||||
import bisq.core.trade.protocol.tasks.taker.TakerPublishFeeTx;
|
||||
import bisq.core.trade.protocol.tasks.taker.TakerSendInputsForDepositTxRequest;
|
||||
import bisq.core.trade.protocol.tasks.taker.TakerVerifyAndSignContract;
|
||||
import bisq.core.trade.protocol.tasks.taker.TakerVerifyMakerFeePayment;
|
||||
|
@ -104,22 +121,35 @@ public class DebugView extends InitializableView<GridPane, Void> {
|
|||
FXCollections.observableArrayList(Arrays.asList(
|
||||
MakerProcessesInputsForDepositTxRequest.class,
|
||||
ApplyFilter.class,
|
||||
VerifyPeersAccountAgeWitness.class,
|
||||
MakerVerifyTakerFeePayment.class,
|
||||
MakerSetsLockTime.class,
|
||||
MakerCreateAndSignContract.class,
|
||||
BuyerAsMakerCreatesAndSignsDepositTx.class,
|
||||
BuyerSetupDepositTxListener.class,
|
||||
BuyerAsMakerSendsInputsForDepositTxResponse.class,
|
||||
|
||||
MakerVerifyTakerFeePayment.class,
|
||||
BuyerProcessDelayedPayoutTxSignatureRequest.class,
|
||||
BuyerVerifiesPreparedDelayedPayoutTx.class,
|
||||
BuyerSignsDelayedPayoutTx.class,
|
||||
BuyerSendsDelayedPayoutTxSignatureResponse.class,
|
||||
|
||||
BuyerProcessDepositTxAndDelayedPayoutTxMessage.class,
|
||||
BuyerVerifiesFinalDelayedPayoutTx.class,
|
||||
PublishTradeStatistics.class,
|
||||
|
||||
ApplyFilter.class,
|
||||
MakerVerifyTakerFeePayment.class,
|
||||
BuyerSignPayoutTx.class,
|
||||
BuyerSetupPayoutTxListener.class,
|
||||
BuyerSendCounterCurrencyTransferStartedMessage.class,
|
||||
BuyerSetupPayoutTxListener.class)
|
||||
|
||||
BuyerProcessPayoutTxPublishedMessage.class
|
||||
)
|
||||
));
|
||||
addGroup("SellerAsTakerProtocol",
|
||||
FXCollections.observableArrayList(Arrays.asList(
|
||||
ApplyFilter.class,
|
||||
TakerVerifyMakerFeePayment.class,
|
||||
CreateTakerFeeTx.class,
|
||||
SellerAsTakerCreatesDepositTxInputs.class,
|
||||
|
@ -127,20 +157,34 @@ public class DebugView extends InitializableView<GridPane, Void> {
|
|||
|
||||
TakerProcessesInputsForDepositTxResponse.class,
|
||||
ApplyFilter.class,
|
||||
TakerVerifyMakerFeePayment.class,
|
||||
VerifyPeersAccountAgeWitness.class,
|
||||
TakerVerifyAndSignContract.class,
|
||||
TakerPublishFeeTx.class,
|
||||
SellerAsTakerSignsDepositTx.class,
|
||||
SellerCreatesDelayedPayoutTx.class,
|
||||
SellerSendDelayedPayoutTxSignatureRequest.class,
|
||||
|
||||
SellerProcessDelayedPayoutTxSignatureResponse.class,
|
||||
SellerSignsDelayedPayoutTx.class,
|
||||
SellerFinalizesDelayedPayoutTx.class,
|
||||
SellerSendsDepositTxAndDelayedPayoutTxMessage.class,
|
||||
SellerPublishesDepositTx.class,
|
||||
PublishTradeStatistics.class,
|
||||
|
||||
SellerProcessCounterCurrencyTransferStartedMessage.class,
|
||||
ApplyFilter.class,
|
||||
TakerVerifyMakerFeePayment.class,
|
||||
|
||||
ApplyFilter.class,
|
||||
TakerVerifyMakerFeePayment.class,
|
||||
SellerSignAndFinalizePayoutTx.class,
|
||||
SellerBroadcastPayoutTx.class,
|
||||
SellerSendPayoutTxPublishedMessage.class)
|
||||
SellerSendPayoutTxPublishedMessage.class
|
||||
|
||||
)
|
||||
));
|
||||
|
||||
//todo
|
||||
addGroup("BuyerAsTakerProtocol",
|
||||
FXCollections.observableArrayList(Arrays.asList(
|
||||
TakerVerifyMakerFeePayment.class,
|
||||
|
|
|
@ -41,9 +41,9 @@ import bisq.core.trade.Trade;
|
|||
import bisq.core.trade.TradeManager;
|
||||
import bisq.core.user.Preferences;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.ParsingUtils;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
import bisq.core.util.coin.CoinUtil;
|
||||
import bisq.core.util.ParsingUtils;
|
||||
import bisq.core.util.validation.BtcAddressValidator;
|
||||
|
||||
import bisq.network.p2p.P2PService;
|
||||
|
@ -100,7 +100,6 @@ import org.bouncycastle.crypto.params.KeyParameter;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
@ -399,7 +398,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
|||
.forEach(trade -> walletService.getAddressEntry(trade.getId(), AddressEntry.Context.TRADE_PAYOUT)
|
||||
.ifPresent(addressEntry -> {
|
||||
if (walletService.getBalanceForAddress(addressEntry.getAddress()).isZero())
|
||||
tradeManager.addTradeToClosedTrades(trade);
|
||||
tradeManager.onTradeCompleted(trade);
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import bisq.desktop.util.GUIUtil;
|
|||
import bisq.desktop.util.Layout;
|
||||
|
||||
import bisq.core.account.witness.AccountAgeWitnessService;
|
||||
import bisq.core.btc.wallet.BtcWalletService;
|
||||
import bisq.core.locale.CurrencyUtil;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.offer.Offer;
|
||||
|
@ -78,6 +79,7 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
|
|||
private final CoinFormatter formatter;
|
||||
private final ArbitrationManager arbitrationManager;
|
||||
private final TradeManager tradeManager;
|
||||
private final BtcWalletService btcWalletService;
|
||||
private final AccountAgeWitnessService accountAgeWitnessService;
|
||||
private Trade trade;
|
||||
private ChangeListener<Number> changeListener;
|
||||
|
@ -94,10 +96,12 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
|
|||
public TradeDetailsWindow(@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter,
|
||||
ArbitrationManager arbitrationManager,
|
||||
TradeManager tradeManager,
|
||||
BtcWalletService btcWalletService,
|
||||
AccountAgeWitnessService accountAgeWitnessService) {
|
||||
this.formatter = formatter;
|
||||
this.arbitrationManager = arbitrationManager;
|
||||
this.tradeManager = tradeManager;
|
||||
this.btcWalletService = btcWalletService;
|
||||
this.accountAgeWitnessService = accountAgeWitnessService;
|
||||
type = Type.Confirmation;
|
||||
}
|
||||
|
@ -166,7 +170,7 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
|
|||
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.paymentMethod"), paymentMethodText);
|
||||
|
||||
// second group
|
||||
rows = 8;
|
||||
rows = 9;
|
||||
PaymentAccountPayload buyerPaymentAccountPayload = null;
|
||||
PaymentAccountPayload sellerPaymentAccountPayload = null;
|
||||
|
||||
|
@ -185,9 +189,6 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
|
|||
rows++;
|
||||
}
|
||||
|
||||
if (trade.getTakerFeeTxId() != null)
|
||||
rows++;
|
||||
|
||||
if (trade.getPayoutTx() != null)
|
||||
rows++;
|
||||
boolean showDisputedTx = arbitrationManager.findOwnDispute(trade.getId()).isPresent() &&
|
||||
|
@ -280,15 +281,14 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
|
|||
}
|
||||
|
||||
addLabelTxIdTextField(gridPane, ++rowIndex, Res.get("shared.makerFeeTxId"), offer.getOfferFeePaymentTxId());
|
||||
if (trade.getTakerFeeTxId() != null)
|
||||
addLabelTxIdTextField(gridPane, ++rowIndex, Res.get("shared.takerFeeTxId"), trade.getTakerFeeTxId());
|
||||
addLabelTxIdTextField(gridPane, ++rowIndex, Res.get("shared.takerFeeTxId"), trade.getTakerFeeTxId());
|
||||
|
||||
Transaction depositTx = trade.getDepositTx();
|
||||
String depositTxString = depositTx != null ? depositTx.getTxId().toString() : Res.get("shared.na");
|
||||
String depositTxString = depositTx != null ? depositTx.getTxId().toString() : null;
|
||||
addLabelTxIdTextField(gridPane, ++rowIndex, Res.get("shared.depositTransactionId"), depositTxString);
|
||||
|
||||
Transaction delayedPayoutTx = trade.getDelayedPayoutTx();
|
||||
String delayedPayoutTxString = delayedPayoutTx != null ? delayedPayoutTx.getTxId().toString() : Res.get("shared.na");
|
||||
Transaction delayedPayoutTx = trade.getDelayedPayoutTx(btcWalletService);
|
||||
String delayedPayoutTxString = delayedPayoutTx != null ? delayedPayoutTx.getTxId().toString() : null;
|
||||
addLabelTxIdTextField(gridPane, ++rowIndex, Res.get("shared.delayedPayoutTxId"), delayedPayoutTxString);
|
||||
|
||||
if (trade.getPayoutTx() != null)
|
||||
|
|
|
@ -22,6 +22,7 @@ import bisq.desktop.common.model.ActivatableDataModel;
|
|||
import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OfferPayload;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.trade.TradeManager;
|
||||
import bisq.core.trade.failed.FailedTradesManager;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
@ -35,13 +36,15 @@ import java.util.stream.Collectors;
|
|||
class FailedTradesDataModel extends ActivatableDataModel {
|
||||
|
||||
private final FailedTradesManager failedTradesManager;
|
||||
private final TradeManager tradeManager;
|
||||
|
||||
private final ObservableList<FailedTradesListItem> list = FXCollections.observableArrayList();
|
||||
private final ListChangeListener<Trade> tradesListChangeListener;
|
||||
|
||||
@Inject
|
||||
public FailedTradesDataModel(FailedTradesManager failedTradesManager) {
|
||||
public FailedTradesDataModel(FailedTradesManager failedTradesManager, TradeManager tradeManager) {
|
||||
this.failedTradesManager = failedTradesManager;
|
||||
this.tradeManager = tradeManager;
|
||||
|
||||
tradesListChangeListener = change -> applyList();
|
||||
}
|
||||
|
@ -74,6 +77,11 @@ class FailedTradesDataModel extends ActivatableDataModel {
|
|||
list.sort((o1, o2) -> o2.getTrade().getDate().compareTo(o1.getTrade().getDate()));
|
||||
}
|
||||
|
||||
public void moveTradeToPendingTrades(Trade trade) {
|
||||
failedTradesManager.removeTrade(trade);
|
||||
tradeManager.addFailedTradeToPending(trade);
|
||||
}
|
||||
|
||||
public void unfailTrade(Trade trade) {
|
||||
failedTradesManager.unfailTrade(trade);
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
<TableColumn fx:id="volumeColumn" minWidth="130"/>
|
||||
<TableColumn fx:id="directionColumn" minWidth="80"/>
|
||||
<TableColumn fx:id="stateColumn" minWidth="80"/>
|
||||
<TableColumn fx:id="removeTradeColumn" minWidth="40" maxWidth="40"/>
|
||||
</columns>
|
||||
</TableView>
|
||||
</VBox>
|
||||
|
|
|
@ -23,6 +23,7 @@ import bisq.desktop.components.AutoTooltipLabel;
|
|||
import bisq.desktop.components.HyperlinkWithIcon;
|
||||
import bisq.desktop.main.overlays.popups.Popup;
|
||||
import bisq.desktop.main.overlays.windows.TradeDetailsWindow;
|
||||
import bisq.desktop.util.FormBuilder;
|
||||
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.trade.Trade;
|
||||
|
@ -33,9 +34,14 @@ import bisq.common.util.Utilities;
|
|||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||
|
||||
import com.jfoenix.controls.JFXButton;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TableCell;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableView;
|
||||
|
@ -61,7 +67,7 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
TableView<FailedTradesListItem> tableView;
|
||||
@FXML
|
||||
TableColumn<FailedTradesListItem, FailedTradesListItem> priceColumn, amountColumn, volumeColumn,
|
||||
marketColumn, directionColumn, dateColumn, tradeIdColumn, stateColumn;
|
||||
marketColumn, directionColumn, dateColumn, tradeIdColumn, stateColumn, removeTradeColumn;
|
||||
private final TradeDetailsWindow tradeDetailsWindow;
|
||||
private SortedList<FailedTradesListItem> sortedList;
|
||||
private EventHandler<KeyEvent> keyEventEventHandler;
|
||||
|
@ -99,6 +105,7 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
setDateColumnCellFactory();
|
||||
setMarketColumnCellFactory();
|
||||
setStateColumnCellFactory();
|
||||
setRemoveTradeColumnCellFactory();
|
||||
|
||||
tradeIdColumn.setComparator(Comparator.comparing(o -> o.getTrade().getId()));
|
||||
dateColumn.setComparator(Comparator.comparing(o -> o.getTrade().getDate()));
|
||||
|
@ -178,6 +185,13 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
sortedList.comparatorProperty().unbind();
|
||||
}
|
||||
|
||||
private void onRevertTrade(Trade trade) {
|
||||
new Popup().attention(Res.get("portfolio.failed.revertToPending.popup"))
|
||||
.onAction(() -> model.dataModel.moveTradeToPendingTrades(trade))
|
||||
.actionButtonText(Res.get("shared.yes"))
|
||||
.closeButtonText(Res.get("shared.no"))
|
||||
.show();
|
||||
}
|
||||
|
||||
private void setTradeIdColumnCellFactory() {
|
||||
tradeIdColumn.getStyleClass().add("first-column");
|
||||
|
@ -211,7 +225,7 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
}
|
||||
|
||||
private void setDateColumnCellFactory() {
|
||||
dateColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
dateColumn.setCellValueFactory((trade) -> new ReadOnlyObjectWrapper<>(trade.getValue()));
|
||||
dateColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
|
@ -232,7 +246,7 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
}
|
||||
|
||||
private void setMarketColumnCellFactory() {
|
||||
marketColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
marketColumn.setCellValueFactory((trade) -> new ReadOnlyObjectWrapper<>(trade.getValue()));
|
||||
marketColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
|
@ -251,7 +265,7 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
|
||||
private void setStateColumnCellFactory() {
|
||||
stateColumn.getStyleClass().add("last-column");
|
||||
stateColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
stateColumn.setCellValueFactory((trade) -> new ReadOnlyObjectWrapper<>(trade.getValue()));
|
||||
stateColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
|
@ -273,7 +287,7 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
|
||||
|
||||
private void setAmountColumnCellFactory() {
|
||||
amountColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
amountColumn.setCellValueFactory((trade) -> new ReadOnlyObjectWrapper<>(trade.getValue()));
|
||||
amountColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
|
@ -291,7 +305,7 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
}
|
||||
|
||||
private void setPriceColumnCellFactory() {
|
||||
priceColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
priceColumn.setCellValueFactory((trade) -> new ReadOnlyObjectWrapper<>(trade.getValue()));
|
||||
priceColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
|
@ -309,7 +323,7 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
}
|
||||
|
||||
private void setVolumeColumnCellFactory() {
|
||||
volumeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
volumeColumn.setCellValueFactory((trade) -> new ReadOnlyObjectWrapper<>(trade.getValue()));
|
||||
volumeColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
|
@ -330,7 +344,7 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
}
|
||||
|
||||
private void setDirectionColumnCellFactory() {
|
||||
directionColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
directionColumn.setCellValueFactory((trade) -> new ReadOnlyObjectWrapper<>(trade.getValue()));
|
||||
directionColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
|
@ -346,5 +360,36 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
private TableColumn<FailedTradesListItem, FailedTradesListItem> setRemoveTradeColumnCellFactory() {
|
||||
removeTradeColumn.setCellValueFactory((trade) -> new ReadOnlyObjectWrapper<>(trade.getValue()));
|
||||
removeTradeColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
public TableCell<FailedTradesListItem, FailedTradesListItem> call(TableColumn<FailedTradesListItem,
|
||||
FailedTradesListItem> column) {
|
||||
return new TableCell<>() {
|
||||
|
||||
@Override
|
||||
public void updateItem(FailedTradesListItem newItem, boolean empty) {
|
||||
super.updateItem(newItem, empty);
|
||||
if (!empty && newItem != null) {
|
||||
Label icon = FormBuilder.getIcon(AwesomeIcon.UNDO);
|
||||
icon.getStyleClass().addAll("icon", "dao-remove-proposal-icon");
|
||||
JFXButton iconButton = new JFXButton("", icon);
|
||||
iconButton.setStyle("-fx-cursor: hand;");
|
||||
iconButton.getStyleClass().add("hidden-icon-button");
|
||||
iconButton.setTooltip(new Tooltip(Res.get("portfolio.failed.revertToPending")));
|
||||
iconButton.setOnAction(e -> onRevertTrade(newItem.getTrade()));
|
||||
setGraphic(iconButton);
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
return removeTradeColumn;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -79,7 +79,6 @@ import javafx.collections.ObservableList;
|
|||
|
||||
import org.bouncycastle.crypto.params.KeyParameter;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -232,10 +231,6 @@ public class PendingTradesDataModel extends ActivatableDataModel {
|
|||
tryOpenDispute(true);
|
||||
}
|
||||
|
||||
public void onMoveToFailedTrades() {
|
||||
tradeManager.addTradeToFailedTrades(getTrade());
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Getters
|
||||
|
@ -687,8 +682,8 @@ public class PendingTradesDataModel extends ActivatableDataModel {
|
|||
return GUIUtil.isBootstrappedOrShowPopup(p2PService);
|
||||
}
|
||||
|
||||
public void addTradeToFailedTrades() {
|
||||
tradeManager.addTradeToFailedTrades(selectedTrade);
|
||||
public void moveTradeToFailedTrades(Trade trade) {
|
||||
tradeManager.moveTradeToFailedTrades(trade);
|
||||
}
|
||||
|
||||
public boolean isSignWitnessTrade() {
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
<TableColumn fx:id="roleColumn" minWidth="150"/>
|
||||
<TableColumn fx:id="avatarColumn" minWidth="40" maxWidth="40"/>
|
||||
<TableColumn fx:id="chatColumn" minWidth="40" maxWidth="40"/>
|
||||
<TableColumn fx:id="moveTradeToFailedColumn" minWidth="40" maxWidth="40"/>
|
||||
</columns>
|
||||
</TableView>
|
||||
</VBox>
|
||||
|
|
|
@ -50,9 +50,11 @@ import bisq.common.util.Utilities;
|
|||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||
import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon;
|
||||
|
||||
import com.jfoenix.controls.JFXBadge;
|
||||
import com.jfoenix.controls.JFXButton;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
|
||||
|
@ -64,6 +66,7 @@ import javafx.stage.Window;
|
|||
import javafx.scene.Node;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TableCell;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableView;
|
||||
|
@ -87,6 +90,7 @@ import javafx.beans.value.ChangeListener;
|
|||
import javafx.event.EventHandler;
|
||||
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.collections.transformation.SortedList;
|
||||
|
||||
import javafx.util.Callback;
|
||||
|
@ -97,6 +101,9 @@ import java.util.Map;
|
|||
|
||||
@FxmlView
|
||||
public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTradesViewModel> {
|
||||
public interface ChatCallback {
|
||||
void onOpenChat(Trade trade);
|
||||
}
|
||||
|
||||
private final TradeDetailsWindow tradeDetailsWindow;
|
||||
private final CoinFormatter formatter;
|
||||
|
@ -108,7 +115,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
TableView<PendingTradesListItem> tableView;
|
||||
@FXML
|
||||
TableColumn<PendingTradesListItem, PendingTradesListItem> priceColumn, volumeColumn, amountColumn, avatarColumn,
|
||||
marketColumn, roleColumn, paymentMethodColumn, tradeIdColumn, dateColumn, chatColumn;
|
||||
marketColumn, roleColumn, paymentMethodColumn, tradeIdColumn, dateColumn, chatColumn, moveTradeToFailedColumn;
|
||||
private SortedList<PendingTradesListItem> sortedList;
|
||||
private TradeSubView selectedSubView;
|
||||
private EventHandler<KeyEvent> keyEventEventHandler;
|
||||
|
@ -165,6 +172,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
paymentMethodColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.paymentMethod")));
|
||||
avatarColumn.setText("");
|
||||
chatColumn.setText("");
|
||||
moveTradeToFailedColumn.setText("");
|
||||
|
||||
setTradeIdColumnCellFactory();
|
||||
setDateColumnCellFactory();
|
||||
|
@ -176,6 +184,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
setRoleColumnCellFactory();
|
||||
setAvatarColumnCellFactory();
|
||||
setChatColumnCellFactory();
|
||||
setRemoveTradeColumnCellFactory();
|
||||
|
||||
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||
tableView.setPlaceholder(new AutoTooltipLabel(Res.get("table.placeholder.noItems", Res.get("shared.openTrades"))));
|
||||
|
@ -212,10 +221,6 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
.closeButtonText(Res.get("shared.cancel"))
|
||||
.onClose(popup::hide)
|
||||
.show();
|
||||
} else if (Utilities.isAltOrCtrlPressed(KeyCode.Y, keyEvent)) {
|
||||
new Popup().warning(Res.get("portfolio.pending.removeFailedTrade"))
|
||||
.onAction(model.dataModel::onMoveToFailedTrades)
|
||||
.show();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -224,26 +229,16 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
|
||||
@Override
|
||||
protected void activate() {
|
||||
sortedList = new SortedList<>(model.dataModel.list);
|
||||
ObservableList<PendingTradesListItem> list = model.dataModel.list;
|
||||
sortedList = new SortedList<>(list);
|
||||
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
||||
tableView.setItems(sortedList);
|
||||
|
||||
updateMoveTradeToFailedColumnState();
|
||||
|
||||
scene = root.getScene();
|
||||
if (scene != null) {
|
||||
scene.addEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler);
|
||||
|
||||
//TODO: in what cases is it necessary to request focus?
|
||||
/*appFocusSubscription = EasyBind.subscribe(scene.getWindow().focusedProperty(), isFocused -> {
|
||||
if (isFocused && model.dataModel.selectedItemProperty.get() != null) {
|
||||
// Focus selectedItem from model
|
||||
int index = table.getItems().indexOf(model.dataModel.selectedItemProperty.get());
|
||||
UserThread.execute(() -> {
|
||||
//TODO app wide focus
|
||||
//table.requestFocus();
|
||||
//UserThread.execute(() -> table.getFocusModel().focus(index));
|
||||
});
|
||||
}
|
||||
});*/
|
||||
}
|
||||
|
||||
selectedItemSubscription = EasyBind.subscribe(model.dataModel.selectedItemProperty, selectedItem -> {
|
||||
|
@ -287,7 +282,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
|
||||
updateTableSelection();
|
||||
|
||||
model.dataModel.list.addListener(tradesListChangeListener);
|
||||
list.addListener(tradesListChangeListener);
|
||||
updateNewChatMessagesByTradeMap();
|
||||
}
|
||||
|
||||
|
@ -313,6 +308,41 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
}
|
||||
}
|
||||
|
||||
private void updateMoveTradeToFailedColumnState() {
|
||||
moveTradeToFailedColumn.setVisible(model.dataModel.list.stream().anyMatch(item -> isInvalidState(item.getTrade())));
|
||||
}
|
||||
|
||||
private boolean isInvalidState(Trade trade) {
|
||||
String errorMessage = trade.getErrorMessage();
|
||||
boolean hasErrorMsg = errorMessage != null && !errorMessage.isEmpty();
|
||||
return hasErrorMsg ||
|
||||
trade.getDepositTxId() == null ||
|
||||
trade.getDelayedPayoutTxBytes() == null;
|
||||
}
|
||||
|
||||
private void onMoveTradeToFailedTrades(Trade trade) {
|
||||
String reason;
|
||||
String errorMessage = trade.getErrorMessage();
|
||||
if (errorMessage != null && !errorMessage.isEmpty()) {
|
||||
reason = errorMessage;
|
||||
} else if (trade.getDepositTxId() == null) {
|
||||
reason = Res.get("trade.error.depositTxIsNull");
|
||||
} else if (trade.getDelayedPayoutTxBytes() == null) {
|
||||
reason = Res.get("trade.error.delayedPayoutTxIsNull");
|
||||
} else {
|
||||
reason = Res.get("shared.na");
|
||||
}
|
||||
new Popup().attention(Res.get("portfolio.pending.moveToFailed.popup", reason))
|
||||
.onAction(() -> {
|
||||
model.dataModel.moveTradeToFailedTrades(trade);
|
||||
updateMoveTradeToFailedColumnState();
|
||||
})
|
||||
.actionButtonText(Res.get("shared.yes"))
|
||||
.closeButtonText(Res.get("shared.no"))
|
||||
.show();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Chat
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -503,9 +533,18 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
super.updateItem(item, empty);
|
||||
|
||||
if (item != null && !empty) {
|
||||
field = new HyperlinkWithIcon(item.getTrade().getShortId());
|
||||
field.setOnAction(event -> tradeDetailsWindow.show(item.getTrade()));
|
||||
field.setTooltip(new Tooltip(Res.get("tooltip.openPopupForDetails")));
|
||||
if (isInvalidState(item.getTrade())) {
|
||||
field = new HyperlinkWithIcon(item.getTrade().getShortId(), AwesomeIcon.WARNING_SIGN);
|
||||
field.setOnAction(event -> tradeDetailsWindow.show(item.getTrade()));
|
||||
field.setTooltip(new Tooltip(Res.get("tooltip.invalidTradeState.warning")));
|
||||
//FIXME icon does not take red color ;-(
|
||||
field.getIcon().getStyleClass().clear();
|
||||
field.getIcon().getStyleClass().addAll("hyperlink", "error");
|
||||
} else {
|
||||
field = new HyperlinkWithIcon(item.getTrade().getShortId());
|
||||
field.setOnAction(event -> tradeDetailsWindow.show(item.getTrade()));
|
||||
field.setTooltip(new Tooltip(Res.get("tooltip.openPopupForDetails")));
|
||||
}
|
||||
setGraphic(field);
|
||||
} else {
|
||||
setGraphic(null);
|
||||
|
@ -519,7 +558,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
}
|
||||
|
||||
private void setDateColumnCellFactory() {
|
||||
dateColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
dateColumn.setCellValueFactory((trade) -> new ReadOnlyObjectWrapper<>(trade.getValue()));
|
||||
dateColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
|
@ -541,7 +580,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
}
|
||||
|
||||
private void setAmountColumnCellFactory() {
|
||||
amountColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
amountColumn.setCellValueFactory((trade) -> new ReadOnlyObjectWrapper<>(trade.getValue()));
|
||||
amountColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
|
@ -562,7 +601,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
}
|
||||
|
||||
private void setPriceColumnCellFactory() {
|
||||
priceColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
priceColumn.setCellValueFactory((trade) -> new ReadOnlyObjectWrapper<>(trade.getValue()));
|
||||
priceColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
|
@ -583,7 +622,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
}
|
||||
|
||||
private void setVolumeColumnCellFactory() {
|
||||
volumeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
volumeColumn.setCellValueFactory((trade) -> new ReadOnlyObjectWrapper<>(trade.getValue()));
|
||||
volumeColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
|
@ -593,9 +632,13 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
@Override
|
||||
public void updateItem(final PendingTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null && !empty)
|
||||
setGraphic(new AutoTooltipLabel(DisplayUtils.formatVolumeWithCode(item.getTrade().getTradeVolume())));
|
||||
else
|
||||
if (item != null && !empty) {
|
||||
try {
|
||||
String volume = DisplayUtils.formatVolumeWithCode(item.getTrade().getTradeVolume());
|
||||
setGraphic(new AutoTooltipLabel(volume));
|
||||
} catch (Throwable ignore) {
|
||||
}
|
||||
} else
|
||||
setGraphic(null);
|
||||
}
|
||||
};
|
||||
|
@ -604,7 +647,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
}
|
||||
|
||||
private void setPaymentMethodColumnCellFactory() {
|
||||
paymentMethodColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
paymentMethodColumn.setCellValueFactory((trade) -> new ReadOnlyObjectWrapper<>(trade.getValue()));
|
||||
paymentMethodColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
|
@ -625,7 +668,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
}
|
||||
|
||||
private void setMarketColumnCellFactory() {
|
||||
marketColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
marketColumn.setCellValueFactory((trade) -> new ReadOnlyObjectWrapper<>(trade.getValue()));
|
||||
marketColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
|
@ -643,7 +686,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
}
|
||||
|
||||
private void setRoleColumnCellFactory() {
|
||||
roleColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
roleColumn.setCellValueFactory((trade) -> new ReadOnlyObjectWrapper<>(trade.getValue()));
|
||||
roleColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
|
@ -665,7 +708,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
private TableColumn<PendingTradesListItem, PendingTradesListItem> setAvatarColumnCellFactory() {
|
||||
avatarColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
avatarColumn.setCellValueFactory((trade) -> new ReadOnlyObjectWrapper<>(trade.getValue()));
|
||||
avatarColumn.getStyleClass().addAll("last-column", "avatar-column");
|
||||
avatarColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
|
@ -675,7 +718,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
return new TableCell<>() {
|
||||
|
||||
@Override
|
||||
public void updateItem(final PendingTradesListItem newItem, boolean empty) {
|
||||
public void updateItem(PendingTradesListItem newItem, boolean empty) {
|
||||
super.updateItem(newItem, empty);
|
||||
if (!empty && newItem != null) {
|
||||
final Trade trade = newItem.getTrade();
|
||||
|
@ -704,8 +747,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
private TableColumn<PendingTradesListItem, PendingTradesListItem> setChatColumnCellFactory() {
|
||||
chatColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
//TODO
|
||||
chatColumn.setCellValueFactory((trade) -> new ReadOnlyObjectWrapper<>(trade.getValue()));
|
||||
chatColumn.getStyleClass().addAll("last-column", "avatar-column");
|
||||
chatColumn.setSortable(false);
|
||||
chatColumn.setCellFactory(
|
||||
|
@ -715,7 +757,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
return new TableCell<>() {
|
||||
|
||||
@Override
|
||||
public void updateItem(final PendingTradesListItem newItem, boolean empty) {
|
||||
public void updateItem(PendingTradesListItem newItem, boolean empty) {
|
||||
super.updateItem(newItem, empty);
|
||||
|
||||
if (!empty && newItem != null) {
|
||||
|
@ -772,8 +814,34 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
return chatColumn;
|
||||
}
|
||||
|
||||
public interface ChatCallback {
|
||||
void onOpenChat(Trade trade);
|
||||
}
|
||||
private TableColumn<PendingTradesListItem, PendingTradesListItem> setRemoveTradeColumnCellFactory() {
|
||||
moveTradeToFailedColumn.setCellValueFactory((trade) -> new ReadOnlyObjectWrapper<>(trade.getValue()));
|
||||
moveTradeToFailedColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
public TableCell<PendingTradesListItem, PendingTradesListItem> call(TableColumn<PendingTradesListItem,
|
||||
PendingTradesListItem> column) {
|
||||
return new TableCell<>() {
|
||||
|
||||
@Override
|
||||
public void updateItem(PendingTradesListItem newItem, boolean empty) {
|
||||
super.updateItem(newItem, empty);
|
||||
if (!empty && newItem != null && isInvalidState(newItem.getTrade())) {
|
||||
Label icon = FormBuilder.getIcon(AwesomeIcon.TRASH);
|
||||
icon.getStyleClass().addAll("icon", "error-icon");
|
||||
JFXButton iconButton = new JFXButton("", icon);
|
||||
iconButton.setStyle("-fx-cursor: hand;");
|
||||
iconButton.getStyleClass().add("hidden-icon-button");
|
||||
iconButton.setTooltip(new Tooltip(Res.get("portfolio.pending.moveTradeToFailed")));
|
||||
iconButton.setOnAction(e -> onMoveTradeToFailedTrades(newItem.getTrade()));
|
||||
setGraphic(iconButton);
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
return moveTradeToFailedColumn;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -588,7 +588,6 @@ public abstract class TradeStepView extends AnchorPane {
|
|||
if (trade.getDepositTx() == null) {
|
||||
log.error("trade.getDepositTx() was null at openMediationResultPopup. " +
|
||||
"We add the trade to failed trades. TradeId={}", trade.getId());
|
||||
model.dataModel.addTradeToFailedTrades();
|
||||
new Popup().warning(Res.get("portfolio.pending.mediationResult.error.depositTxNull")).show();
|
||||
return;
|
||||
} else if (trade.getDelayedPayoutTx() == null) {
|
||||
|
|
|
@ -151,7 +151,7 @@ public class BuyerStep4View extends TradeStepView {
|
|||
|
||||
useSavingsWalletButton.setOnAction(e -> {
|
||||
handleTradeCompleted();
|
||||
model.dataModel.tradeManager.addTradeToClosedTrades(trade);
|
||||
model.dataModel.tradeManager.onTradeCompleted(trade);
|
||||
});
|
||||
withdrawToExternalWalletButton.setOnAction(e -> {
|
||||
onWithdrawal();
|
||||
|
@ -199,7 +199,7 @@ public class BuyerStep4View extends TradeStepView {
|
|||
Coin receiverAmount = amount.subtract(fee);
|
||||
if (balance.isZero()) {
|
||||
new Popup().warning(Res.get("portfolio.pending.step5_buyer.alreadyWithdrawn")).show();
|
||||
model.dataModel.tradeManager.addTradeToClosedTrades(trade);
|
||||
model.dataModel.tradeManager.onTradeCompleted(trade);
|
||||
} else {
|
||||
if (toAddresses.isEmpty()) {
|
||||
validateWithdrawAddress();
|
||||
|
|
|
@ -555,6 +555,11 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
|||
public void sendEncryptedMailboxMessage(NodeAddress peersNodeAddress, PubKeyRing peersPubKeyRing,
|
||||
NetworkEnvelope message,
|
||||
SendMailboxMessageListener sendMailboxMessageListener) {
|
||||
if (peersPubKeyRing == null) {
|
||||
log.error("sendEncryptedMailboxMessage: peersPubKeyRing is null. We ignore the call.");
|
||||
return;
|
||||
}
|
||||
|
||||
checkNotNull(peersNodeAddress,
|
||||
"PeerAddress must not be null (sendEncryptedMailboxMessage)");
|
||||
checkNotNull(networkNode.getNodeAddress(),
|
||||
|
|
Loading…
Add table
Reference in a new issue