mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-25 07:27:18 +01:00
Merge pull request #5886 from ripcurlx/add-bsq-swap-duplicate-offer-support
Add support to duplicate BSQ swap offers
This commit is contained in:
commit
5041dc57ef
14 changed files with 279 additions and 81 deletions
|
@ -25,6 +25,7 @@ import bisq.core.btc.wallet.BsqWalletService;
|
||||||
import bisq.core.btc.wallet.BtcWalletService;
|
import bisq.core.btc.wallet.BtcWalletService;
|
||||||
import bisq.core.monetary.Price;
|
import bisq.core.monetary.Price;
|
||||||
import bisq.core.monetary.Volume;
|
import bisq.core.monetary.Volume;
|
||||||
|
import bisq.core.offer.Offer;
|
||||||
import bisq.core.offer.OfferDirection;
|
import bisq.core.offer.OfferDirection;
|
||||||
import bisq.core.offer.OfferUtil;
|
import bisq.core.offer.OfferUtil;
|
||||||
import bisq.core.payment.payload.PaymentMethod;
|
import bisq.core.payment.payload.PaymentMethod;
|
||||||
|
@ -124,10 +125,20 @@ public class BsqSwapOfferModel {
|
||||||
// API
|
// API
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public void init(OfferDirection direction, boolean isMaker) {
|
public void init(OfferDirection direction, boolean isMaker, @Nullable Offer offer) {
|
||||||
this.direction = direction;
|
this.direction = direction;
|
||||||
this.isMaker = isMaker;
|
this.isMaker = isMaker;
|
||||||
|
|
||||||
|
if (offer != null) {
|
||||||
|
setPrice(offer.getPrice());
|
||||||
|
|
||||||
|
setBtcAmount(Coin.valueOf(Math.min(offer.getAmount().value, getMaxTradeLimit())));
|
||||||
|
calculateVolumeForAmount(getBtcAmount());
|
||||||
|
|
||||||
|
setMinAmount(offer.getMinAmount());
|
||||||
|
calculateMinVolume();
|
||||||
|
}
|
||||||
|
|
||||||
createListeners();
|
createListeners();
|
||||||
applyTxFeePerVbyte();
|
applyTxFeePerVbyte();
|
||||||
|
|
||||||
|
|
|
@ -67,17 +67,9 @@ public class BsqSwapTakeOfferModel extends BsqSwapOfferModel {
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public void initWithData(Offer offer) {
|
public void initWithData(Offer offer) {
|
||||||
super.init(offer.getDirection(), false);
|
super.init(offer.getDirection(), false, offer);
|
||||||
|
|
||||||
this.offer = offer;
|
this.offer = offer;
|
||||||
setPrice(offer.getPrice());
|
|
||||||
|
|
||||||
setBtcAmount(Coin.valueOf(Math.min(offer.getAmount().value, getMaxTradeLimit())));
|
|
||||||
calculateVolumeForAmount(getBtcAmount());
|
|
||||||
|
|
||||||
setMinAmount(offer.getMinAmount());
|
|
||||||
calculateMinVolume();
|
|
||||||
|
|
||||||
offer.resetState();
|
offer.resetState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,7 @@ shared.BTCMinMax=BTC (min - max)
|
||||||
shared.removeOffer=Remove offer
|
shared.removeOffer=Remove offer
|
||||||
shared.dontRemoveOffer=Don't remove offer
|
shared.dontRemoveOffer=Don't remove offer
|
||||||
shared.editOffer=Edit offer
|
shared.editOffer=Edit offer
|
||||||
|
shared.duplicateOffer=Duplicate offer
|
||||||
shared.openLargeQRWindow=Open large QR code window
|
shared.openLargeQRWindow=Open large QR code window
|
||||||
shared.tradingAccount=Trading account
|
shared.tradingAccount=Trading account
|
||||||
shared.faq=Visit FAQ page
|
shared.faq=Visit FAQ page
|
||||||
|
|
|
@ -37,6 +37,7 @@ import bisq.core.locale.Res;
|
||||||
import bisq.core.locale.TradeCurrency;
|
import bisq.core.locale.TradeCurrency;
|
||||||
import bisq.core.offer.Offer;
|
import bisq.core.offer.Offer;
|
||||||
import bisq.core.offer.OfferDirection;
|
import bisq.core.offer.OfferDirection;
|
||||||
|
import bisq.core.offer.bsq_swap.BsqSwapOfferPayload;
|
||||||
import bisq.core.payment.payload.PaymentMethod;
|
import bisq.core.payment.payload.PaymentMethod;
|
||||||
import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
|
import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
|
||||||
import bisq.core.user.Preferences;
|
import bisq.core.user.Preferences;
|
||||||
|
@ -56,6 +57,8 @@ import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public abstract class OfferView extends ActivatableView<TabPane, Void> {
|
public abstract class OfferView extends ActivatableView<TabPane, Void> {
|
||||||
|
|
||||||
private OfferBookView offerBookView;
|
private OfferBookView offerBookView;
|
||||||
|
@ -102,7 +105,7 @@ public abstract class OfferView extends ActivatableView<TabPane, Void> {
|
||||||
protected void initialize() {
|
protected void initialize() {
|
||||||
navigationListener = (viewPath, data) -> {
|
navigationListener = (viewPath, data) -> {
|
||||||
if (viewPath.size() == 3 && viewPath.indexOf(this.getClass()) == 1)
|
if (viewPath.size() == 3 && viewPath.indexOf(this.getClass()) == 1)
|
||||||
loadView(viewPath.tip());
|
loadView(viewPath.tip(), data);
|
||||||
};
|
};
|
||||||
tabChangeListener = (observableValue, oldValue, newValue) -> {
|
tabChangeListener = (observableValue, oldValue, newValue) -> {
|
||||||
if (newValue != null) {
|
if (newValue != null) {
|
||||||
|
@ -198,7 +201,7 @@ public abstract class OfferView extends ActivatableView<TabPane, Void> {
|
||||||
return Res.get("offerbook.takeOffer").toUpperCase();
|
return Res.get("offerbook.takeOffer").toUpperCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadView(Class<? extends View> viewClass) {
|
private void loadView(Class<? extends View> viewClass, @Nullable Object data) {
|
||||||
TabPane tabPane = root;
|
TabPane tabPane = root;
|
||||||
tabPane.setTabClosingPolicy(TabPane.TabClosingPolicy.ALL_TABS);
|
tabPane.setTabClosingPolicy(TabPane.TabClosingPolicy.ALL_TABS);
|
||||||
View view;
|
View view;
|
||||||
|
@ -237,7 +240,7 @@ public abstract class OfferView extends ActivatableView<TabPane, Void> {
|
||||||
} else if (viewClass == BsqSwapCreateOfferView.class && bsqSwapCreateOfferView == null) {
|
} else if (viewClass == BsqSwapCreateOfferView.class && bsqSwapCreateOfferView == null) {
|
||||||
view = viewLoader.load(viewClass);
|
view = viewLoader.load(viewClass);
|
||||||
bsqSwapCreateOfferView = (BsqSwapCreateOfferView) view;
|
bsqSwapCreateOfferView = (BsqSwapCreateOfferView) view;
|
||||||
bsqSwapCreateOfferView.initWithData(direction, offerActionHandler);
|
bsqSwapCreateOfferView.initWithData(direction, offerActionHandler, (BsqSwapOfferPayload) data);
|
||||||
createOfferPane = bsqSwapCreateOfferView.getRoot();
|
createOfferPane = bsqSwapCreateOfferView.getRoot();
|
||||||
createOfferTab = new Tab(getCreateOfferTabName(viewClass));
|
createOfferTab = new Tab(getCreateOfferTabName(viewClass));
|
||||||
createOfferTab.setClosable(true);
|
createOfferTab.setClosable(true);
|
||||||
|
|
|
@ -28,6 +28,7 @@ import bisq.core.offer.Offer;
|
||||||
import bisq.core.offer.OfferDirection;
|
import bisq.core.offer.OfferDirection;
|
||||||
import bisq.core.offer.OfferUtil;
|
import bisq.core.offer.OfferUtil;
|
||||||
import bisq.core.offer.bsq_swap.BsqSwapOfferModel;
|
import bisq.core.offer.bsq_swap.BsqSwapOfferModel;
|
||||||
|
import bisq.core.offer.bsq_swap.BsqSwapOfferPayload;
|
||||||
import bisq.core.offer.bsq_swap.OpenBsqSwapOfferService;
|
import bisq.core.offer.bsq_swap.OpenBsqSwapOfferService;
|
||||||
import bisq.core.payment.PaymentAccount;
|
import bisq.core.payment.PaymentAccount;
|
||||||
import bisq.core.user.User;
|
import bisq.core.user.User;
|
||||||
|
@ -52,6 +53,8 @@ import java.util.function.Consumer;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
import static java.util.Comparator.comparing;
|
import static java.util.Comparator.comparing;
|
||||||
|
|
||||||
|
@ -91,8 +94,8 @@ class BsqSwapCreateOfferDataModel extends BsqSwapOfferDataModel {
|
||||||
// API
|
// API
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void initWithData(OfferDirection direction) {
|
void initWithData(OfferDirection direction, @Nullable BsqSwapOfferPayload offerPayload) {
|
||||||
bsqSwapOfferModel.init(direction, true);
|
bsqSwapOfferModel.init(direction, true, offerPayload != null ? new Offer(offerPayload) : null);
|
||||||
|
|
||||||
fillPaymentAccounts();
|
fillPaymentAccounts();
|
||||||
applyPaymentAccount();
|
applyPaymentAccount();
|
||||||
|
|
|
@ -37,6 +37,7 @@ import bisq.desktop.util.Layout;
|
||||||
import bisq.core.locale.CurrencyUtil;
|
import bisq.core.locale.CurrencyUtil;
|
||||||
import bisq.core.locale.Res;
|
import bisq.core.locale.Res;
|
||||||
import bisq.core.offer.OfferDirection;
|
import bisq.core.offer.OfferDirection;
|
||||||
|
import bisq.core.offer.bsq_swap.BsqSwapOfferPayload;
|
||||||
import bisq.core.payment.PaymentAccount;
|
import bisq.core.payment.PaymentAccount;
|
||||||
import bisq.core.user.DontShowAgainLookup;
|
import bisq.core.user.DontShowAgainLookup;
|
||||||
|
|
||||||
|
@ -74,6 +75,8 @@ import java.util.concurrent.TimeUnit;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static bisq.core.offer.bsq_swap.BsqSwapOfferModel.BSQ;
|
import static bisq.core.offer.bsq_swap.BsqSwapOfferModel.BSQ;
|
||||||
import static bisq.desktop.util.FormBuilder.*;
|
import static bisq.desktop.util.FormBuilder.*;
|
||||||
|
|
||||||
|
@ -159,9 +162,12 @@ public class BsqSwapCreateOfferView extends BsqSwapOfferView<BsqSwapCreateOfferV
|
||||||
// API
|
// API
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public void initWithData(OfferDirection direction, OfferView.OfferActionHandler offerActionHandler) {
|
public void initWithData(OfferDirection direction,
|
||||||
|
OfferView.OfferActionHandler offerActionHandler,
|
||||||
|
@Nullable BsqSwapOfferPayload offerPayload) {
|
||||||
this.offerActionHandler = offerActionHandler;
|
this.offerActionHandler = offerActionHandler;
|
||||||
model.initWithData(direction);
|
|
||||||
|
model.initWithData(offerPayload != null ? offerPayload.getDirection() : direction, offerPayload);
|
||||||
|
|
||||||
if (model.dataModel.isBuyOffer()) {
|
if (model.dataModel.isBuyOffer()) {
|
||||||
actionButton.setId("buy-button-big");
|
actionButton.setId("buy-button-big");
|
||||||
|
|
|
@ -31,6 +31,7 @@ import bisq.core.monetary.Price;
|
||||||
import bisq.core.monetary.Volume;
|
import bisq.core.monetary.Volume;
|
||||||
import bisq.core.offer.OfferDirection;
|
import bisq.core.offer.OfferDirection;
|
||||||
import bisq.core.offer.OfferRestrictions;
|
import bisq.core.offer.OfferRestrictions;
|
||||||
|
import bisq.core.offer.bsq_swap.BsqSwapOfferPayload;
|
||||||
import bisq.core.payment.payload.PaymentMethod;
|
import bisq.core.payment.payload.PaymentMethod;
|
||||||
import bisq.core.util.FormattingUtils;
|
import bisq.core.util.FormattingUtils;
|
||||||
import bisq.core.util.VolumeUtil;
|
import bisq.core.util.VolumeUtil;
|
||||||
|
@ -60,6 +61,8 @@ import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static bisq.core.offer.bsq_swap.BsqSwapOfferModel.BSQ;
|
import static bisq.core.offer.bsq_swap.BsqSwapOfferModel.BSQ;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@ -144,6 +147,8 @@ class BsqSwapCreateOfferViewModel extends BsqSwapOfferViewModel<BsqSwapCreateOff
|
||||||
addBindings();
|
addBindings();
|
||||||
addListeners();
|
addListeners();
|
||||||
|
|
||||||
|
maybeInitializeWithData();
|
||||||
|
|
||||||
updateButtonDisableState();
|
updateButtonDisableState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,8 +164,8 @@ class BsqSwapCreateOfferViewModel extends BsqSwapOfferViewModel<BsqSwapCreateOff
|
||||||
// API
|
// API
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void initWithData(OfferDirection direction) {
|
void initWithData(OfferDirection direction, @Nullable BsqSwapOfferPayload offerPayload) {
|
||||||
dataModel.initWithData(direction);
|
dataModel.initWithData(direction, offerPayload);
|
||||||
|
|
||||||
btcValidator.setMaxValue(PaymentMethod.BSQ_SWAP.getMaxTradeLimitAsCoin(BSQ));
|
btcValidator.setMaxValue(PaymentMethod.BSQ_SWAP.getMaxTradeLimitAsCoin(BSQ));
|
||||||
btcValidator.setMaxTradeLimit(Coin.valueOf(dataModel.getMaxTradeLimit()));
|
btcValidator.setMaxTradeLimit(Coin.valueOf(dataModel.getMaxTradeLimit()));
|
||||||
|
@ -572,6 +577,33 @@ class BsqSwapCreateOfferViewModel extends BsqSwapOfferViewModel<BsqSwapCreateOff
|
||||||
isPlaceOfferButtonDisabled.set(createOfferRequested || !inputDataValid || miningPoW.get());
|
isPlaceOfferButtonDisabled.set(createOfferRequested || !inputDataValid || miningPoW.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void maybeInitializeWithData() {
|
||||||
|
ObjectProperty<Coin> btcMinAmount = dataModel.getMinAmount();
|
||||||
|
if (btcMinAmount.get() != null) {
|
||||||
|
minAmountAsCoinListener.changed(btcMinAmount, null, btcMinAmount.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectProperty<Coin> btcAmount = dataModel.getBtcAmount();
|
||||||
|
|
||||||
|
if (btcAmount.get() != null && btcMinAmount.get() != null) {
|
||||||
|
syncMinAmountWithAmount = btcMinAmount.get().equals(dataModel.getBtcAmount().get());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (btcAmount.get() != null) {
|
||||||
|
amountAsCoinListener.changed(btcAmount, null, btcAmount.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectProperty<Price> price = dataModel.getPrice();
|
||||||
|
if (price.get() != null) {
|
||||||
|
priceListener.changed(price, null, price.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectProperty<Volume> volume = dataModel.getVolume();
|
||||||
|
if (volume.get() != null) {
|
||||||
|
volumeListener.changed(volume, null, volume.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void stopTimeoutTimer() {
|
private void stopTimeoutTimer() {
|
||||||
if (timeoutTimer != null) {
|
if (timeoutTimer != null) {
|
||||||
timeoutTimer.stop();
|
timeoutTimer.stop();
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
<TableColumn fx:id="sellerSecurityDepositColumn" visible="false" minWidth="75"/>
|
<TableColumn fx:id="sellerSecurityDepositColumn" visible="false" minWidth="75"/>
|
||||||
<TableColumn fx:id="directionColumn" minWidth="70"/>
|
<TableColumn fx:id="directionColumn" minWidth="70"/>
|
||||||
<TableColumn fx:id="stateColumn" minWidth="80"/>
|
<TableColumn fx:id="stateColumn" minWidth="80"/>
|
||||||
|
<TableColumn fx:id="duplicateColumn" minWidth="30" maxWidth="30" sortable="false"/>
|
||||||
<TableColumn fx:id="avatarColumn" minWidth="40" maxWidth="40"/>
|
<TableColumn fx:id="avatarColumn" minWidth="40" maxWidth="40"/>
|
||||||
</columns>
|
</columns>
|
||||||
</TableView>
|
</TableView>
|
||||||
|
|
|
@ -26,21 +26,19 @@ import bisq.desktop.components.AutoTooltipTableColumn;
|
||||||
import bisq.desktop.components.HyperlinkWithIcon;
|
import bisq.desktop.components.HyperlinkWithIcon;
|
||||||
import bisq.desktop.components.InputTextField;
|
import bisq.desktop.components.InputTextField;
|
||||||
import bisq.desktop.components.PeerInfoIconTrading;
|
import bisq.desktop.components.PeerInfoIconTrading;
|
||||||
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.BsqTradeDetailsWindow;
|
import bisq.desktop.main.overlays.windows.BsqTradeDetailsWindow;
|
||||||
import bisq.desktop.main.overlays.windows.ClosedTradesSummaryWindow;
|
import bisq.desktop.main.overlays.windows.ClosedTradesSummaryWindow;
|
||||||
import bisq.desktop.main.overlays.windows.OfferDetailsWindow;
|
import bisq.desktop.main.overlays.windows.OfferDetailsWindow;
|
||||||
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.presentation.PortfolioUtil;
|
||||||
import bisq.desktop.main.portfolio.duplicateoffer.DuplicateOfferView;
|
|
||||||
import bisq.desktop.util.GUIUtil;
|
import bisq.desktop.util.GUIUtil;
|
||||||
|
|
||||||
import bisq.core.alert.PrivateNotificationManager;
|
import bisq.core.alert.PrivateNotificationManager;
|
||||||
import bisq.core.locale.Res;
|
import bisq.core.locale.Res;
|
||||||
import bisq.core.offer.Offer;
|
import bisq.core.offer.Offer;
|
||||||
|
import bisq.core.offer.OfferPayloadBase;
|
||||||
import bisq.core.offer.OpenOffer;
|
import bisq.core.offer.OpenOffer;
|
||||||
import bisq.core.offer.bisq_v1.OfferPayload;
|
|
||||||
import bisq.core.trade.model.Tradable;
|
import bisq.core.trade.model.Tradable;
|
||||||
import bisq.core.trade.model.TradeModel;
|
import bisq.core.trade.model.TradeModel;
|
||||||
import bisq.core.trade.model.bisq_v1.Contract;
|
import bisq.core.trade.model.bisq_v1.Contract;
|
||||||
|
@ -60,11 +58,14 @@ import com.googlecode.jcsv.writer.CSVEntryConverter;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
|
|
||||||
|
import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon;
|
||||||
|
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
|
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.ContextMenu;
|
import javafx.scene.control.ContextMenu;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.MenuItem;
|
import javafx.scene.control.MenuItem;
|
||||||
|
@ -85,6 +86,8 @@ import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||||
import javafx.beans.value.ChangeListener;
|
import javafx.beans.value.ChangeListener;
|
||||||
|
|
||||||
|
import javafx.event.ActionEvent;
|
||||||
|
|
||||||
import javafx.collections.transformation.FilteredList;
|
import javafx.collections.transformation.FilteredList;
|
||||||
import javafx.collections.transformation.SortedList;
|
import javafx.collections.transformation.SortedList;
|
||||||
|
|
||||||
|
@ -94,6 +97,8 @@ import java.util.Comparator;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import static bisq.desktop.util.FormBuilder.getRegularIconButton;
|
||||||
|
|
||||||
@FxmlView
|
@FxmlView
|
||||||
public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTradesViewModel> {
|
public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTradesViewModel> {
|
||||||
private final boolean useDevPrivilegeKeys;
|
private final boolean useDevPrivilegeKeys;
|
||||||
|
@ -132,7 +137,8 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
||||||
@FXML
|
@FXML
|
||||||
TableColumn<Tradable, Tradable> priceColumn, deviationColumn, amountColumn, volumeColumn,
|
TableColumn<Tradable, Tradable> priceColumn, deviationColumn, amountColumn, volumeColumn,
|
||||||
txFeeColumn, tradeFeeColumn, buyerSecurityDepositColumn, sellerSecurityDepositColumn,
|
txFeeColumn, tradeFeeColumn, buyerSecurityDepositColumn, sellerSecurityDepositColumn,
|
||||||
marketColumn, directionColumn, dateColumn, tradeIdColumn, stateColumn, avatarColumn;
|
marketColumn, directionColumn, dateColumn, tradeIdColumn, stateColumn,
|
||||||
|
duplicateColumn, avatarColumn;
|
||||||
@FXML
|
@FXML
|
||||||
HBox searchBox;
|
HBox searchBox;
|
||||||
@FXML
|
@FXML
|
||||||
|
@ -198,6 +204,7 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
||||||
dateColumn.setGraphic(new AutoTooltipLabel(ColumnNames.DATE.toString()));
|
dateColumn.setGraphic(new AutoTooltipLabel(ColumnNames.DATE.toString()));
|
||||||
tradeIdColumn.setGraphic(new AutoTooltipLabel(ColumnNames.TRADE_ID.toString()));
|
tradeIdColumn.setGraphic(new AutoTooltipLabel(ColumnNames.TRADE_ID.toString()));
|
||||||
stateColumn.setGraphic(new AutoTooltipLabel(ColumnNames.STATUS.toString()));
|
stateColumn.setGraphic(new AutoTooltipLabel(ColumnNames.STATUS.toString()));
|
||||||
|
duplicateColumn.setGraphic(new AutoTooltipLabel(""));
|
||||||
avatarColumn.setText("");
|
avatarColumn.setText("");
|
||||||
|
|
||||||
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||||
|
@ -216,10 +223,11 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
||||||
setDateColumnCellFactory();
|
setDateColumnCellFactory();
|
||||||
setMarketColumnCellFactory();
|
setMarketColumnCellFactory();
|
||||||
setStateColumnCellFactory();
|
setStateColumnCellFactory();
|
||||||
|
setDuplicateColumnCellFactory();
|
||||||
setAvatarColumnCellFactory();
|
setAvatarColumnCellFactory();
|
||||||
|
|
||||||
tradeIdColumn.setComparator(Comparator.comparing(o -> o.getId()));
|
tradeIdColumn.setComparator(Comparator.comparing(Tradable::getId));
|
||||||
dateColumn.setComparator(Comparator.comparing(o -> o.getDate()));
|
dateColumn.setComparator(Comparator.comparing(Tradable::getDate));
|
||||||
directionColumn.setComparator(Comparator.comparing(o -> o.getOffer().getDirection()));
|
directionColumn.setComparator(Comparator.comparing(o -> o.getOffer().getDirection()));
|
||||||
marketColumn.setComparator(Comparator.comparing(model::getMarketLabel));
|
marketColumn.setComparator(Comparator.comparing(model::getMarketLabel));
|
||||||
priceColumn.setComparator(Comparator.comparing(model::getPrice, Comparator.nullsFirst(Comparator.naturalOrder())));
|
priceColumn.setComparator(Comparator.comparing(model::getPrice, Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||||
|
@ -229,7 +237,7 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
||||||
volumeColumn.setComparator(nullsFirstComparingAsTrade(TradeModel::getVolume));
|
volumeColumn.setComparator(nullsFirstComparingAsTrade(TradeModel::getVolume));
|
||||||
amountColumn.setComparator(Comparator.comparing(model::getAmount, Comparator.nullsFirst(Comparator.naturalOrder())));
|
amountColumn.setComparator(Comparator.comparing(model::getAmount, Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||||
avatarColumn.setComparator(Comparator.comparing(
|
avatarColumn.setComparator(Comparator.comparing(
|
||||||
o -> model.dataModel.getNumPastTrades(o),
|
model.dataModel::getNumPastTrades,
|
||||||
Comparator.nullsFirst(Comparator.naturalOrder())
|
Comparator.nullsFirst(Comparator.naturalOrder())
|
||||||
));
|
));
|
||||||
txFeeColumn.setComparator(nullsFirstComparing(o ->
|
txFeeColumn.setComparator(nullsFirstComparing(o ->
|
||||||
|
@ -262,20 +270,9 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
||||||
tableView -> {
|
tableView -> {
|
||||||
TableRow<Tradable> row = new TableRow<>();
|
TableRow<Tradable> row = new TableRow<>();
|
||||||
ContextMenu rowMenu = new ContextMenu();
|
ContextMenu rowMenu = new ContextMenu();
|
||||||
MenuItem editItem = new MenuItem(Res.get("portfolio.context.offerLikeThis"));
|
MenuItem duplicateItem = new MenuItem(Res.get("portfolio.context.offerLikeThis"));
|
||||||
editItem.setOnAction((event) -> {
|
duplicateItem.setOnAction((ActionEvent event) -> onDuplicateOffer(row.getItem().getOffer()));
|
||||||
try {
|
rowMenu.getItems().add(duplicateItem);
|
||||||
OfferPayload offerPayload = row.getItem().getOffer().getOfferPayload().orElseThrow();
|
|
||||||
if (offerPayload.getPubKeyRing().equals(keyRing.getPubKeyRing())) {
|
|
||||||
navigation.navigateToWithData(offerPayload, MainView.class, PortfolioView.class, DuplicateOfferView.class);
|
|
||||||
} else {
|
|
||||||
new Popup().warning(Res.get("portfolio.context.notYourOffer")).show();
|
|
||||||
}
|
|
||||||
} catch (NullPointerException e) {
|
|
||||||
log.warn("Unable to get offerPayload - {}", e.toString());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
rowMenu.getItems().add(editItem);
|
|
||||||
row.contextMenuProperty().bind(
|
row.contextMenuProperty().bind(
|
||||||
Bindings.when(Bindings.isNotNull(row.itemProperty()))
|
Bindings.when(Bindings.isNotNull(row.itemProperty()))
|
||||||
.then(rowMenu)
|
.then(rowMenu)
|
||||||
|
@ -579,6 +576,40 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setDuplicateColumnCellFactory() {
|
||||||
|
duplicateColumn.getStyleClass().add("avatar-column");
|
||||||
|
duplicateColumn.setCellValueFactory((offerListItem) -> new ReadOnlyObjectWrapper<>(offerListItem.getValue()));
|
||||||
|
duplicateColumn.setCellFactory(
|
||||||
|
new Callback<>() {
|
||||||
|
@Override
|
||||||
|
public TableCell<Tradable, Tradable> call(TableColumn<Tradable, Tradable> column) {
|
||||||
|
return new TableCell<>() {
|
||||||
|
Button button;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateItem(final Tradable item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
|
||||||
|
if (item != null && !empty && isMyOfferAsMaker(item.getOffer().getOfferPayloadBase())) {
|
||||||
|
if (button == null) {
|
||||||
|
button = getRegularIconButton(MaterialDesignIcon.CONTENT_COPY);
|
||||||
|
button.setTooltip(new Tooltip(Res.get("shared.duplicateOffer")));
|
||||||
|
setGraphic(button);
|
||||||
|
}
|
||||||
|
button.setOnAction(event -> onDuplicateOffer(item.getOffer()));
|
||||||
|
} else {
|
||||||
|
setGraphic(null);
|
||||||
|
if (button != null) {
|
||||||
|
button.setOnAction(null);
|
||||||
|
button = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("UnusedReturnValue")
|
@SuppressWarnings("UnusedReturnValue")
|
||||||
private TableColumn<Tradable, Tradable> setAvatarColumnCellFactory() {
|
private TableColumn<Tradable, Tradable> setAvatarColumnCellFactory() {
|
||||||
avatarColumn.getStyleClass().addAll("last-column", "avatar-column");
|
avatarColumn.getStyleClass().addAll("last-column", "avatar-column");
|
||||||
|
@ -593,7 +624,7 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
||||||
public void updateItem(final Tradable item, boolean empty) {
|
public void updateItem(final Tradable item, boolean empty) {
|
||||||
super.updateItem(item, empty);
|
super.updateItem(item, empty);
|
||||||
|
|
||||||
if (item != null && !empty && item instanceof TradeModel) {
|
if (!empty && item instanceof TradeModel) {
|
||||||
TradeModel tradeModel = (TradeModel) item;
|
TradeModel tradeModel = (TradeModel) item;
|
||||||
int numPastTrades = model.dataModel.getNumPastTrades(tradeModel);
|
int numPastTrades = model.dataModel.getNumPastTrades(tradeModel);
|
||||||
NodeAddress tradingPeerNodeAddress = tradeModel.getTradingPeerNodeAddress();
|
NodeAddress tradingPeerNodeAddress = tradeModel.getTradingPeerNodeAddress();
|
||||||
|
@ -783,6 +814,23 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onDuplicateOffer(Offer offer) {
|
||||||
|
try {
|
||||||
|
OfferPayloadBase offerPayloadBase = offer.getOfferPayloadBase();
|
||||||
|
if (isMyOfferAsMaker(offerPayloadBase)) {
|
||||||
|
PortfolioUtil.duplicateOffer(navigation, offerPayloadBase);
|
||||||
|
} else {
|
||||||
|
new Popup().warning(Res.get("portfolio.context.notYourOffer")).show();
|
||||||
|
}
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
log.warn("Unable to get offerPayload - {}", e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isMyOfferAsMaker(OfferPayloadBase offerPayloadBase) {
|
||||||
|
return offerPayloadBase.getPubKeyRing().equals(keyRing.getPubKeyRing());
|
||||||
|
}
|
||||||
|
|
||||||
private Tradable getDummyTradable() {
|
private Tradable getDummyTradable() {
|
||||||
return new Tradable() {
|
return new Tradable() {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -25,10 +25,14 @@ import bisq.core.account.witness.AccountAgeWitnessService;
|
||||||
import bisq.core.btc.wallet.BsqWalletService;
|
import bisq.core.btc.wallet.BsqWalletService;
|
||||||
import bisq.core.btc.wallet.BtcWalletService;
|
import bisq.core.btc.wallet.BtcWalletService;
|
||||||
import bisq.core.btc.wallet.Restrictions;
|
import bisq.core.btc.wallet.Restrictions;
|
||||||
|
import bisq.core.locale.CurrencyUtil;
|
||||||
|
import bisq.core.locale.TradeCurrency;
|
||||||
import bisq.core.offer.Offer;
|
import bisq.core.offer.Offer;
|
||||||
import bisq.core.offer.OfferUtil;
|
import bisq.core.offer.OfferUtil;
|
||||||
import bisq.core.offer.OpenOfferManager;
|
import bisq.core.offer.OpenOfferManager;
|
||||||
import bisq.core.offer.bisq_v1.CreateOfferService;
|
import bisq.core.offer.bisq_v1.CreateOfferService;
|
||||||
|
import bisq.core.payment.BsqSwapAccount;
|
||||||
|
import bisq.core.payment.PaymentAccount;
|
||||||
import bisq.core.provider.fee.FeeService;
|
import bisq.core.provider.fee.FeeService;
|
||||||
import bisq.core.provider.price.PriceFeedService;
|
import bisq.core.provider.price.PriceFeedService;
|
||||||
import bisq.core.trade.statistics.TradeStatisticsManager;
|
import bisq.core.trade.statistics.TradeStatisticsManager;
|
||||||
|
@ -46,6 +50,8 @@ import com.google.inject.Inject;
|
||||||
|
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
class DuplicateOfferDataModel extends MutableOfferDataModel {
|
class DuplicateOfferDataModel extends MutableOfferDataModel {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
|
@ -104,4 +110,25 @@ class DuplicateOfferDataModel extends MutableOfferDataModel {
|
||||||
return Math.min(offerBuyerSecurityDepositAsPercent,
|
return Math.min(offerBuyerSecurityDepositAsPercent,
|
||||||
Restrictions.getMaxBuyerSecurityDepositAsPercent());
|
Restrictions.getMaxBuyerSecurityDepositAsPercent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PaymentAccount getPreselectedPaymentAccount() {
|
||||||
|
// If trade currency is BSQ don't use the BSQ swap payment account as it will automatically
|
||||||
|
// close the duplicate offer view
|
||||||
|
Optional<TradeCurrency> bsqOptional = CurrencyUtil.getTradeCurrency("BSQ");
|
||||||
|
if (bsqOptional.isPresent() && tradeCurrency.equals(bsqOptional.get()) && user.getPaymentAccounts() != null) {
|
||||||
|
Optional<PaymentAccount> firstBsqPaymentAccount = user.getPaymentAccounts().stream().filter(paymentAccount1 -> {
|
||||||
|
Optional<TradeCurrency> tradeCurrency = paymentAccount1.getTradeCurrency();
|
||||||
|
return tradeCurrency.isPresent() &&
|
||||||
|
tradeCurrency.get().equals(bsqOptional.get()) &&
|
||||||
|
!paymentAccount1.getId().equals(BsqSwapAccount.ID);
|
||||||
|
}).findFirst();
|
||||||
|
|
||||||
|
if (firstBsqPaymentAccount.isPresent()) {
|
||||||
|
return firstBsqPaymentAccount.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.getPreselectedPaymentAccount();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
<TableColumn fx:id="deactivateItemColumn" minWidth="60" maxWidth="60" sortable="false"/>
|
<TableColumn fx:id="deactivateItemColumn" minWidth="60" maxWidth="60" sortable="false"/>
|
||||||
<TableColumn fx:id="editItemColumn" minWidth="30" maxWidth="30" sortable="false"/>
|
<TableColumn fx:id="editItemColumn" minWidth="30" maxWidth="30" sortable="false"/>
|
||||||
<TableColumn fx:id="triggerIconColumn" minWidth="30" maxWidth="30" sortable="false"/>
|
<TableColumn fx:id="triggerIconColumn" minWidth="30" maxWidth="30" sortable="false"/>
|
||||||
|
<TableColumn fx:id="duplicateItemColumn" minWidth="30" maxWidth="30" sortable="false"/>
|
||||||
<TableColumn fx:id="removeItemColumn" minWidth="30" maxWidth="30" sortable="false"/>
|
<TableColumn fx:id="removeItemColumn" minWidth="30" maxWidth="30" sortable="false"/>
|
||||||
</columns>
|
</columns>
|
||||||
</TableView>
|
</TableView>
|
||||||
|
|
|
@ -33,12 +33,11 @@ import bisq.desktop.main.overlays.popups.Popup;
|
||||||
import bisq.desktop.main.overlays.windows.BsqSwapOfferDetailsWindow;
|
import bisq.desktop.main.overlays.windows.BsqSwapOfferDetailsWindow;
|
||||||
import bisq.desktop.main.overlays.windows.OfferDetailsWindow;
|
import bisq.desktop.main.overlays.windows.OfferDetailsWindow;
|
||||||
import bisq.desktop.main.portfolio.PortfolioView;
|
import bisq.desktop.main.portfolio.PortfolioView;
|
||||||
import bisq.desktop.main.portfolio.duplicateoffer.DuplicateOfferView;
|
import bisq.desktop.main.portfolio.presentation.PortfolioUtil;
|
||||||
import bisq.desktop.util.GUIUtil;
|
import bisq.desktop.util.GUIUtil;
|
||||||
|
|
||||||
import bisq.core.locale.Res;
|
import bisq.core.locale.Res;
|
||||||
import bisq.core.offer.Offer;
|
import bisq.core.offer.Offer;
|
||||||
import bisq.core.offer.OfferPayloadBase;
|
|
||||||
import bisq.core.offer.OpenOffer;
|
import bisq.core.offer.OpenOffer;
|
||||||
import bisq.core.user.DontShowAgainLookup;
|
import bisq.core.user.DontShowAgainLookup;
|
||||||
|
|
||||||
|
@ -98,7 +97,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||||
@FXML
|
@FXML
|
||||||
TableColumn<OpenOfferListItem, OpenOfferListItem> priceColumn, deviationColumn, amountColumn, volumeColumn,
|
TableColumn<OpenOfferListItem, OpenOfferListItem> priceColumn, deviationColumn, amountColumn, volumeColumn,
|
||||||
marketColumn, directionColumn, dateColumn, offerIdColumn, deactivateItemColumn,
|
marketColumn, directionColumn, dateColumn, offerIdColumn, deactivateItemColumn,
|
||||||
removeItemColumn, editItemColumn, triggerPriceColumn, triggerIconColumn, paymentMethodColumn;
|
removeItemColumn, editItemColumn, triggerPriceColumn, triggerIconColumn, paymentMethodColumn, duplicateItemColumn;
|
||||||
@FXML
|
@FXML
|
||||||
HBox searchBox;
|
HBox searchBox;
|
||||||
@FXML
|
@FXML
|
||||||
|
@ -152,6 +151,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||||
triggerPriceColumn.setGraphic(new AutoTooltipLabel(Res.get("openOffer.header.triggerPrice")));
|
triggerPriceColumn.setGraphic(new AutoTooltipLabel(Res.get("openOffer.header.triggerPrice")));
|
||||||
deactivateItemColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.enabled")));
|
deactivateItemColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.enabled")));
|
||||||
editItemColumn.setGraphic(new AutoTooltipLabel(""));
|
editItemColumn.setGraphic(new AutoTooltipLabel(""));
|
||||||
|
duplicateItemColumn.setGraphic(new AutoTooltipLabel(""));
|
||||||
removeItemColumn.setGraphic(new AutoTooltipLabel(""));
|
removeItemColumn.setGraphic(new AutoTooltipLabel(""));
|
||||||
|
|
||||||
setOfferIdColumnCellFactory();
|
setOfferIdColumnCellFactory();
|
||||||
|
@ -167,6 +167,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||||
setEditColumnCellFactory();
|
setEditColumnCellFactory();
|
||||||
setTriggerIconColumnCellFactory();
|
setTriggerIconColumnCellFactory();
|
||||||
setTriggerPriceColumnCellFactory();
|
setTriggerPriceColumnCellFactory();
|
||||||
|
setDuplicateColumnCellFactory();
|
||||||
setRemoveColumnCellFactory();
|
setRemoveColumnCellFactory();
|
||||||
|
|
||||||
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||||
|
@ -191,17 +192,9 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||||
tableView -> {
|
tableView -> {
|
||||||
final TableRow<OpenOfferListItem> row = new TableRow<>();
|
final TableRow<OpenOfferListItem> row = new TableRow<>();
|
||||||
final ContextMenu rowMenu = new ContextMenu();
|
final ContextMenu rowMenu = new ContextMenu();
|
||||||
MenuItem editItem = new MenuItem(Res.get("portfolio.context.offerLikeThis"));
|
MenuItem duplicateItem = new MenuItem(Res.get("portfolio.context.offerLikeThis"));
|
||||||
editItem.setOnAction((event) -> {
|
duplicateItem.setOnAction((event) -> onDuplicateOffer(row.getItem().getOffer()));
|
||||||
try {
|
rowMenu.getItems().add(duplicateItem);
|
||||||
OfferPayloadBase offerPayloadBase = row.getItem().getOffer().getOfferPayloadBase();
|
|
||||||
navigation.navigateToWithData(offerPayloadBase, MainView.class, PortfolioView.class,
|
|
||||||
DuplicateOfferView.class);
|
|
||||||
} catch (NullPointerException e) {
|
|
||||||
log.warn("Unable to get offerPayload - {}", e.toString());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
rowMenu.getItems().add(editItem);
|
|
||||||
row.contextMenuProperty().bind(
|
row.contextMenuProperty().bind(
|
||||||
Bindings.when(Bindings.isNotNull(row.itemProperty()))
|
Bindings.when(Bindings.isNotNull(row.itemProperty()))
|
||||||
.then(rowMenu)
|
.then(rowMenu)
|
||||||
|
@ -215,7 +208,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||||
searchBox.setSpacing(5);
|
searchBox.setSpacing(5);
|
||||||
HBox.setHgrow(searchBoxSpacer, Priority.ALWAYS);
|
HBox.setHgrow(searchBoxSpacer, Priority.ALWAYS);
|
||||||
|
|
||||||
selectToggleButton.setPadding(new Insets(0, 60, -20, 0));
|
selectToggleButton.setPadding(new Insets(0, 90, -20, 0));
|
||||||
selectToggleButton.setText(Res.get("shared.enabled"));
|
selectToggleButton.setText(Res.get("shared.enabled"));
|
||||||
selectToggleButton.setDisable(true);
|
selectToggleButton.setDisable(true);
|
||||||
|
|
||||||
|
@ -356,11 +349,8 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||||
if (model.getDirectionLabel(item).contains(filterString)) {
|
if (model.getDirectionLabel(item).contains(filterString)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (offer.getOfferFeePaymentTxId() != null &&
|
return offer.getOfferFeePaymentTxId() != null &&
|
||||||
offer.getOfferFeePaymentTxId().contains(filterString)) {
|
offer.getOfferFeePaymentTxId().contains(filterString);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,6 +430,14 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onDuplicateOffer(Offer offer) {
|
||||||
|
try {
|
||||||
|
PortfolioUtil.duplicateOffer(navigation, offer.getOfferPayloadBase());
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
log.warn("Unable to get offerPayload - {}", e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void setOfferIdColumnCellFactory() {
|
private void setOfferIdColumnCellFactory() {
|
||||||
offerIdColumn.setCellValueFactory((openOfferListItem) -> new ReadOnlyObjectWrapper<>(openOfferListItem.getValue()));
|
offerIdColumn.setCellValueFactory((openOfferListItem) -> new ReadOnlyObjectWrapper<>(openOfferListItem.getValue()));
|
||||||
offerIdColumn.getStyleClass().addAll("number-column", "first-column");
|
offerIdColumn.getStyleClass().addAll("number-column", "first-column");
|
||||||
|
@ -787,6 +785,40 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setDuplicateColumnCellFactory() {
|
||||||
|
duplicateItemColumn.getStyleClass().add("avatar-column");
|
||||||
|
duplicateItemColumn.setCellValueFactory((offerListItem) -> new ReadOnlyObjectWrapper<>(offerListItem.getValue()));
|
||||||
|
duplicateItemColumn.setCellFactory(
|
||||||
|
new Callback<>() {
|
||||||
|
@Override
|
||||||
|
public TableCell<OpenOfferListItem, OpenOfferListItem> call(TableColumn<OpenOfferListItem, OpenOfferListItem> column) {
|
||||||
|
return new TableCell<>() {
|
||||||
|
Button button;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateItem(final OpenOfferListItem item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
|
||||||
|
if (item != null && !empty) {
|
||||||
|
if (button == null) {
|
||||||
|
button = getRegularIconButton(MaterialDesignIcon.CONTENT_COPY);
|
||||||
|
button.setTooltip(new Tooltip(Res.get("shared.duplicateOffer")));
|
||||||
|
setGraphic(button);
|
||||||
|
}
|
||||||
|
button.setOnAction(event -> onDuplicateOffer(item.getOffer()));
|
||||||
|
} else {
|
||||||
|
setGraphic(null);
|
||||||
|
if (button != null) {
|
||||||
|
button.setOnAction(null);
|
||||||
|
button = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void setTriggerIconColumnCellFactory() {
|
private void setTriggerIconColumnCellFactory() {
|
||||||
triggerIconColumn.setCellValueFactory((offerListItem) -> new ReadOnlyObjectWrapper<>(offerListItem.getValue()));
|
triggerIconColumn.setCellValueFactory((offerListItem) -> new ReadOnlyObjectWrapper<>(offerListItem.getValue()));
|
||||||
triggerIconColumn.setCellFactory(
|
triggerIconColumn.setCellFactory(
|
||||||
|
|
|
@ -26,8 +26,7 @@ import bisq.desktop.components.PeerInfoIconTrading;
|
||||||
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.presentation.PortfolioUtil;
|
||||||
import bisq.desktop.main.portfolio.duplicateoffer.DuplicateOfferView;
|
|
||||||
import bisq.desktop.main.shared.ChatView;
|
import bisq.desktop.main.shared.ChatView;
|
||||||
import bisq.desktop.util.CssTheme;
|
import bisq.desktop.util.CssTheme;
|
||||||
import bisq.desktop.util.DisplayUtils;
|
import bisq.desktop.util.DisplayUtils;
|
||||||
|
@ -232,12 +231,12 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
||||||
tableView -> {
|
tableView -> {
|
||||||
final TableRow<PendingTradesListItem> row = new TableRow<>();
|
final TableRow<PendingTradesListItem> row = new TableRow<>();
|
||||||
final ContextMenu rowMenu = new ContextMenu();
|
final ContextMenu rowMenu = new ContextMenu();
|
||||||
MenuItem editItem = new MenuItem(Res.get("portfolio.context.offerLikeThis"));
|
MenuItem duplicateItem = new MenuItem(Res.get("portfolio.context.offerLikeThis"));
|
||||||
editItem.setOnAction((event) -> {
|
duplicateItem.setOnAction((event) -> {
|
||||||
try {
|
try {
|
||||||
OfferPayload offerPayload = row.getItem().getTrade().getOffer().getOfferPayload().orElseThrow();
|
OfferPayload offerPayload = row.getItem().getTrade().getOffer().getOfferPayload().orElseThrow();
|
||||||
if (offerPayload.getPubKeyRing().equals(keyRing.getPubKeyRing())) {
|
if (offerPayload.getPubKeyRing().equals(keyRing.getPubKeyRing())) {
|
||||||
navigation.navigateToWithData(offerPayload, MainView.class, PortfolioView.class, DuplicateOfferView.class);
|
PortfolioUtil.duplicateOffer(navigation, offerPayload);
|
||||||
} else {
|
} else {
|
||||||
new Popup().warning(Res.get("portfolio.context.notYourOffer")).show();
|
new Popup().warning(Res.get("portfolio.context.notYourOffer")).show();
|
||||||
}
|
}
|
||||||
|
@ -245,7 +244,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
||||||
log.warn("Unable to get offerPayload - {}", e.toString());
|
log.warn("Unable to get offerPayload - {}", e.toString());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
rowMenu.getItems().add(editItem);
|
rowMenu.getItems().add(duplicateItem);
|
||||||
row.contextMenuProperty().bind(
|
row.contextMenuProperty().bind(
|
||||||
Bindings.when(Bindings.isNotNull(row.itemProperty()))
|
Bindings.when(Bindings.isNotNull(row.itemProperty()))
|
||||||
.then(rowMenu)
|
.then(rowMenu)
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Bisq.
|
||||||
|
*
|
||||||
|
* Bisq 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.
|
||||||
|
*
|
||||||
|
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package bisq.desktop.main.portfolio.presentation;
|
||||||
|
|
||||||
|
import bisq.desktop.Navigation;
|
||||||
|
import bisq.desktop.main.MainView;
|
||||||
|
import bisq.desktop.main.offer.BuyOfferView;
|
||||||
|
import bisq.desktop.main.offer.SellOfferView;
|
||||||
|
import bisq.desktop.main.offer.bsq_swap.create_offer.BsqSwapCreateOfferView;
|
||||||
|
import bisq.desktop.main.portfolio.PortfolioView;
|
||||||
|
import bisq.desktop.main.portfolio.duplicateoffer.DuplicateOfferView;
|
||||||
|
|
||||||
|
import bisq.core.offer.OfferDirection;
|
||||||
|
import bisq.core.offer.OfferPayloadBase;
|
||||||
|
import bisq.core.offer.bsq_swap.BsqSwapOfferPayload;
|
||||||
|
|
||||||
|
public class PortfolioUtil {
|
||||||
|
|
||||||
|
public static void duplicateOffer(Navigation navigation, OfferPayloadBase offerPayload) {
|
||||||
|
if (offerPayload instanceof BsqSwapOfferPayload) {
|
||||||
|
var offerViewClass = offerPayload.getDirection() == OfferDirection.BUY ? BuyOfferView.class : SellOfferView.class;
|
||||||
|
navigation.navigateToWithData(offerPayload, MainView.class, offerViewClass, BsqSwapCreateOfferView.class);
|
||||||
|
} else {
|
||||||
|
navigation.navigateToWithData(offerPayload, MainView.class, PortfolioView.class, DuplicateOfferView.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue