support broadcasting maker and taker reserve txs in legacy ui
Co-authored-by: niyid <neeyeed@gmail.com>
This commit is contained in:
parent
34b79e779b
commit
ed0f458bc4
@ -702,6 +702,13 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ObservableList<SignedOffer> getObservableSignedOffersList() {
|
||||||
|
synchronized (signedOffers) {
|
||||||
|
return signedOffers.getObservableList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public ObservableList<OpenOffer> getObservableList() {
|
public ObservableList<OpenOffer> getObservableList() {
|
||||||
return openOffers.getObservableList();
|
return openOffers.getObservableList();
|
||||||
}
|
}
|
||||||
@ -1004,8 +1011,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||||||
SignedOffer signedOffer = new SignedOffer(
|
SignedOffer signedOffer = new SignedOffer(
|
||||||
System.currentTimeMillis(),
|
System.currentTimeMillis(),
|
||||||
signedOfferPayload.getId(),
|
signedOfferPayload.getId(),
|
||||||
offer.getAmount().longValue(),
|
HavenoUtils.coinToAtomicUnits(offer.getAmount()).longValueExact(),
|
||||||
HavenoUtils.getMakerFee(offer.getAmount()).longValue(), // TODO: these values are centineros, whereas reserve tx mining fee is BigInteger
|
HavenoUtils.coinToAtomicUnits(HavenoUtils.getMakerFee(offer.getAmount())).longValueExact(),
|
||||||
request.getReserveTxHash(),
|
request.getReserveTxHash(),
|
||||||
request.getReserveTxHex(),
|
request.getReserveTxHex(),
|
||||||
request.getReserveTxKeyImages(),
|
request.getReserveTxKeyImages(),
|
||||||
|
@ -17,11 +17,6 @@
|
|||||||
|
|
||||||
package bisq.core.trade;
|
package bisq.core.trade;
|
||||||
|
|
||||||
import bisq.common.config.Config;
|
|
||||||
import bisq.common.crypto.Hash;
|
|
||||||
import bisq.common.crypto.PubKeyRing;
|
|
||||||
import bisq.common.crypto.Sig;
|
|
||||||
import bisq.common.util.Utilities;
|
|
||||||
import bisq.core.offer.Offer;
|
import bisq.core.offer.Offer;
|
||||||
import bisq.core.offer.OfferPayload;
|
import bisq.core.offer.OfferPayload;
|
||||||
import bisq.core.support.dispute.arbitration.ArbitrationManager;
|
import bisq.core.support.dispute.arbitration.ArbitrationManager;
|
||||||
@ -33,11 +28,27 @@ import bisq.core.util.JsonUtil;
|
|||||||
import bisq.core.util.ParsingUtils;
|
import bisq.core.util.ParsingUtils;
|
||||||
import bisq.core.util.coin.CoinUtil;
|
import bisq.core.util.coin.CoinUtil;
|
||||||
import bisq.network.p2p.NodeAddress;
|
import bisq.network.p2p.NodeAddress;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
import bisq.common.config.Config;
|
||||||
|
import bisq.common.crypto.Hash;
|
||||||
|
import bisq.common.crypto.PubKeyRing;
|
||||||
|
import bisq.common.crypto.Sig;
|
||||||
|
import bisq.common.util.Utilities;
|
||||||
|
|
||||||
|
import org.bitcoinj.core.Coin;
|
||||||
|
import org.bitcoinj.utils.MonetaryFormat;
|
||||||
|
|
||||||
|
import com.google.common.base.CaseFormat;
|
||||||
|
import com.google.common.base.Charsets;
|
||||||
|
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.net.URI;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -47,12 +58,9 @@ import java.util.concurrent.Executors;
|
|||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import org.bitcoinj.core.Coin;
|
import javax.annotation.Nullable;
|
||||||
import org.bitcoinj.utils.MonetaryFormat;
|
|
||||||
import com.google.common.base.CaseFormat;
|
|
||||||
import com.google.common.base.Charsets;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collection of utilities.
|
* Collection of utilities.
|
||||||
@ -62,26 +70,19 @@ public class HavenoUtils {
|
|||||||
|
|
||||||
public static final String LOOPBACK_HOST = "127.0.0.1"; // local loopback address to host Monero node
|
public static final String LOOPBACK_HOST = "127.0.0.1"; // local loopback address to host Monero node
|
||||||
public static final String LOCALHOST = "localhost";
|
public static final String LOCALHOST = "localhost";
|
||||||
|
public static final BigInteger CENTINEROS_AU_MULTIPLIER = new BigInteger("10000");
|
||||||
// multipliers to convert units
|
private static final BigInteger XMR_AU_MULTIPLIER = new BigInteger("1000000000000");
|
||||||
public static BigInteger CENTINEROS_AU_MULTIPLIER = new BigInteger("10000");
|
public static final DecimalFormat XMR_FORMATTER = new DecimalFormat("0.000000000000");
|
||||||
private static BigInteger XMR_AU_MULTIPLIER = new BigInteger("1000000000000");
|
public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||||
|
|
||||||
// global thread pool
|
|
||||||
private static final int POOL_SIZE = 10;
|
private static final int POOL_SIZE = 10;
|
||||||
private static final ExecutorService POOL = Executors.newFixedThreadPool(POOL_SIZE);
|
private static final ExecutorService POOL = Executors.newFixedThreadPool(POOL_SIZE);
|
||||||
|
|
||||||
// TODO: better way to share reference?
|
public static ArbitrationManager arbitrationManager; // TODO: better way to share reference?
|
||||||
public static ArbitrationManager arbitrationManager;
|
|
||||||
|
|
||||||
public static BigInteger coinToAtomicUnits(Coin coin) {
|
public static BigInteger coinToAtomicUnits(Coin coin) {
|
||||||
return centinerosToAtomicUnits(coin.value);
|
return centinerosToAtomicUnits(coin.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double coinToXmr(Coin coin) {
|
|
||||||
return atomicUnitsToXmr(coinToAtomicUnits(coin));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BigInteger centinerosToAtomicUnits(long centineros) {
|
public static BigInteger centinerosToAtomicUnits(long centineros) {
|
||||||
return BigInteger.valueOf(centineros).multiply(CENTINEROS_AU_MULTIPLIER);
|
return BigInteger.valueOf(centineros).multiply(CENTINEROS_AU_MULTIPLIER);
|
||||||
}
|
}
|
||||||
@ -102,10 +103,18 @@ public class HavenoUtils {
|
|||||||
return atomicUnits.divide(CENTINEROS_AU_MULTIPLIER).longValueExact();
|
return atomicUnits.divide(CENTINEROS_AU_MULTIPLIER).longValueExact();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Coin atomicUnitsToCoin(BigInteger atomicUnits) {
|
public static Coin atomicUnitsToCoin(long atomicUnits) {
|
||||||
return Coin.valueOf(atomicUnitsToCentineros(atomicUnits));
|
return Coin.valueOf(atomicUnitsToCentineros(atomicUnits));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Coin atomicUnitsToCoin(BigInteger atomicUnits) {
|
||||||
|
return atomicUnitsToCoin(atomicUnits.longValueExact());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double atomicUnitsToXmr(long atomicUnits) {
|
||||||
|
return atomicUnitsToXmr(BigInteger.valueOf(atomicUnits));
|
||||||
|
}
|
||||||
|
|
||||||
public static double atomicUnitsToXmr(BigInteger atomicUnits) {
|
public static double atomicUnitsToXmr(BigInteger atomicUnits) {
|
||||||
return new BigDecimal(atomicUnits).divide(new BigDecimal(XMR_AU_MULTIPLIER)).doubleValue();
|
return new BigDecimal(atomicUnits).divide(new BigDecimal(XMR_AU_MULTIPLIER)).doubleValue();
|
||||||
}
|
}
|
||||||
@ -118,6 +127,26 @@ public class HavenoUtils {
|
|||||||
return atomicUnitsToCentineros(xmrToAtomicUnits(xmr));
|
return atomicUnitsToCentineros(xmrToAtomicUnits(xmr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static double coinToXmr(Coin coin) {
|
||||||
|
return atomicUnitsToXmr(coinToAtomicUnits(coin));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String formatXmrWithCode(Coin coin) {
|
||||||
|
return formatXmrWithCode(coinToAtomicUnits(coin).longValueExact());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String formatXmrWithCode(long atomicUnits) {
|
||||||
|
String formatted = XMR_FORMATTER.format(atomicUnitsToXmr(atomicUnits));
|
||||||
|
|
||||||
|
// strip trailing 0s
|
||||||
|
if (formatted.contains(".")) {
|
||||||
|
while (formatted.length() > 3 && formatted.charAt(formatted.length() - 1) == '0') {
|
||||||
|
formatted = formatted.substring(0, formatted.length() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return formatted.concat(" ").concat("XMR");
|
||||||
|
}
|
||||||
|
|
||||||
private static final MonetaryFormat xmrCoinFormat = Config.baseCurrencyNetworkParameters().getMonetaryFormat();
|
private static final MonetaryFormat xmrCoinFormat = Config.baseCurrencyNetworkParameters().getMonetaryFormat();
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -226,6 +226,8 @@ shared.numItemsLabel=Number of entries: {0}
|
|||||||
shared.filter=Filter
|
shared.filter=Filter
|
||||||
shared.enabled=Enabled
|
shared.enabled=Enabled
|
||||||
shared.me=Me
|
shared.me=Me
|
||||||
|
shared.maker=Maker
|
||||||
|
shared.taker=Taker
|
||||||
|
|
||||||
|
|
||||||
####################################################################
|
####################################################################
|
||||||
@ -990,7 +992,11 @@ portfolio.failed.cantUnfail=This trade cannot be moved back to open trades at th
|
|||||||
Try again after completion of trade(s) {0}
|
Try again after completion of trade(s) {0}
|
||||||
portfolio.failed.depositTxNull=The trade cannot be reverted to a open trade. Deposit 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.
|
portfolio.failed.delayedPayoutTxNull=The trade cannot be reverted to a open trade. Delayed payout transaction is null.
|
||||||
|
portfolio.failed.penalty.msg=This will charge the {0}/{1} the trade fee of {2} and return the remaining trade funds to their wallet. Are you sure you want to send?\n\n\
|
||||||
|
Other Info:\n\
|
||||||
|
Transaction Fee: {3}\n\
|
||||||
|
Reserve Tx Hash: {4}
|
||||||
|
portfolio.failed.error.msg=Trade record does not exist.
|
||||||
|
|
||||||
####################################################################
|
####################################################################
|
||||||
# Funds
|
# Funds
|
||||||
@ -1089,6 +1095,18 @@ support.tab.legacyArbitration.support=Legacy Arbitration
|
|||||||
support.tab.ArbitratorsSupportTickets={0}'s tickets
|
support.tab.ArbitratorsSupportTickets={0}'s tickets
|
||||||
support.filter=Search disputes
|
support.filter=Search disputes
|
||||||
support.filter.prompt=Enter trade ID, date, onion address or account data
|
support.filter.prompt=Enter trade ID, date, onion address or account data
|
||||||
|
support.tab.SignedOffers=Signed Offers
|
||||||
|
support.prompt.signedOffer.penalty.msg=This will charge the maker the trade fee and return their remaining trade funds to their wallet. Are you sure you want to send?\n\n\
|
||||||
|
Offer ID: {0}\n\
|
||||||
|
Maker Trade Fee: {1}\n\
|
||||||
|
Reserve Tx Miner Fee: {2}\n\
|
||||||
|
Reserve Tx Hash: {3}\n\
|
||||||
|
Reserve Tx Key Images: {4}\n\
|
||||||
|
|
||||||
|
support.contextmenu.penalize.msg=Penalize {0} by publishing reserve tx
|
||||||
|
support.prompt.signedOffer.error.msg=Signed Offer record does not exist; contact administrator.
|
||||||
|
support.info.submitTxHex=Reserve transaction has been published with the following result:\n
|
||||||
|
support.result.success=Transaction hex has been successfully submitted.
|
||||||
|
|
||||||
support.sigCheck.button=Check signature
|
support.sigCheck.button=Check signature
|
||||||
support.sigCheck.popup.info=In case of a reimbursement request to the DAO you need to paste the summary message of the \
|
support.sigCheck.popup.info=In case of a reimbursement request to the DAO you need to paste the summary message of the \
|
||||||
@ -1148,6 +1166,12 @@ support.buyerMaker=XMR buyer/Maker
|
|||||||
support.sellerMaker=XMR seller/Maker
|
support.sellerMaker=XMR seller/Maker
|
||||||
support.buyerTaker=XMR buyer/Taker
|
support.buyerTaker=XMR buyer/Taker
|
||||||
support.sellerTaker=XMR seller/Taker
|
support.sellerTaker=XMR seller/Taker
|
||||||
|
support.txKeyImages=Key Images
|
||||||
|
support.txHash=Transaction Hash
|
||||||
|
support.txHex=Transaction Hex
|
||||||
|
support.signature=Signature
|
||||||
|
support.maker.trade.fee=Maker Trade Fee
|
||||||
|
support.tx.miner.fee=Miner Fee
|
||||||
|
|
||||||
support.backgroundInfo=Haveno is not a company, so it handles disputes differently.\n\n\
|
support.backgroundInfo=Haveno is not a company, so it handles disputes differently.\n\n\
|
||||||
Traders can communicate within the application via secure chat on the open trades screen to try solving disputes on their own. \
|
Traders can communicate within the application via secure chat on the open trades screen to try solving disputes on their own. \
|
||||||
|
@ -21,7 +21,6 @@ import bisq.desktop.Navigation;
|
|||||||
import bisq.desktop.components.AutoTooltipButton;
|
import bisq.desktop.components.AutoTooltipButton;
|
||||||
import bisq.desktop.components.AutoTooltipLabel;
|
import bisq.desktop.components.AutoTooltipLabel;
|
||||||
import bisq.desktop.components.HyperlinkWithIcon;
|
import bisq.desktop.components.HyperlinkWithIcon;
|
||||||
import bisq.desktop.main.MainView;
|
|
||||||
import bisq.desktop.main.offer.offerbook.BtcOfferBookView;
|
import bisq.desktop.main.offer.offerbook.BtcOfferBookView;
|
||||||
import bisq.desktop.main.offer.offerbook.OfferBookView;
|
import bisq.desktop.main.offer.offerbook.OfferBookView;
|
||||||
import bisq.desktop.main.offer.offerbook.OtherOfferBookView;
|
import bisq.desktop.main.offer.offerbook.OtherOfferBookView;
|
||||||
@ -29,6 +28,7 @@ import bisq.desktop.main.offer.offerbook.TopAltcoinOfferBookView;
|
|||||||
import bisq.desktop.main.overlays.popups.Popup;
|
import bisq.desktop.main.overlays.popups.Popup;
|
||||||
import bisq.desktop.util.GUIUtil;
|
import bisq.desktop.util.GUIUtil;
|
||||||
|
|
||||||
|
import bisq.core.btc.wallet.XmrWalletService;
|
||||||
import bisq.core.locale.CryptoCurrency;
|
import bisq.core.locale.CryptoCurrency;
|
||||||
import bisq.core.locale.CurrencyUtil;
|
import bisq.core.locale.CurrencyUtil;
|
||||||
import bisq.core.locale.Res;
|
import bisq.core.locale.Res;
|
||||||
@ -40,6 +40,7 @@ import bisq.common.UserThread;
|
|||||||
import bisq.common.util.Tuple2;
|
import bisq.common.util.Tuple2;
|
||||||
|
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.TableView;
|
||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
@ -54,9 +55,16 @@ import java.util.Objects;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import monero.daemon.model.MoneroSubmitTxResult;
|
||||||
|
|
||||||
// Shared utils for Views
|
// Shared utils for Views
|
||||||
|
@Slf4j
|
||||||
public class OfferViewUtil {
|
public class OfferViewUtil {
|
||||||
|
|
||||||
public static Label createPopOverLabel(String text) {
|
public static Label createPopOverLabel(String text) {
|
||||||
@ -166,4 +174,18 @@ public class OfferViewUtil {
|
|||||||
return CurrencyUtil.getMainCryptoCurrencies().stream().filter(cryptoCurrency ->
|
return CurrencyUtil.getMainCryptoCurrencies().stream().filter(cryptoCurrency ->
|
||||||
!Objects.equals(cryptoCurrency.getCode(), GUIUtil.TOP_ALTCOIN.getCode()));
|
!Objects.equals(cryptoCurrency.getCode(), GUIUtil.TOP_ALTCOIN.getCode()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void submitTransactionHex(XmrWalletService xmrWalletService,
|
||||||
|
TableView tableView,
|
||||||
|
String reserveTxHex) {
|
||||||
|
MoneroSubmitTxResult result = xmrWalletService.getDaemon().submitTxHex(reserveTxHex);
|
||||||
|
log.info("submitTransactionHex: reserveTxHex={} result={}", result);
|
||||||
|
tableView.refresh();
|
||||||
|
|
||||||
|
if(result.isGood()) {
|
||||||
|
new Popup().information(Res.get("support.result.success")).show();
|
||||||
|
} else {
|
||||||
|
new Popup().attention(result.toString()).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,23 +23,26 @@ import bisq.desktop.components.AutoTooltipButton;
|
|||||||
import bisq.desktop.components.AutoTooltipLabel;
|
import bisq.desktop.components.AutoTooltipLabel;
|
||||||
import bisq.desktop.components.HyperlinkWithIcon;
|
import bisq.desktop.components.HyperlinkWithIcon;
|
||||||
import bisq.desktop.components.InputTextField;
|
import bisq.desktop.components.InputTextField;
|
||||||
|
import bisq.desktop.main.offer.OfferViewUtil;
|
||||||
import bisq.desktop.main.overlays.popups.Popup;
|
import bisq.desktop.main.overlays.popups.Popup;
|
||||||
import bisq.desktop.main.overlays.windows.TradeDetailsWindow;
|
import bisq.desktop.main.overlays.windows.TradeDetailsWindow;
|
||||||
import bisq.desktop.util.FormBuilder;
|
import bisq.desktop.util.FormBuilder;
|
||||||
import bisq.desktop.util.GUIUtil;
|
import bisq.desktop.util.GUIUtil;
|
||||||
|
|
||||||
|
import bisq.core.btc.wallet.XmrWalletService;
|
||||||
import bisq.core.locale.Res;
|
import bisq.core.locale.Res;
|
||||||
import bisq.core.offer.Offer;
|
import bisq.core.offer.Offer;
|
||||||
import bisq.core.trade.Contract;
|
import bisq.core.trade.Contract;
|
||||||
|
import bisq.core.trade.HavenoUtils;
|
||||||
import bisq.core.trade.Trade;
|
import bisq.core.trade.Trade;
|
||||||
|
|
||||||
import bisq.common.config.Config;
|
|
||||||
import bisq.common.util.Utilities;
|
import bisq.common.util.Utilities;
|
||||||
|
|
||||||
|
import org.bitcoinj.core.Coin;
|
||||||
|
|
||||||
import com.googlecode.jcsv.writer.CSVEntryConverter;
|
import com.googlecode.jcsv.writer.CSVEntryConverter;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
|
||||||
|
|
||||||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||||
|
|
||||||
@ -50,9 +53,12 @@ import javafx.fxml.FXML;
|
|||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
|
import javafx.scene.control.ContextMenu;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.MenuItem;
|
||||||
import javafx.scene.control.TableCell;
|
import javafx.scene.control.TableCell;
|
||||||
import javafx.scene.control.TableColumn;
|
import javafx.scene.control.TableColumn;
|
||||||
|
import javafx.scene.control.TableRow;
|
||||||
import javafx.scene.control.TableView;
|
import javafx.scene.control.TableView;
|
||||||
import javafx.scene.control.Tooltip;
|
import javafx.scene.control.Tooltip;
|
||||||
import javafx.scene.input.KeyCode;
|
import javafx.scene.input.KeyCode;
|
||||||
@ -107,12 +113,16 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||||||
private EventHandler<KeyEvent> keyEventEventHandler;
|
private EventHandler<KeyEvent> keyEventEventHandler;
|
||||||
private ChangeListener<String> filterTextFieldListener;
|
private ChangeListener<String> filterTextFieldListener;
|
||||||
private Scene scene;
|
private Scene scene;
|
||||||
|
private XmrWalletService xmrWalletService;
|
||||||
|
private ContextMenu contextMenu;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public FailedTradesView(FailedTradesViewModel model,
|
public FailedTradesView(FailedTradesViewModel model,
|
||||||
TradeDetailsWindow tradeDetailsWindow) {
|
TradeDetailsWindow tradeDetailsWindow,
|
||||||
|
XmrWalletService xmrWalletService) {
|
||||||
super(model);
|
super(model);
|
||||||
this.tradeDetailsWindow = tradeDetailsWindow;
|
this.tradeDetailsWindow = tradeDetailsWindow;
|
||||||
|
this.xmrWalletService = xmrWalletService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -195,6 +205,39 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||||||
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
||||||
tableView.setItems(sortedList);
|
tableView.setItems(sortedList);
|
||||||
|
|
||||||
|
contextMenu = new ContextMenu();
|
||||||
|
MenuItem item1 = new MenuItem(Res.get("support.contextmenu.penalize.msg", Res.get("shared.maker")));
|
||||||
|
MenuItem item2 = new MenuItem(Res.get("support.contextmenu.penalize.msg", Res.get("shared.taker")));
|
||||||
|
contextMenu.getItems().addAll(item1, item2);
|
||||||
|
|
||||||
|
tableView.setRowFactory(tv -> {
|
||||||
|
TableRow<FailedTradesListItem> row = new TableRow<>();
|
||||||
|
row.setOnContextMenuRequested(event -> {
|
||||||
|
contextMenu.show(row, event.getScreenX(), event.getScreenY());
|
||||||
|
});
|
||||||
|
return row;
|
||||||
|
});
|
||||||
|
|
||||||
|
item1.setOnAction(event -> {
|
||||||
|
Trade selectedFailedTrade = tableView.getSelectionModel().getSelectedItem().getTrade();
|
||||||
|
handleContextMenu("portfolio.failed.penalty.msg",
|
||||||
|
Res.get(selectedFailedTrade.getMaker() == selectedFailedTrade.getBuyer() ? "shared.buyer" : "shared.seller"),
|
||||||
|
Res.get("shared.maker"),
|
||||||
|
selectedFailedTrade.getMakerFee(),
|
||||||
|
selectedFailedTrade.getMaker().getReserveTxHash(),
|
||||||
|
selectedFailedTrade.getMaker().getReserveTxHex());
|
||||||
|
});
|
||||||
|
|
||||||
|
item2.setOnAction(event -> {
|
||||||
|
Trade selectedFailedTrade = tableView.getSelectionModel().getSelectedItem().getTrade();
|
||||||
|
handleContextMenu("portfolio.failed.penalty.msg",
|
||||||
|
Res.get(selectedFailedTrade.getTaker() == selectedFailedTrade.getBuyer() ? "shared.buyer" : "shared.seller"),
|
||||||
|
Res.get("shared.taker"),
|
||||||
|
selectedFailedTrade.getTakerFee(),
|
||||||
|
selectedFailedTrade.getTaker().getReserveTxHash(),
|
||||||
|
selectedFailedTrade.getTaker().getReserveTxHex());
|
||||||
|
});
|
||||||
|
|
||||||
numItems.setText(Res.get("shared.numItemsLabel", sortedList.size()));
|
numItems.setText(Res.get("shared.numItemsLabel", sortedList.size()));
|
||||||
exportButton.setOnAction(event -> {
|
exportButton.setOnAction(event -> {
|
||||||
ObservableList<TableColumn<FailedTradesListItem, ?>> tableColumns = tableView.getColumns();
|
ObservableList<TableColumn<FailedTradesListItem, ?>> tableColumns = tableView.getColumns();
|
||||||
@ -230,6 +273,23 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||||||
applyFilteredListPredicate(filterTextField.getText());
|
applyFilteredListPredicate(filterTextField.getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleContextMenu(String msgKey, String buyerOrSeller, String makerOrTaker, Coin fee, String reserveTxHash, String reserveTxHex) {
|
||||||
|
final Trade failedTrade = tableView.getSelectionModel().getSelectedItem().getTrade();
|
||||||
|
log.debug("Found {} matching trade.", (failedTrade != null ? failedTrade.getId() : null));
|
||||||
|
if(failedTrade != null) {
|
||||||
|
new Popup().warning(Res.get(msgKey,
|
||||||
|
buyerOrSeller,
|
||||||
|
makerOrTaker,
|
||||||
|
HavenoUtils.formatXmrWithCode(fee),
|
||||||
|
"todo", // TODO: set reserve tx miner fee when verified
|
||||||
|
reserveTxHash
|
||||||
|
)
|
||||||
|
).onAction(() -> OfferViewUtil.submitTransactionHex(xmrWalletService, tableView, reserveTxHex)).show();
|
||||||
|
} else {
|
||||||
|
new Popup().error(Res.get("portfolio.failed.error.msg")).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void deactivate() {
|
protected void deactivate() {
|
||||||
if (scene != null) {
|
if (scene != null) {
|
||||||
|
@ -22,14 +22,11 @@ import bisq.desktop.common.view.ActivatableViewAndModel;
|
|||||||
import bisq.desktop.common.view.FxmlView;
|
import bisq.desktop.common.view.FxmlView;
|
||||||
import bisq.desktop.components.AutoTooltipLabel;
|
import bisq.desktop.components.AutoTooltipLabel;
|
||||||
import bisq.desktop.components.HyperlinkWithIcon;
|
import bisq.desktop.components.HyperlinkWithIcon;
|
||||||
import bisq.desktop.components.PeerInfoIcon;
|
|
||||||
import bisq.desktop.components.PeerInfoIconTrading;
|
import bisq.desktop.components.PeerInfoIconTrading;
|
||||||
import bisq.desktop.components.list.FilterBox;
|
import bisq.desktop.components.list.FilterBox;
|
||||||
import bisq.desktop.main.MainView;
|
import bisq.desktop.main.MainView;
|
||||||
import bisq.desktop.main.overlays.popups.Popup;
|
import bisq.desktop.main.overlays.popups.Popup;
|
||||||
import bisq.desktop.main.overlays.windows.TradeDetailsWindow;
|
import bisq.desktop.main.overlays.windows.TradeDetailsWindow;
|
||||||
import bisq.desktop.main.portfolio.PortfolioView;
|
|
||||||
import bisq.desktop.main.portfolio.duplicateoffer.DuplicateOfferView;
|
|
||||||
import bisq.desktop.main.portfolio.presentation.PortfolioUtil;
|
import bisq.desktop.main.portfolio.presentation.PortfolioUtil;
|
||||||
import bisq.desktop.main.shared.ChatView;
|
import bisq.desktop.main.shared.ChatView;
|
||||||
import bisq.desktop.util.CssTheme;
|
import bisq.desktop.util.CssTheme;
|
||||||
@ -55,7 +52,6 @@ import bisq.network.p2p.NodeAddress;
|
|||||||
import bisq.common.UserThread;
|
import bisq.common.UserThread;
|
||||||
import bisq.common.config.Config;
|
import bisq.common.config.Config;
|
||||||
import bisq.common.crypto.KeyRing;
|
import bisq.common.crypto.KeyRing;
|
||||||
import bisq.common.crypto.PubKeyRing;
|
|
||||||
import bisq.common.util.Utilities;
|
import bisq.common.util.Utilities;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
@ -25,6 +25,7 @@ import bisq.desktop.common.view.View;
|
|||||||
import bisq.desktop.common.view.ViewLoader;
|
import bisq.desktop.common.view.ViewLoader;
|
||||||
import bisq.desktop.main.MainView;
|
import bisq.desktop.main.MainView;
|
||||||
import bisq.desktop.main.overlays.popups.Popup;
|
import bisq.desktop.main.overlays.popups.Popup;
|
||||||
|
import bisq.desktop.main.support.dispute.agent.SignedOfferView;
|
||||||
import bisq.desktop.main.support.dispute.agent.arbitration.ArbitratorView;
|
import bisq.desktop.main.support.dispute.agent.arbitration.ArbitratorView;
|
||||||
import bisq.desktop.main.support.dispute.agent.mediation.MediatorView;
|
import bisq.desktop.main.support.dispute.agent.mediation.MediatorView;
|
||||||
import bisq.desktop.main.support.dispute.agent.refund.RefundAgentView;
|
import bisq.desktop.main.support.dispute.agent.refund.RefundAgentView;
|
||||||
@ -69,7 +70,8 @@ public class SupportView extends ActivatableView<TabPane, Void> {
|
|||||||
private Tab mediatorTab, refundAgentTab;
|
private Tab mediatorTab, refundAgentTab;
|
||||||
@Nullable
|
@Nullable
|
||||||
private Tab arbitratorTab;
|
private Tab arbitratorTab;
|
||||||
|
@Nullable
|
||||||
|
private Tab signedOfferTab;
|
||||||
private final Navigation navigation;
|
private final Navigation navigation;
|
||||||
private final ArbitratorManager arbitratorManager;
|
private final ArbitratorManager arbitratorManager;
|
||||||
private final MediatorManager mediatorManager;
|
private final MediatorManager mediatorManager;
|
||||||
@ -77,6 +79,7 @@ public class SupportView extends ActivatableView<TabPane, Void> {
|
|||||||
private final ArbitrationManager arbitrationManager;
|
private final ArbitrationManager arbitrationManager;
|
||||||
private final MediationManager mediationManager;
|
private final MediationManager mediationManager;
|
||||||
private final RefundManager refundManager;
|
private final RefundManager refundManager;
|
||||||
|
|
||||||
private final KeyRing keyRing;
|
private final KeyRing keyRing;
|
||||||
|
|
||||||
private Navigation.Listener navigationListener;
|
private Navigation.Listener navigationListener;
|
||||||
@ -143,6 +146,8 @@ public class SupportView extends ActivatableView<TabPane, Void> {
|
|||||||
navigation.navigateTo(MainView.class, SupportView.class, RefundClientView.class);
|
navigation.navigateTo(MainView.class, SupportView.class, RefundClientView.class);
|
||||||
else if (newValue == arbitratorTab)
|
else if (newValue == arbitratorTab)
|
||||||
navigation.navigateTo(MainView.class, SupportView.class, ArbitratorView.class);
|
navigation.navigateTo(MainView.class, SupportView.class, ArbitratorView.class);
|
||||||
|
else if (newValue == signedOfferTab)
|
||||||
|
navigation.navigateTo(MainView.class, SupportView.class, SignedOfferView.class);
|
||||||
else if (newValue == mediatorTab)
|
else if (newValue == mediatorTab)
|
||||||
navigation.navigateTo(MainView.class, SupportView.class, MediatorView.class);
|
navigation.navigateTo(MainView.class, SupportView.class, MediatorView.class);
|
||||||
else if (newValue == refundAgentTab)
|
else if (newValue == refundAgentTab)
|
||||||
@ -161,17 +166,16 @@ public class SupportView extends ActivatableView<TabPane, Void> {
|
|||||||
if (hasArbitrationCases) {
|
if (hasArbitrationCases) {
|
||||||
boolean isActiveArbitrator = arbitratorManager.getObservableMap().values().stream()
|
boolean isActiveArbitrator = arbitratorManager.getObservableMap().values().stream()
|
||||||
.anyMatch(e -> e.getPubKeyRing() != null && e.getPubKeyRing().equals(myPubKeyRing));
|
.anyMatch(e -> e.getPubKeyRing() != null && e.getPubKeyRing().equals(myPubKeyRing));
|
||||||
if (arbitratorTab == null) {
|
|
||||||
// In case a arbitrator has become inactive he still might get disputes from pending trades
|
// In case a arbitrator has become inactive he still might get disputes from pending trades
|
||||||
boolean hasDisputesAsArbitrator = arbitrationManager.getDisputesAsObservableList().stream()
|
boolean hasDisputesAsArbitrator = arbitrationManager.getDisputesAsObservableList().stream()
|
||||||
.anyMatch(d -> d.getAgentPubKeyRing().equals(myPubKeyRing));
|
.anyMatch(d -> d.getAgentPubKeyRing().equals(myPubKeyRing));
|
||||||
if (isActiveArbitrator || hasDisputesAsArbitrator) {
|
if (arbitratorTab == null && (isActiveArbitrator || hasDisputesAsArbitrator)) {
|
||||||
arbitratorTab = new Tab();
|
arbitratorTab = new Tab();
|
||||||
arbitratorTab.setClosable(false);
|
arbitratorTab.setClosable(false);
|
||||||
root.getTabs().add(arbitratorTab);
|
root.getTabs().add(arbitratorTab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
boolean isActiveMediator = mediatorManager.getObservableMap().values().stream()
|
boolean isActiveMediator = mediatorManager.getObservableMap().values().stream()
|
||||||
.anyMatch(e -> e.getPubKeyRing() != null && e.getPubKeyRing().equals(myPubKeyRing));
|
.anyMatch(e -> e.getPubKeyRing() != null && e.getPubKeyRing().equals(myPubKeyRing));
|
||||||
@ -186,6 +190,12 @@ public class SupportView extends ActivatableView<TabPane, Void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (signedOfferTab == null) {
|
||||||
|
signedOfferTab = new Tab();
|
||||||
|
signedOfferTab.setClosable(false);
|
||||||
|
root.getTabs().add(signedOfferTab);
|
||||||
|
}
|
||||||
|
|
||||||
boolean isActiveRefundAgent = refundAgentManager.getObservableMap().values().stream()
|
boolean isActiveRefundAgent = refundAgentManager.getObservableMap().values().stream()
|
||||||
.anyMatch(e -> e.getPubKeyRing() != null && e.getPubKeyRing().equals(myPubKeyRing));
|
.anyMatch(e -> e.getPubKeyRing() != null && e.getPubKeyRing().equals(myPubKeyRing));
|
||||||
if (refundAgentTab == null) {
|
if (refundAgentTab == null) {
|
||||||
@ -203,6 +213,9 @@ public class SupportView extends ActivatableView<TabPane, Void> {
|
|||||||
if (arbitratorTab != null) {
|
if (arbitratorTab != null) {
|
||||||
arbitratorTab.setText(Res.get("support.tab.ArbitratorsSupportTickets", Res.get("shared.arbitrator")).toUpperCase());
|
arbitratorTab.setText(Res.get("support.tab.ArbitratorsSupportTickets", Res.get("shared.arbitrator")).toUpperCase());
|
||||||
}
|
}
|
||||||
|
if (signedOfferTab != null) {
|
||||||
|
signedOfferTab.setText(Res.get("support.tab.SignedOffers").toUpperCase());
|
||||||
|
}
|
||||||
if (mediatorTab != null) {
|
if (mediatorTab != null) {
|
||||||
mediatorTab.setText(Res.get("support.tab.ArbitratorsSupportTickets", Res.get("shared.mediator")).toUpperCase());
|
mediatorTab.setText(Res.get("support.tab.ArbitratorsSupportTickets", Res.get("shared.mediator")).toUpperCase());
|
||||||
}
|
}
|
||||||
@ -235,6 +248,8 @@ public class SupportView extends ActivatableView<TabPane, Void> {
|
|||||||
navigation.navigateTo(MainView.class, SupportView.class, RefundClientView.class);
|
navigation.navigateTo(MainView.class, SupportView.class, RefundClientView.class);
|
||||||
} else if (arbitratorTab != null) {
|
} else if (arbitratorTab != null) {
|
||||||
navigation.navigateTo(MainView.class, SupportView.class, ArbitratorView.class);
|
navigation.navigateTo(MainView.class, SupportView.class, ArbitratorView.class);
|
||||||
|
} else if (signedOfferTab != null) {
|
||||||
|
navigation.navigateTo(MainView.class, SupportView.class, SignedOfferView.class);
|
||||||
} else if (mediatorTab != null) {
|
} else if (mediatorTab != null) {
|
||||||
navigation.navigateTo(MainView.class, SupportView.class, MediatorView.class);
|
navigation.navigateTo(MainView.class, SupportView.class, MediatorView.class);
|
||||||
} else if (refundAgentTab != null) {
|
} else if (refundAgentTab != null) {
|
||||||
@ -275,6 +290,8 @@ public class SupportView extends ActivatableView<TabPane, Void> {
|
|||||||
currentTab = tradersRefundDisputesTab;
|
currentTab = tradersRefundDisputesTab;
|
||||||
} else if (view instanceof ArbitratorView) {
|
} else if (view instanceof ArbitratorView) {
|
||||||
currentTab = arbitratorTab;
|
currentTab = arbitratorTab;
|
||||||
|
} else if (view instanceof SignedOfferView) {
|
||||||
|
currentTab = signedOfferTab;
|
||||||
} else if (view instanceof MediatorView) {
|
} else if (view instanceof MediatorView) {
|
||||||
currentTab = mediatorTab;
|
currentTab = mediatorTab;
|
||||||
} else if (view instanceof RefundAgentView) {
|
} else if (view instanceof RefundAgentView) {
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
~ This file is part of Haveno.
|
||||||
|
~
|
||||||
|
~ Haveno is free software: you can redistribute it and/or modify it
|
||||||
|
~ under the terms of the GNU Affero General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or (at
|
||||||
|
~ your option) any later version.
|
||||||
|
~
|
||||||
|
~ Haveno is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
~ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
~ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||||
|
~ License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU Affero General Public License
|
||||||
|
~ along with Haveno. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<?import javafx.scene.control.Label?>
|
||||||
|
<?import javafx.scene.control.TableColumn?>
|
||||||
|
<?import javafx.scene.control.TableView?>
|
||||||
|
<?import javafx.scene.layout.HBox?>
|
||||||
|
<?import javafx.scene.layout.Pane?>
|
||||||
|
<?import javafx.scene.layout.Region?>
|
||||||
|
<?import javafx.scene.layout.VBox?>
|
||||||
|
<?import javafx.geometry.Insets?>
|
||||||
|
<VBox fx:id="root" fx:controller="bisq.desktop.main.support.dispute.agent.SignedOfferView"
|
||||||
|
spacing="10" xmlns:fx="http://javafx.com/fxml">
|
||||||
|
<padding>
|
||||||
|
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0"/>
|
||||||
|
</padding>
|
||||||
|
<TableView fx:id="tableView" VBox.vgrow="ALWAYS" />
|
||||||
|
<HBox spacing="10">
|
||||||
|
<Label fx:id="numItems"/>
|
||||||
|
<Region fx:id="footerSpacer"/>
|
||||||
|
</HBox>
|
||||||
|
</VBox>
|
@ -0,0 +1,444 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Haveno.
|
||||||
|
*
|
||||||
|
* Haveno is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* Haveno is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||||
|
* License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with Haveno. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package bisq.desktop.main.support.dispute.agent;
|
||||||
|
|
||||||
|
import bisq.desktop.common.view.ActivatableView;
|
||||||
|
import bisq.desktop.common.view.FxmlView;
|
||||||
|
import bisq.desktop.components.AutoTooltipLabel;
|
||||||
|
import bisq.desktop.components.AutoTooltipTableColumn;
|
||||||
|
import bisq.desktop.components.HyperlinkWithIcon;
|
||||||
|
import bisq.desktop.components.InputTextField;
|
||||||
|
import bisq.desktop.main.offer.OfferViewUtil;
|
||||||
|
import bisq.desktop.main.overlays.popups.Popup;
|
||||||
|
import bisq.desktop.util.DisplayUtils;
|
||||||
|
import bisq.desktop.util.GUIUtil;
|
||||||
|
import bisq.common.UserThread;
|
||||||
|
import bisq.core.btc.wallet.XmrWalletService;
|
||||||
|
import bisq.core.locale.Res;
|
||||||
|
import bisq.core.offer.OpenOfferManager;
|
||||||
|
import bisq.core.offer.SignedOffer;
|
||||||
|
import bisq.core.trade.HavenoUtils;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
|
||||||
|
import javafx.scene.control.ContextMenu;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.MenuItem;
|
||||||
|
import javafx.scene.control.TableCell;
|
||||||
|
import javafx.scene.control.TableColumn;
|
||||||
|
import javafx.scene.control.TableRow;
|
||||||
|
import javafx.scene.control.TableView;
|
||||||
|
import javafx.scene.control.Tooltip;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
import javafx.scene.layout.Priority;
|
||||||
|
import javafx.scene.layout.Region;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
|
||||||
|
import javafx.geometry.Insets;
|
||||||
|
|
||||||
|
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||||
|
|
||||||
|
import javafx.collections.ListChangeListener;
|
||||||
|
import javafx.collections.transformation.SortedList;
|
||||||
|
|
||||||
|
import javafx.util.Callback;
|
||||||
|
import javafx.util.Duration;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@FxmlView
|
||||||
|
public class SignedOfferView extends ActivatableView<VBox, Void> {
|
||||||
|
|
||||||
|
private final OpenOfferManager openOfferManager;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
protected TableView<SignedOffer> tableView;
|
||||||
|
@FXML
|
||||||
|
TableColumn<SignedOffer, SignedOffer> dateColumn;
|
||||||
|
@FXML
|
||||||
|
TableColumn<SignedOffer, SignedOffer> offerIdColumn;
|
||||||
|
@FXML
|
||||||
|
TableColumn<SignedOffer, SignedOffer> reserveTxHashColumn;
|
||||||
|
@FXML
|
||||||
|
TableColumn<SignedOffer, SignedOffer> reserveTxHexColumn;
|
||||||
|
@FXML
|
||||||
|
TableColumn<SignedOffer, SignedOffer> reserveTxKeyImages;
|
||||||
|
@FXML
|
||||||
|
TableColumn<SignedOffer, SignedOffer> arbitratorSignatureColumn;
|
||||||
|
@FXML
|
||||||
|
TableColumn<SignedOffer, SignedOffer> reserveTxMinerFeeColumn;
|
||||||
|
@FXML
|
||||||
|
TableColumn<SignedOffer, SignedOffer> makerTradeFeeColumn;
|
||||||
|
@FXML
|
||||||
|
InputTextField filterTextField;
|
||||||
|
@FXML
|
||||||
|
Label numItems;
|
||||||
|
@FXML
|
||||||
|
Region footerSpacer;
|
||||||
|
|
||||||
|
private SignedOffer selectedSignedOffer;
|
||||||
|
|
||||||
|
private XmrWalletService xmrWalletService;
|
||||||
|
|
||||||
|
private ContextMenu contextMenu;
|
||||||
|
|
||||||
|
private final ListChangeListener<SignedOffer> signedOfferListChangeListener;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public SignedOfferView(OpenOfferManager openOfferManager, XmrWalletService xmrWalletService) {
|
||||||
|
this.openOfferManager = openOfferManager;
|
||||||
|
this.xmrWalletService = xmrWalletService;
|
||||||
|
|
||||||
|
signedOfferListChangeListener = change -> applyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyList() {
|
||||||
|
UserThread.execute(() -> {
|
||||||
|
SortedList<SignedOffer> sortedList = new SortedList<>(openOfferManager.getObservableSignedOffersList());
|
||||||
|
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
||||||
|
tableView.setItems(sortedList);
|
||||||
|
numItems.setText(Res.get("shared.numItemsLabel", sortedList.size()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Life cycle
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
Label label = new AutoTooltipLabel(Res.get("support.filter"));
|
||||||
|
HBox.setMargin(label, new Insets(5, 0, 0, 0));
|
||||||
|
HBox.setHgrow(label, Priority.NEVER);
|
||||||
|
|
||||||
|
filterTextField = new InputTextField();
|
||||||
|
Tooltip tooltip = new Tooltip();
|
||||||
|
tooltip.setShowDelay(Duration.millis(100));
|
||||||
|
tooltip.setShowDuration(Duration.seconds(10));
|
||||||
|
filterTextField.setTooltip(tooltip);
|
||||||
|
HBox.setHgrow(filterTextField, Priority.NEVER);
|
||||||
|
|
||||||
|
filterTextField.setText("open");
|
||||||
|
|
||||||
|
setupTable();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
protected void activate() {
|
||||||
|
super.activate();
|
||||||
|
|
||||||
|
applyList();
|
||||||
|
openOfferManager.getObservableSignedOffersList().addListener(signedOfferListChangeListener);
|
||||||
|
contextMenu = new ContextMenu();
|
||||||
|
MenuItem item1 = new MenuItem(Res.get("support.contextmenu.penalize.msg",
|
||||||
|
Res.get("shared.maker")));
|
||||||
|
contextMenu.getItems().addAll(item1);
|
||||||
|
|
||||||
|
tableView.setRowFactory(tv -> {
|
||||||
|
TableRow<SignedOffer> row = new TableRow<>();
|
||||||
|
row.setOnContextMenuRequested(event -> {
|
||||||
|
contextMenu.show(row, event.getScreenX(), event.getScreenY());
|
||||||
|
});
|
||||||
|
return row;
|
||||||
|
});
|
||||||
|
|
||||||
|
item1.setOnAction(event -> {
|
||||||
|
selectedSignedOffer = tableView.getSelectionModel().getSelectedItem();
|
||||||
|
if(selectedSignedOffer != null) {
|
||||||
|
new Popup().warning(Res.get("support.prompt.signedOffer.penalty.msg",
|
||||||
|
selectedSignedOffer.getOfferId(),
|
||||||
|
HavenoUtils.formatXmrWithCode(selectedSignedOffer.getMakerTradeFee()),
|
||||||
|
HavenoUtils.formatXmrWithCode(selectedSignedOffer.getReserveTxMinerFee()),
|
||||||
|
selectedSignedOffer.getReserveTxHash(),
|
||||||
|
selectedSignedOffer.getReserveTxKeyImages())
|
||||||
|
).onAction(() -> OfferViewUtil.submitTransactionHex(xmrWalletService, tableView,
|
||||||
|
selectedSignedOffer.getReserveTxHex())).show();
|
||||||
|
} else {
|
||||||
|
new Popup().error(Res.get("support.prompt.signedOffer.error.msg")).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
GUIUtil.requestFocus(tableView);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deactivate() {
|
||||||
|
super.deactivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// SignedOfferView
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
protected void setupTable() {
|
||||||
|
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||||
|
Label placeholder = new AutoTooltipLabel(Res.get("support.noTickets"));
|
||||||
|
placeholder.setWrapText(true);
|
||||||
|
tableView.setPlaceholder(placeholder);
|
||||||
|
tableView.getSelectionModel().clearSelection();
|
||||||
|
|
||||||
|
dateColumn = getDateColumn();
|
||||||
|
tableView.getColumns().add(dateColumn);
|
||||||
|
|
||||||
|
offerIdColumn = getOfferIdColumn();
|
||||||
|
tableView.getColumns().add(offerIdColumn);
|
||||||
|
|
||||||
|
reserveTxHashColumn = getReserveTxHashColumn();
|
||||||
|
tableView.getColumns().add(reserveTxHashColumn);
|
||||||
|
|
||||||
|
reserveTxHexColumn = getReserveTxHexColumn();
|
||||||
|
tableView.getColumns().add(reserveTxHexColumn);
|
||||||
|
|
||||||
|
reserveTxKeyImages = getReserveTxKeyImagesColumn();
|
||||||
|
tableView.getColumns().add(reserveTxKeyImages);
|
||||||
|
|
||||||
|
arbitratorSignatureColumn = getArbitratorSignatureColumn();
|
||||||
|
tableView.getColumns().add(arbitratorSignatureColumn);
|
||||||
|
|
||||||
|
makerTradeFeeColumn = getMakerTradeFeeColumn();
|
||||||
|
tableView.getColumns().add(makerTradeFeeColumn);
|
||||||
|
|
||||||
|
reserveTxMinerFeeColumn = getReserveTxMinerFeeColumn();
|
||||||
|
tableView.getColumns().add(reserveTxMinerFeeColumn);
|
||||||
|
|
||||||
|
offerIdColumn.setComparator(Comparator.comparing(SignedOffer::getOfferId));
|
||||||
|
dateColumn.setComparator(Comparator.comparing(SignedOffer::getTimeStamp));
|
||||||
|
|
||||||
|
dateColumn.setSortType(TableColumn.SortType.DESCENDING);
|
||||||
|
tableView.getSortOrder().add(dateColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TableColumn<SignedOffer, SignedOffer> getDateColumn() {
|
||||||
|
TableColumn<SignedOffer, SignedOffer> column = new AutoTooltipTableColumn<>(Res.get("shared.date")) {
|
||||||
|
{
|
||||||
|
setMinWidth(180);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
column.setCellValueFactory((signedOffer) -> new ReadOnlyObjectWrapper<>(signedOffer.getValue()));
|
||||||
|
column.setCellFactory(
|
||||||
|
new Callback<>() {
|
||||||
|
@Override
|
||||||
|
public TableCell<SignedOffer, SignedOffer> call(TableColumn<SignedOffer, SignedOffer> column) {
|
||||||
|
return new TableCell<>() {
|
||||||
|
@Override
|
||||||
|
public void updateItem(final SignedOffer item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
if (item != null && !empty)
|
||||||
|
setText(DisplayUtils.formatDateTime(new Date(item.getTimeStamp())));
|
||||||
|
else
|
||||||
|
setText("");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return column;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TableColumn<SignedOffer, SignedOffer> getOfferIdColumn() {
|
||||||
|
TableColumn<SignedOffer, SignedOffer> column = new AutoTooltipTableColumn<>(Res.get("shared.offerId")) {
|
||||||
|
{
|
||||||
|
setMinWidth(110);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
column.setCellValueFactory((signedOffer) -> new ReadOnlyObjectWrapper<>(signedOffer.getValue()));
|
||||||
|
column.setCellFactory(
|
||||||
|
new Callback<>() {
|
||||||
|
@Override
|
||||||
|
public TableCell<SignedOffer, SignedOffer> call(TableColumn<SignedOffer, SignedOffer> column) {
|
||||||
|
return new TableCell<>() {
|
||||||
|
private HyperlinkWithIcon field;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateItem(final SignedOffer item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
|
||||||
|
if (item != null && !empty) {
|
||||||
|
setText(item.getOfferId());
|
||||||
|
setGraphic(field);
|
||||||
|
} else {
|
||||||
|
setGraphic(null);
|
||||||
|
setText("");
|
||||||
|
if (field != null)
|
||||||
|
field.setOnAction(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return column;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TableColumn<SignedOffer, SignedOffer> getReserveTxHashColumn() {
|
||||||
|
TableColumn<SignedOffer, SignedOffer> column = new AutoTooltipTableColumn<>(Res.get("support.txHash")) {
|
||||||
|
{
|
||||||
|
setMinWidth(160);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
column.setCellValueFactory((signedOffer) -> new ReadOnlyObjectWrapper<>(signedOffer.getValue()));
|
||||||
|
column.setCellFactory(
|
||||||
|
new Callback<>() {
|
||||||
|
@Override
|
||||||
|
public TableCell<SignedOffer, SignedOffer> call(TableColumn<SignedOffer, SignedOffer> column) {
|
||||||
|
return new TableCell<>() {
|
||||||
|
@Override
|
||||||
|
public void updateItem(final SignedOffer item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
if (item != null && !empty)
|
||||||
|
setText(item.getReserveTxHash());
|
||||||
|
else
|
||||||
|
setText("");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return column;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TableColumn<SignedOffer, SignedOffer> getReserveTxHexColumn() {
|
||||||
|
TableColumn<SignedOffer, SignedOffer> column = new AutoTooltipTableColumn<>(Res.get("support.txHex")) {
|
||||||
|
{
|
||||||
|
setMinWidth(160);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
column.setCellValueFactory((signedOffer) -> new ReadOnlyObjectWrapper<>(signedOffer.getValue()));
|
||||||
|
column.setCellFactory(
|
||||||
|
new Callback<>() {
|
||||||
|
@Override
|
||||||
|
public TableCell<SignedOffer, SignedOffer> call(TableColumn<SignedOffer, SignedOffer> column) {
|
||||||
|
return new TableCell<>() {
|
||||||
|
@Override
|
||||||
|
public void updateItem(final SignedOffer item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
if (item != null && !empty)
|
||||||
|
setText(item.getReserveTxHex());
|
||||||
|
else
|
||||||
|
setText("");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return column;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TableColumn<SignedOffer, SignedOffer> getReserveTxKeyImagesColumn() {
|
||||||
|
TableColumn<SignedOffer, SignedOffer> column = new AutoTooltipTableColumn<>(Res.get("support.txKeyImages")) {
|
||||||
|
{
|
||||||
|
setMinWidth(160);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
column.setCellValueFactory((signedOffer) -> new ReadOnlyObjectWrapper<>(signedOffer.getValue()));
|
||||||
|
column.setCellFactory(
|
||||||
|
new Callback<>() {
|
||||||
|
@Override
|
||||||
|
public TableCell<SignedOffer, SignedOffer> call(TableColumn<SignedOffer, SignedOffer> column) {
|
||||||
|
return new TableCell<>() {
|
||||||
|
@Override
|
||||||
|
public void updateItem(final SignedOffer item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
if (item != null && !empty)
|
||||||
|
setText(item.getReserveTxKeyImages().toString());
|
||||||
|
else
|
||||||
|
setText("");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return column;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TableColumn<SignedOffer, SignedOffer> getArbitratorSignatureColumn() {
|
||||||
|
TableColumn<SignedOffer, SignedOffer> column = new AutoTooltipTableColumn<>(Res.get("support.signature")) {
|
||||||
|
{
|
||||||
|
setMinWidth(160);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
column.setCellValueFactory((signedOffer) -> new ReadOnlyObjectWrapper<>(signedOffer.getValue()));
|
||||||
|
column.setCellFactory(
|
||||||
|
new Callback<>() {
|
||||||
|
@Override
|
||||||
|
public TableCell<SignedOffer, SignedOffer> call(TableColumn<SignedOffer, SignedOffer> column) {
|
||||||
|
return new TableCell<>() {
|
||||||
|
@Override
|
||||||
|
public void updateItem(final SignedOffer item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
if (item != null && !empty)
|
||||||
|
setText(item.getArbitratorSignature());
|
||||||
|
else
|
||||||
|
setText("");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return column;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TableColumn<SignedOffer, SignedOffer> getMakerTradeFeeColumn() {
|
||||||
|
TableColumn<SignedOffer, SignedOffer> column = new AutoTooltipTableColumn<>(Res.get("support.maker.trade.fee")) {
|
||||||
|
{
|
||||||
|
setMinWidth(160);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
column.setCellValueFactory((signedOffer) -> new ReadOnlyObjectWrapper<>(signedOffer.getValue()));
|
||||||
|
column.setCellFactory(
|
||||||
|
new Callback<>() {
|
||||||
|
@Override
|
||||||
|
public TableCell<SignedOffer, SignedOffer> call(TableColumn<SignedOffer, SignedOffer> column) {
|
||||||
|
return new TableCell<>() {
|
||||||
|
@Override
|
||||||
|
public void updateItem(final SignedOffer item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
if (item != null && !empty)
|
||||||
|
setText(HavenoUtils.formatXmrWithCode(item.getMakerTradeFee()));
|
||||||
|
else
|
||||||
|
setText("");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return column;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TableColumn<SignedOffer, SignedOffer> getReserveTxMinerFeeColumn() {
|
||||||
|
TableColumn<SignedOffer, SignedOffer> column = new AutoTooltipTableColumn<>(Res.get("support.tx.miner.fee")) {
|
||||||
|
{
|
||||||
|
setMinWidth(160);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
column.setCellValueFactory((signedOffer) -> new ReadOnlyObjectWrapper<>(signedOffer.getValue()));
|
||||||
|
column.setCellFactory(
|
||||||
|
new Callback<>() {
|
||||||
|
@Override
|
||||||
|
public TableCell<SignedOffer, SignedOffer> call(TableColumn<SignedOffer, SignedOffer> column) {
|
||||||
|
return new TableCell<>() {
|
||||||
|
@Override
|
||||||
|
public void updateItem(final SignedOffer item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
if (item != null && !empty)
|
||||||
|
setText(HavenoUtils.formatXmrWithCode(item.getReserveTxMinerFee()));
|
||||||
|
else
|
||||||
|
setText("");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return column;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user