From 7f73df5dfd761a26392fb6ae16adc937ef6bf9da Mon Sep 17 00:00:00 2001 From: jmacxx <47253594+jmacxx@users.noreply.github.com> Date: Tue, 20 Apr 2021 14:58:16 -0500 Subject: [PATCH 1/2] Functionality to duplicate an offer --- .../resources/i18n/displayStrings.properties | 3 + .../main/java/bisq/desktop/Navigation.java | 6 +- .../common/view/CachingViewLoader.java | 4 + .../main/java/bisq/desktop/main/MainView.java | 2 +- .../desktop/main/account/AccountView.java | 2 +- .../java/bisq/desktop/main/dao/DaoView.java | 2 +- .../desktop/main/dao/bonding/BondingView.java | 19 ++-- .../desktop/main/dao/burnbsq/BurnBsqView.java | 2 +- .../desktop/main/dao/economy/EconomyView.java | 2 +- .../main/dao/governance/GovernanceView.java | 2 +- .../desktop/main/dao/monitor/MonitorView.java | 2 +- .../main/dao/wallet/BsqWalletView.java | 22 +---- .../bisq/desktop/main/funds/FundsView.java | 2 +- .../bisq/desktop/main/market/MarketView.java | 2 +- .../main/offer/MutableOfferViewModel.java | 4 +- .../bisq/desktop/main/offer/OfferView.java | 2 +- .../desktop/main/portfolio/PortfolioView.java | 56 +++++++++-- .../closedtrades/ClosedTradesView.java | 42 +++++++++ .../DuplicateOfferDataModel.java | 92 +++++++++++++++++++ .../duplicateoffer/DuplicateOfferView.fxml | 24 +++++ .../duplicateoffer/DuplicateOfferView.java | 68 ++++++++++++++ .../DuplicateOfferViewModel.java | 92 +++++++++++++++++++ .../portfolio/openoffer/OpenOffersView.java | 27 ++++++ .../pendingtrades/PendingTradesView.java | 39 ++++++++ .../desktop/main/settings/SettingsView.java | 2 +- .../desktop/main/support/SupportView.java | 2 +- 26 files changed, 466 insertions(+), 56 deletions(-) create mode 100644 desktop/src/main/java/bisq/desktop/main/portfolio/duplicateoffer/DuplicateOfferDataModel.java create mode 100644 desktop/src/main/java/bisq/desktop/main/portfolio/duplicateoffer/DuplicateOfferView.fxml create mode 100644 desktop/src/main/java/bisq/desktop/main/portfolio/duplicateoffer/DuplicateOfferView.java create mode 100644 desktop/src/main/java/bisq/desktop/main/portfolio/duplicateoffer/DuplicateOfferViewModel.java diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index 6d58cbd4f73..7b833955dfd 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -583,6 +583,9 @@ portfolio.tab.pendingTrades=Open trades portfolio.tab.history=History portfolio.tab.failed=Failed portfolio.tab.editOpenOffer=Edit offer +portfolio.tab.duplicateOffer=Duplicate offer +portfolio.context.offerLikeThis=New offer like this... +portfolio.context.notYourOffer=You can only duplicate trades where you were the maker. portfolio.closedTrades.deviation.help=Percentage price deviation from market diff --git a/desktop/src/main/java/bisq/desktop/Navigation.java b/desktop/src/main/java/bisq/desktop/Navigation.java index cb9da123d79..b59bc8f8672 100644 --- a/desktop/src/main/java/bisq/desktop/Navigation.java +++ b/desktop/src/main/java/bisq/desktop/Navigation.java @@ -48,10 +48,7 @@ public final class Navigation implements PersistedDataHost { private static final ViewPath DEFAULT_VIEW_PATH = ViewPath.to(MainView.class, MarketView.class); public interface Listener { - void onNavigationRequested(ViewPath path); - - default void onNavigationRequested(ViewPath path, @Nullable Object data) { - } + void onNavigationRequested(ViewPath path, @Nullable Object data); } // New listeners can be added during iteration so we use CopyOnWriteArrayList to @@ -137,7 +134,6 @@ public void navigateTo(ViewPath newPath, @Nullable Object data) { currentPath = newPath; previousPath = currentPath; - listeners.forEach((e) -> e.onNavigationRequested(currentPath)); listeners.forEach((e) -> e.onNavigationRequested(currentPath, data)); requestPersistence(); } diff --git a/desktop/src/main/java/bisq/desktop/common/view/CachingViewLoader.java b/desktop/src/main/java/bisq/desktop/common/view/CachingViewLoader.java index 9f92d779191..06e47daace6 100644 --- a/desktop/src/main/java/bisq/desktop/common/view/CachingViewLoader.java +++ b/desktop/src/main/java/bisq/desktop/common/view/CachingViewLoader.java @@ -43,4 +43,8 @@ public View load(Class viewClass) { cache.put(viewClass, view); return view; } + + public void removeFromCache(Class viewClass) { + cache.remove(viewClass); + } } diff --git a/desktop/src/main/java/bisq/desktop/main/MainView.java b/desktop/src/main/java/bisq/desktop/main/MainView.java index ecd158be28e..854e8af9746 100644 --- a/desktop/src/main/java/bisq/desktop/main/MainView.java +++ b/desktop/src/main/java/bisq/desktop/main/MainView.java @@ -367,7 +367,7 @@ protected Tooltip computeValue() { setupBadge(supportButtonWithBadge, model.getNumOpenSupportTickets(), model.getShowOpenSupportTicketsNotification()); setupBadge(settingsButtonWithBadge, new SimpleStringProperty(Res.get("shared.new")), model.getShowSettingsUpdatesNotification()); - navigation.addListener(viewPath -> { + navigation.addListener((viewPath, data) -> { if (viewPath.size() != 2 || viewPath.indexOf(MainView.class) != 0) return; diff --git a/desktop/src/main/java/bisq/desktop/main/account/AccountView.java b/desktop/src/main/java/bisq/desktop/main/account/AccountView.java index 531f3ac3c09..40993a913e2 100644 --- a/desktop/src/main/java/bisq/desktop/main/account/AccountView.java +++ b/desktop/src/main/java/bisq/desktop/main/account/AccountView.java @@ -106,7 +106,7 @@ public void initialize() { walletInfoTab.setText(Res.get("account.menu.walletInfo").toUpperCase()); backupTab.setText(Res.get("account.menu.backup").toUpperCase()); - navigationListener = viewPath -> { + navigationListener = (viewPath, data) -> { if (viewPath.size() == 3 && viewPath.indexOf(AccountView.class) == 1) { if (arbitratorRegistrationTab == null && viewPath.get(2).equals(ArbitratorRegistrationView.class)) { navigation.navigateTo(MainView.class, AccountView.class, FiatAccountsView.class); diff --git a/desktop/src/main/java/bisq/desktop/main/dao/DaoView.java b/desktop/src/main/java/bisq/desktop/main/dao/DaoView.java index 7d34574c6ed..40b5f8082a5 100644 --- a/desktop/src/main/java/bisq/desktop/main/dao/DaoView.java +++ b/desktop/src/main/java/bisq/desktop/main/dao/DaoView.java @@ -111,7 +111,7 @@ public void initialize() { root.getTabs().addAll(factsAndFiguresTab, bsqWalletTab, proposalsTab, bondingTab, burnBsqTab, monitorTab); } - navigationListener = viewPath -> { + navigationListener = (viewPath, data) -> { if (viewPath.size() == 3 && viewPath.indexOf(DaoView.class) == 1) { if (proposalsTab == null && viewPath.get(2).equals(EconomyView.class)) navigation.navigateTo(MainView.class, DaoView.class, EconomyView.class); diff --git a/desktop/src/main/java/bisq/desktop/main/dao/bonding/BondingView.java b/desktop/src/main/java/bisq/desktop/main/dao/bonding/BondingView.java index b2d18cbd9ba..cbeb133f9b0 100644 --- a/desktop/src/main/java/bisq/desktop/main/dao/bonding/BondingView.java +++ b/desktop/src/main/java/bisq/desktop/main/dao/bonding/BondingView.java @@ -73,19 +73,12 @@ private BondingView(CachingViewLoader viewLoader, Navigation navigation) { @Override public void initialize() { - listener = new Navigation.Listener() { - @Override - public void onNavigationRequested(ViewPath path) { - } - - @Override - public void onNavigationRequested(ViewPath viewPath, @Nullable Object data) { - if (viewPath.size() != 4 || viewPath.indexOf(bisq.desktop.main.dao.bonding.BondingView.class) != 2) - return; - - selectedViewClass = viewPath.tip(); - loadView(selectedViewClass, data); - } + listener = (viewPath, data) -> { + if (viewPath.size() != 4 || viewPath.indexOf(bisq.desktop.main.dao.bonding.BondingView.class) != 2) + return; + + selectedViewClass = viewPath.tip(); + loadView(selectedViewClass, data); }; toggleGroup = new ToggleGroup(); diff --git a/desktop/src/main/java/bisq/desktop/main/dao/burnbsq/BurnBsqView.java b/desktop/src/main/java/bisq/desktop/main/dao/burnbsq/BurnBsqView.java index 59b1e280852..882da4aedf6 100644 --- a/desktop/src/main/java/bisq/desktop/main/dao/burnbsq/BurnBsqView.java +++ b/desktop/src/main/java/bisq/desktop/main/dao/burnbsq/BurnBsqView.java @@ -68,7 +68,7 @@ private BurnBsqView(CachingViewLoader viewLoader, Navigation navigation) { @Override public void initialize() { - listener = viewPath -> { + listener = (viewPath, data) -> { if (viewPath.size() != 4 || viewPath.indexOf(BurnBsqView.class) != 2) return; diff --git a/desktop/src/main/java/bisq/desktop/main/dao/economy/EconomyView.java b/desktop/src/main/java/bisq/desktop/main/dao/economy/EconomyView.java index ce54dd63f05..f21e6b62d30 100644 --- a/desktop/src/main/java/bisq/desktop/main/dao/economy/EconomyView.java +++ b/desktop/src/main/java/bisq/desktop/main/dao/economy/EconomyView.java @@ -71,7 +71,7 @@ private EconomyView(CachingViewLoader viewLoader, Navigation navigation) { @Override public void initialize() { - listener = viewPath -> { + listener = (viewPath, data) -> { if (viewPath.size() != 4 || viewPath.indexOf(EconomyView.class) != 2) return; diff --git a/desktop/src/main/java/bisq/desktop/main/dao/governance/GovernanceView.java b/desktop/src/main/java/bisq/desktop/main/dao/governance/GovernanceView.java index ac9faf64f97..6d0c6eaa56d 100644 --- a/desktop/src/main/java/bisq/desktop/main/dao/governance/GovernanceView.java +++ b/desktop/src/main/java/bisq/desktop/main/dao/governance/GovernanceView.java @@ -81,7 +81,7 @@ private GovernanceView(CachingViewLoader viewLoader, Navigation navigation, DaoF @Override public void initialize() { - navigationListener = viewPath -> { + navigationListener = (viewPath, data) -> { if (viewPath.size() != 4 || viewPath.indexOf(GovernanceView.class) != 2) return; diff --git a/desktop/src/main/java/bisq/desktop/main/dao/monitor/MonitorView.java b/desktop/src/main/java/bisq/desktop/main/dao/monitor/MonitorView.java index 23f94d3f4d1..d0b166dfc48 100644 --- a/desktop/src/main/java/bisq/desktop/main/dao/monitor/MonitorView.java +++ b/desktop/src/main/java/bisq/desktop/main/dao/monitor/MonitorView.java @@ -67,7 +67,7 @@ private MonitorView(CachingViewLoader viewLoader, Navigation navigation) { @Override public void initialize() { - navigationListener = viewPath -> { + navigationListener = (viewPath, data) -> { if (viewPath.size() != 4 || viewPath.indexOf(MonitorView.class) != 2) return; diff --git a/desktop/src/main/java/bisq/desktop/main/dao/wallet/BsqWalletView.java b/desktop/src/main/java/bisq/desktop/main/dao/wallet/BsqWalletView.java index e92de106119..c0fb6799974 100644 --- a/desktop/src/main/java/bisq/desktop/main/dao/wallet/BsqWalletView.java +++ b/desktop/src/main/java/bisq/desktop/main/dao/wallet/BsqWalletView.java @@ -74,24 +74,12 @@ private BsqWalletView(CachingViewLoader viewLoader, Navigation navigation) { @Override public void initialize() { - listener = new Navigation.Listener() { - @Override - public void onNavigationRequested(ViewPath viewPath) { - if (viewPath.size() != 4 || viewPath.indexOf(BsqWalletView.class) != 2) - return; - - selectedViewClass = viewPath.tip(); - loadView(selectedViewClass); - } - - @Override - public void onNavigationRequested(ViewPath viewPath, @Nullable Object data) { - if (viewPath.size() != 4 || viewPath.indexOf(BsqWalletView.class) != 2) - return; + listener = (viewPath, data) -> { + if (viewPath.size() != 4 || viewPath.indexOf(BsqWalletView.class) != 2) + return; - selectedViewClass = viewPath.tip(); - loadView(selectedViewClass, data); - } + selectedViewClass = viewPath.tip(); + loadView(selectedViewClass, data); }; toggleGroup = new ToggleGroup(); diff --git a/desktop/src/main/java/bisq/desktop/main/funds/FundsView.java b/desktop/src/main/java/bisq/desktop/main/funds/FundsView.java index 425b5bdd912..ce05c651e79 100644 --- a/desktop/src/main/java/bisq/desktop/main/funds/FundsView.java +++ b/desktop/src/main/java/bisq/desktop/main/funds/FundsView.java @@ -68,7 +68,7 @@ public void initialize() { lockedTab.setText(Res.get("funds.tab.locked").toUpperCase()); transactionsTab.setText(Res.get("funds.tab.transactions").toUpperCase()); - navigationListener = viewPath -> { + navigationListener = (viewPath, data) -> { if (viewPath.size() == 3 && viewPath.indexOf(FundsView.class) == 1) loadView(viewPath.tip()); }; diff --git a/desktop/src/main/java/bisq/desktop/main/market/MarketView.java b/desktop/src/main/java/bisq/desktop/main/market/MarketView.java index cca380d703d..d868271f910 100644 --- a/desktop/src/main/java/bisq/desktop/main/market/MarketView.java +++ b/desktop/src/main/java/bisq/desktop/main/market/MarketView.java @@ -101,7 +101,7 @@ public void initialize() { spreadTabPaymentMethod.setText(Res.get("market.tabs.spreadPayment").toUpperCase()); tradesTab.setText(Res.get("market.tabs.trades").toUpperCase()); - navigationListener = viewPath -> { + navigationListener = (viewPath, data) -> { if (viewPath.size() == 3 && viewPath.indexOf(MarketView.class) == 1) loadView(viewPath.tip()); }; diff --git a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java index 2bddeb41410..a136f6d8456 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java @@ -100,7 +100,7 @@ public abstract class MutableOfferViewModel ext private final BtcValidator btcValidator; private final BsqValidator bsqValidator; protected final SecurityDepositValidator securityDepositValidator; - private final PriceFeedService priceFeedService; + protected final PriceFeedService priceFeedService; private final AccountAgeWitnessService accountAgeWitnessService; private final Navigation navigation; private final Preferences preferences; @@ -179,7 +179,7 @@ public abstract class MutableOfferViewModel ext private ChangeListener isWalletFundedListener; private ChangeListener errorMessageListener; - private Offer offer; + protected Offer offer; private Timer timeoutTimer; private boolean inputIsMarketBasedPrice; private ChangeListener useMarketBasedPriceListener; diff --git a/desktop/src/main/java/bisq/desktop/main/offer/OfferView.java b/desktop/src/main/java/bisq/desktop/main/offer/OfferView.java index be6f209f0f9..e071b6967b8 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/OfferView.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/OfferView.java @@ -94,7 +94,7 @@ protected OfferView(ViewLoader viewLoader, @Override protected void initialize() { - navigationListener = viewPath -> { + navigationListener = (viewPath, data) -> { if (viewPath.size() == 3 && viewPath.indexOf(this.getClass()) == 1) loadView(viewPath.tip()); }; diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/PortfolioView.java b/desktop/src/main/java/bisq/desktop/main/portfolio/PortfolioView.java index c23e4607959..52809d5b192 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/PortfolioView.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/PortfolioView.java @@ -22,15 +22,16 @@ import bisq.desktop.common.view.CachingViewLoader; import bisq.desktop.common.view.FxmlView; import bisq.desktop.common.view.View; -import bisq.desktop.common.view.ViewLoader; import bisq.desktop.main.MainView; import bisq.desktop.main.portfolio.closedtrades.ClosedTradesView; +import bisq.desktop.main.portfolio.duplicateoffer.DuplicateOfferView; import bisq.desktop.main.portfolio.editoffer.EditOfferView; import bisq.desktop.main.portfolio.failedtrades.FailedTradesView; import bisq.desktop.main.portfolio.openoffer.OpenOffersView; import bisq.desktop.main.portfolio.pendingtrades.PendingTradesView; import bisq.core.locale.Res; +import bisq.core.offer.OfferPayload; import bisq.core.offer.OpenOffer; import bisq.core.trade.Trade; import bisq.core.trade.failed.FailedTradesManager; @@ -48,22 +49,25 @@ import java.util.List; +import javax.annotation.Nullable; + @FxmlView public class PortfolioView extends ActivatableView { @FXML Tab openOffersTab, pendingTradesTab, closedTradesTab; - private Tab editOpenOfferTab; + private Tab editOpenOfferTab, duplicateOfferTab; private final Tab failedTradesTab = new Tab(Res.get("portfolio.tab.failed").toUpperCase()); private Tab currentTab; private Navigation.Listener navigationListener; private ChangeListener tabChangeListener; private ListChangeListener tabListChangeListener; - private final ViewLoader viewLoader; + private final CachingViewLoader viewLoader; private final Navigation navigation; private final FailedTradesManager failedTradesManager; private EditOfferView editOfferView; + private DuplicateOfferView duplicateOfferView; private boolean editOpenOfferViewOpen; private OpenOffer openOffer; private OpenOffersView openOffersView; @@ -84,9 +88,9 @@ public void initialize() { pendingTradesTab.setText(Res.get("portfolio.tab.pendingTrades").toUpperCase()); closedTradesTab.setText(Res.get("portfolio.tab.history").toUpperCase()); - navigationListener = viewPath -> { + navigationListener = (viewPath, data) -> { if (viewPath.size() == 3 && viewPath.indexOf(PortfolioView.class) == 1) - loadView(viewPath.tip()); + loadView(viewPath.tip(), data); }; tabChangeListener = (ov, oldValue, newValue) -> { @@ -98,12 +102,16 @@ else if (newValue == closedTradesTab) navigation.navigateTo(MainView.class, PortfolioView.class, ClosedTradesView.class); else if (newValue == failedTradesTab) navigation.navigateTo(MainView.class, PortfolioView.class, FailedTradesView.class); - else if (newValue == editOpenOfferTab) { + else if (newValue == editOpenOfferTab) navigation.navigateTo(MainView.class, PortfolioView.class, EditOfferView.class); + else if (newValue == duplicateOfferTab) { + navigation.navigateTo(MainView.class, PortfolioView.class, DuplicateOfferView.class); } if (oldValue != null && oldValue == editOpenOfferTab) editOfferView.onTabSelected(false); + if (oldValue != null && oldValue == duplicateOfferTab) + duplicateOfferView.onTabSelected(false); }; @@ -112,6 +120,8 @@ else if (newValue == editOpenOfferTab) { List removedTabs = change.getRemoved(); if (removedTabs.size() == 1 && removedTabs.get(0).equals(editOpenOfferTab)) onEditOpenOfferRemoved(); + if (removedTabs.size() == 1 && removedTabs.get(0).equals(duplicateOfferTab)) + onDuplicateOfferRemoved(); }; } @@ -125,6 +135,15 @@ private void onEditOpenOfferRemoved() { navigation.navigateTo(MainView.class, this.getClass(), OpenOffersView.class); } + private void onDuplicateOfferRemoved() { + if (duplicateOfferView != null) { + duplicateOfferView.onClose(); + duplicateOfferView = null; + } + + navigation.navigateTo(MainView.class, this.getClass(), OpenOffersView.class); + } + @Override protected void activate() { failedTradesManager.getObservableList().addListener((ListChangeListener) c -> { @@ -149,6 +168,9 @@ else if (root.getSelectionModel().getSelectedItem() == failedTradesTab) else if (root.getSelectionModel().getSelectedItem() == editOpenOfferTab) { navigation.navigateTo(MainView.class, PortfolioView.class, EditOfferView.class); if (editOfferView != null) editOfferView.onTabSelected(true); + } else if (root.getSelectionModel().getSelectedItem() == duplicateOfferTab) { + navigation.navigateTo(MainView.class, PortfolioView.class, DuplicateOfferView.class); + if (duplicateOfferView != null) duplicateOfferView.onTabSelected(true); } } @@ -160,7 +182,7 @@ protected void deactivate() { currentTab = null; } - private void loadView(Class viewClass) { + private void loadView(Class viewClass, @Nullable Object data) { // we want to get activate/deactivate called, so we remove the old view on tab change // TODO Don't understand the check for currentTab != editOpenOfferTab if (currentTab != null && currentTab != editOpenOfferTab) @@ -195,6 +217,26 @@ private void loadView(Class viewClass) { view = viewLoader.load(OpenOffersView.class); selectOpenOffersView((OpenOffersView) view); } + } else if (view instanceof DuplicateOfferView) { + if (duplicateOfferView == null && data instanceof OfferPayload && data != null) { + viewLoader.removeFromCache(viewClass); // remove cached dialog + view = viewLoader.load(viewClass); // and load a fresh one + duplicateOfferView = (DuplicateOfferView) view; + duplicateOfferView.initWithData((OfferPayload) data); + duplicateOfferTab = new Tab(Res.get("portfolio.tab.duplicateOffer").toUpperCase()); + duplicateOfferView.setCloseHandler(() -> { + root.getTabs().remove(duplicateOfferTab); + }); + root.getTabs().add(duplicateOfferTab); + } + if (duplicateOfferView != null) { + if (currentTab != duplicateOfferTab) + duplicateOfferView.onTabSelected(true); + currentTab = duplicateOfferTab; + } else { + view = viewLoader.load(OpenOffersView.class); + selectOpenOffersView((OpenOffersView) view); + } } currentTab.setContent(view.getRoot()); diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/closedtrades/ClosedTradesView.java b/desktop/src/main/java/bisq/desktop/main/portfolio/closedtrades/ClosedTradesView.java index 50841a3afde..bb7e4266b7c 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/closedtrades/ClosedTradesView.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/closedtrades/ClosedTradesView.java @@ -17,6 +17,7 @@ package bisq.desktop.main.portfolio.closedtrades; +import bisq.desktop.Navigation; import bisq.desktop.common.view.ActivatableViewAndModel; import bisq.desktop.common.view.FxmlView; import bisq.desktop.components.AutoTooltipButton; @@ -25,14 +26,19 @@ import bisq.desktop.components.HyperlinkWithIcon; import bisq.desktop.components.InputTextField; import bisq.desktop.components.PeerInfoIcon; +import bisq.desktop.main.MainView; +import bisq.desktop.main.overlays.popups.Popup; import bisq.desktop.main.overlays.windows.ClosedTradesSummaryWindow; import bisq.desktop.main.overlays.windows.OfferDetailsWindow; import bisq.desktop.main.overlays.windows.TradeDetailsWindow; +import bisq.desktop.main.portfolio.PortfolioView; +import bisq.desktop.main.portfolio.duplicateoffer.DuplicateOfferView; import bisq.desktop.util.GUIUtil; import bisq.core.alert.PrivateNotificationManager; import bisq.core.locale.Res; import bisq.core.offer.Offer; +import bisq.core.offer.OfferPayload; import bisq.core.offer.OpenOffer; import bisq.core.trade.Contract; import bisq.core.trade.Tradable; @@ -42,6 +48,7 @@ import bisq.network.p2p.NodeAddress; import bisq.common.config.Config; +import bisq.common.crypto.KeyRing; import com.googlecode.jcsv.writer.CSVEntryConverter; @@ -53,9 +60,12 @@ import javafx.stage.Stage; import javafx.scene.Node; +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; @@ -66,6 +76,7 @@ import javafx.geometry.Insets; +import javafx.beans.binding.Bindings; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.value.ChangeListener; @@ -132,6 +143,8 @@ public String toString() { Region footerSpacer; private final OfferDetailsWindow offerDetailsWindow; + private final Navigation navigation; + private final KeyRing keyRing; private final Preferences preferences; private final TradeDetailsWindow tradeDetailsWindow; private final PrivateNotificationManager privateNotificationManager; @@ -143,12 +156,16 @@ public String toString() { @Inject public ClosedTradesView(ClosedTradesViewModel model, OfferDetailsWindow offerDetailsWindow, + Navigation navigation, + KeyRing keyRing, Preferences preferences, TradeDetailsWindow tradeDetailsWindow, PrivateNotificationManager privateNotificationManager, @Named(Config.USE_DEV_PRIVILEGE_KEYS) boolean useDevPrivilegeKeys) { super(model); this.offerDetailsWindow = offerDetailsWindow; + this.navigation = navigation; + this.keyRing = keyRing; this.preferences = preferences; this.tradeDetailsWindow = tradeDetailsWindow; this.privateNotificationManager = privateNotificationManager; @@ -232,6 +249,31 @@ public void initialize() { dateColumn.setSortType(TableColumn.SortType.DESCENDING); tableView.getSortOrder().add(dateColumn); + tableView.setRowFactory( + tableView -> { + final TableRow row = new TableRow<>(); + final ContextMenu rowMenu = new ContextMenu(); + MenuItem editItem = new MenuItem(Res.get("portfolio.context.offerLikeThis")); + editItem.setOnAction((event) -> { + try { + OfferPayload offerPayload = row.getItem().getTradable().getOffer().getOfferPayload(); + 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( + Bindings.when(Bindings.isNotNull(row.itemProperty())) + .then(rowMenu) + .otherwise((ContextMenu) null)); + return row; + }); + filterLabel.setText(Res.get("shared.filter")); HBox.setMargin(filterLabel, new Insets(5, 0, 0, 10)); filterTextFieldListener = (observable, oldValue, newValue) -> applyFilteredListPredicate(filterTextField.getText()); diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/duplicateoffer/DuplicateOfferDataModel.java b/desktop/src/main/java/bisq/desktop/main/portfolio/duplicateoffer/DuplicateOfferDataModel.java new file mode 100644 index 00000000000..dc356dc26df --- /dev/null +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/duplicateoffer/DuplicateOfferDataModel.java @@ -0,0 +1,92 @@ +/* + * 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 . + */ + +package bisq.desktop.main.portfolio.duplicateoffer; + + +import bisq.desktop.Navigation; +import bisq.desktop.main.offer.MutableOfferDataModel; + +import bisq.core.account.witness.AccountAgeWitnessService; +import bisq.core.btc.wallet.BsqWalletService; +import bisq.core.btc.wallet.BtcWalletService; +import bisq.core.offer.CreateOfferService; +import bisq.core.offer.Offer; +import bisq.core.offer.OfferUtil; +import bisq.core.offer.OpenOfferManager; +import bisq.core.provider.fee.FeeService; +import bisq.core.provider.price.PriceFeedService; +import bisq.core.trade.statistics.TradeStatisticsManager; +import bisq.core.user.Preferences; +import bisq.core.user.User; +import bisq.core.util.FormattingUtils; +import bisq.core.util.coin.CoinFormatter; + +import bisq.network.p2p.P2PService; + +import com.google.inject.Inject; + +import javax.inject.Named; + +class DuplicateOfferDataModel extends MutableOfferDataModel { + + @Inject + DuplicateOfferDataModel(CreateOfferService createOfferService, + OpenOfferManager openOfferManager, + OfferUtil offerUtil, + BtcWalletService btcWalletService, + BsqWalletService bsqWalletService, + Preferences preferences, + User user, + P2PService p2PService, + PriceFeedService priceFeedService, + AccountAgeWitnessService accountAgeWitnessService, + FeeService feeService, + @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter, + TradeStatisticsManager tradeStatisticsManager, + Navigation navigation) { + + super(createOfferService, + openOfferManager, + offerUtil, + btcWalletService, + bsqWalletService, + preferences, + user, + p2PService, + priceFeedService, + accountAgeWitnessService, + feeService, + btcFormatter, + tradeStatisticsManager, + navigation); + } + + public void populateData(Offer offer) { + if (offer == null) + return; + paymentAccount = user.getPaymentAccount(offer.getMakerPaymentAccountId()); + setMinAmount(offer.getMinAmount()); + setAmount(offer.getAmount()); + setPrice(offer.getPrice()); + setVolume(offer.getVolume()); + setUseMarketBasedPrice(offer.isUseMarketBasedPrice()); + if (offer.isUseMarketBasedPrice()) { + setMarketPriceMargin(offer.getMarketPriceMargin()); + } + } +} diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/duplicateoffer/DuplicateOfferView.fxml b/desktop/src/main/java/bisq/desktop/main/portfolio/duplicateoffer/DuplicateOfferView.fxml new file mode 100644 index 00000000000..3d870e01356 --- /dev/null +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/duplicateoffer/DuplicateOfferView.fxml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/duplicateoffer/DuplicateOfferView.java b/desktop/src/main/java/bisq/desktop/main/portfolio/duplicateoffer/DuplicateOfferView.java new file mode 100644 index 00000000000..ca1b1a4232b --- /dev/null +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/duplicateoffer/DuplicateOfferView.java @@ -0,0 +1,68 @@ +/* + * 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 . + */ + +package bisq.desktop.main.portfolio.duplicateoffer; + +import bisq.desktop.Navigation; +import bisq.desktop.common.view.FxmlView; +import bisq.desktop.main.offer.MutableOfferView; +import bisq.desktop.main.overlays.windows.OfferDetailsWindow; + +import bisq.core.locale.CurrencyUtil; +import bisq.core.offer.OfferPayload; +import bisq.core.user.Preferences; +import bisq.core.util.FormattingUtils; +import bisq.core.util.coin.BsqFormatter; +import bisq.core.util.coin.CoinFormatter; + +import com.google.inject.Inject; + +import javax.inject.Named; + +@FxmlView +public class DuplicateOfferView extends MutableOfferView { + + @Inject + private DuplicateOfferView(DuplicateOfferViewModel model, + Navigation navigation, + Preferences preferences, + OfferDetailsWindow offerDetailsWindow, + @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter, + BsqFormatter bsqFormatter) { + super(model, navigation, preferences, offerDetailsWindow, btcFormatter, bsqFormatter); + } + + @Override + protected void initialize() { + super.initialize(); + } + + @Override + protected void doActivate() { + super.doActivate(); + + updatePriceToggle(); + + // To force re-validation of payment account validation + onPaymentAccountsComboBoxSelected(); + } + + public void initWithData(OfferPayload offerPayload) { + initWithData(offerPayload.getDirection(), CurrencyUtil.getTradeCurrency(offerPayload.getCurrencyCode()).get()); + model.initWithData(offerPayload); + } +} diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/duplicateoffer/DuplicateOfferViewModel.java b/desktop/src/main/java/bisq/desktop/main/portfolio/duplicateoffer/DuplicateOfferViewModel.java new file mode 100644 index 00000000000..76f4f6e711d --- /dev/null +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/duplicateoffer/DuplicateOfferViewModel.java @@ -0,0 +1,92 @@ +/* + * 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 . + */ + +package bisq.desktop.main.portfolio.duplicateoffer; + +import bisq.desktop.Navigation; +import bisq.desktop.main.offer.MutableOfferViewModel; +import bisq.desktop.util.validation.AltcoinValidator; +import bisq.desktop.util.validation.BsqValidator; +import bisq.desktop.util.validation.BtcValidator; +import bisq.desktop.util.validation.FiatPriceValidator; +import bisq.desktop.util.validation.FiatVolumeValidator; +import bisq.desktop.util.validation.SecurityDepositValidator; + +import bisq.core.account.witness.AccountAgeWitnessService; +import bisq.core.offer.Offer; +import bisq.core.offer.OfferPayload; +import bisq.core.offer.OfferUtil; +import bisq.core.provider.price.PriceFeedService; +import bisq.core.user.Preferences; +import bisq.core.util.FormattingUtils; +import bisq.core.util.coin.BsqFormatter; +import bisq.core.util.coin.CoinFormatter; + +import com.google.inject.Inject; + +import javax.inject.Named; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +class DuplicateOfferViewModel extends MutableOfferViewModel { + + @Inject + public DuplicateOfferViewModel(DuplicateOfferDataModel dataModel, + FiatVolumeValidator fiatVolumeValidator, + FiatPriceValidator fiatPriceValidator, + AltcoinValidator altcoinValidator, + BtcValidator btcValidator, + BsqValidator bsqValidator, + SecurityDepositValidator securityDepositValidator, + PriceFeedService priceFeedService, + AccountAgeWitnessService accountAgeWitnessService, + Navigation navigation, + Preferences preferences, + @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter, + BsqFormatter bsqFormatter, + OfferUtil offerUtil) { + super(dataModel, + fiatVolumeValidator, + fiatPriceValidator, + altcoinValidator, + btcValidator, + bsqValidator, + securityDepositValidator, + priceFeedService, + accountAgeWitnessService, + navigation, + preferences, + btcFormatter, + bsqFormatter, + offerUtil); + syncMinAmountWithAmount = false; + } + + public void initWithData(OfferPayload offerPayload) { + this.offer = new Offer(offerPayload); + offer.setPriceFeedService(priceFeedService); + } + + @Override + public void activate() { + super.activate(); + dataModel.populateData(offer); + triggerFocusOutOnAmountFields(); + onFocusOutPriceAsPercentageTextField(true, false); + } +} diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/openoffer/OpenOffersView.java b/desktop/src/main/java/bisq/desktop/main/portfolio/openoffer/OpenOffersView.java index 1badc5dcf1f..4c08adef0b8 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/openoffer/OpenOffersView.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/openoffer/OpenOffersView.java @@ -32,10 +32,12 @@ import bisq.desktop.main.overlays.popups.Popup; import bisq.desktop.main.overlays.windows.OfferDetailsWindow; import bisq.desktop.main.portfolio.PortfolioView; +import bisq.desktop.main.portfolio.duplicateoffer.DuplicateOfferView; import bisq.desktop.util.GUIUtil; import bisq.core.locale.Res; import bisq.core.offer.Offer; +import bisq.core.offer.OfferPayload; import bisq.core.offer.OpenOffer; import bisq.core.user.DontShowAgainLookup; @@ -52,9 +54,12 @@ import javafx.scene.Node; import javafx.scene.Parent; import javafx.scene.control.Button; +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.image.ImageView; @@ -66,6 +71,7 @@ import javafx.geometry.Insets; +import javafx.beans.binding.Bindings; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.value.ChangeListener; @@ -173,6 +179,27 @@ public void initialize() { dateColumn.setSortType(TableColumn.SortType.DESCENDING); tableView.getSortOrder().add(dateColumn); + tableView.setRowFactory( + tableView -> { + final TableRow row = new TableRow<>(); + final ContextMenu rowMenu = new ContextMenu(); + MenuItem editItem = new MenuItem(Res.get("portfolio.context.offerLikeThis")); + editItem.setOnAction((event) -> { + try { + OfferPayload offerPayload = row.getItem().getOffer().getOfferPayload(); + navigation.navigateToWithData(offerPayload, MainView.class, PortfolioView.class, DuplicateOfferView.class); + } catch (NullPointerException e) { + log.warn("Unable to get offerPayload - {}", e.toString()); + } + }); + rowMenu.getItems().add(editItem); + row.contextMenuProperty().bind( + Bindings.when(Bindings.isNotNull(row.itemProperty())) + .then(rowMenu) + .otherwise((ContextMenu) null)); + return row; + }); + filterLabel.setText(Res.get("shared.filter")); HBox.setMargin(filterLabel, new Insets(5, 0, 0, 10)); filterTextFieldListener = (observable, oldValue, newValue) -> applyFilteredListPredicate(filterTextField.getText()); diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesView.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesView.java index a8c18935576..1c2c219e616 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesView.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesView.java @@ -17,6 +17,7 @@ package bisq.desktop.main.portfolio.pendingtrades; +import bisq.desktop.Navigation; import bisq.desktop.common.view.ActivatableViewAndModel; import bisq.desktop.common.view.FxmlView; import bisq.desktop.components.AutoTooltipLabel; @@ -25,6 +26,8 @@ import bisq.desktop.main.MainView; import bisq.desktop.main.overlays.popups.Popup; import bisq.desktop.main.overlays.windows.TradeDetailsWindow; +import bisq.desktop.main.portfolio.PortfolioView; +import bisq.desktop.main.portfolio.duplicateoffer.DuplicateOfferView; import bisq.desktop.main.shared.ChatView; import bisq.desktop.util.CssTheme; import bisq.desktop.util.DisplayUtils; @@ -32,6 +35,7 @@ import bisq.core.alert.PrivateNotificationManager; import bisq.core.locale.Res; +import bisq.core.offer.OfferPayload; import bisq.core.support.dispute.mediation.MediationResultState; import bisq.core.support.messages.ChatMessage; import bisq.core.support.traderchat.TradeChatSession; @@ -46,6 +50,7 @@ import bisq.common.UserThread; import bisq.common.config.Config; +import bisq.common.crypto.KeyRing; import bisq.common.crypto.PubKeyRing; import bisq.common.util.Utilities; @@ -67,8 +72,11 @@ import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.control.Button; +import javafx.scene.control.ContextMenu; +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.input.KeyCode; @@ -86,6 +94,7 @@ import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.Subscription; +import javafx.beans.binding.Bindings; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.value.ChangeListener; @@ -108,6 +117,8 @@ public interface ChatCallback { } private final TradeDetailsWindow tradeDetailsWindow; + private final Navigation navigation; + private final KeyRing keyRing; private final CoinFormatter formatter; private final PrivateNotificationManager privateNotificationManager; private final boolean useDevPrivilegeKeys; @@ -149,6 +160,8 @@ public interface ChatCallback { @Inject public PendingTradesView(PendingTradesViewModel model, TradeDetailsWindow tradeDetailsWindow, + Navigation navigation, + KeyRing keyRing, @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter, PrivateNotificationManager privateNotificationManager, Preferences preferences, @@ -156,6 +169,8 @@ public PendingTradesView(PendingTradesViewModel model, @Named(Config.USE_DEV_MODE_HEADER) boolean useDevModeHeader) { super(model); this.tradeDetailsWindow = tradeDetailsWindow; + this.navigation = navigation; + this.keyRing = keyRing; this.formatter = formatter; this.privateNotificationManager = privateNotificationManager; this.preferences = preferences; @@ -213,6 +228,30 @@ public void initialize() { dateColumn.setSortType(TableColumn.SortType.DESCENDING); tableView.getSortOrder().add(dateColumn); + tableView.setRowFactory( + tableView -> { + final TableRow row = new TableRow<>(); + final ContextMenu rowMenu = new ContextMenu(); + MenuItem editItem = new MenuItem(Res.get("portfolio.context.offerLikeThis")); + editItem.setOnAction((event) -> { + try { + OfferPayload offerPayload = row.getItem().getTrade().getOffer().getOfferPayload(); + 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( + Bindings.when(Bindings.isNotNull(row.itemProperty())) + .then(rowMenu) + .otherwise((ContextMenu) null)); + return row; + }); // we use a hidden emergency shortcut to open support ticket keyEventEventHandler = keyEvent -> { diff --git a/desktop/src/main/java/bisq/desktop/main/settings/SettingsView.java b/desktop/src/main/java/bisq/desktop/main/settings/SettingsView.java index 119566e467b..ae356120b59 100644 --- a/desktop/src/main/java/bisq/desktop/main/settings/SettingsView.java +++ b/desktop/src/main/java/bisq/desktop/main/settings/SettingsView.java @@ -66,7 +66,7 @@ public void initialize() { networkTab.setText(Res.get("settings.tab.network").toUpperCase()); aboutTab.setText(Res.get("settings.tab.about").toUpperCase()); - navigationListener = viewPath -> { + navigationListener = (viewPath, data) -> { if (viewPath.size() == 3 && viewPath.indexOf(SettingsView.class) == 1) loadView(viewPath.tip()); }; diff --git a/desktop/src/main/java/bisq/desktop/main/support/SupportView.java b/desktop/src/main/java/bisq/desktop/main/support/SupportView.java index 078bbaede39..5c23fb4924d 100644 --- a/desktop/src/main/java/bisq/desktop/main/support/SupportView.java +++ b/desktop/src/main/java/bisq/desktop/main/support/SupportView.java @@ -133,7 +133,7 @@ public void initialize() { if (tradersArbitrationDisputesTab != null) { tradersArbitrationDisputesTab.setText(Res.get("support.tab.legacyArbitration.support").toUpperCase()); } - navigationListener = viewPath -> { + navigationListener = (viewPath, data) -> { if (viewPath.size() == 3 && viewPath.indexOf(SupportView.class) == 1) loadView(viewPath.tip()); }; From a5d5eafddf7d575be42068b477d9b0dd4d29280c Mon Sep 17 00:00:00 2001 From: jmacxx <47253594+jmacxx@users.noreply.github.com> Date: Wed, 21 Apr 2021 15:54:16 -0500 Subject: [PATCH 2/2] @m52go edits and popup informing new feature --- .../main/resources/i18n/displayStrings.properties | 10 +++++----- .../main/java/bisq/desktop/main/MainViewModel.java | 14 +++----------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index 7b833955dfd..9fc8b0582d2 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -584,8 +584,8 @@ portfolio.tab.history=History portfolio.tab.failed=Failed portfolio.tab.editOpenOffer=Edit offer portfolio.tab.duplicateOffer=Duplicate offer -portfolio.context.offerLikeThis=New offer like this... -portfolio.context.notYourOffer=You can only duplicate trades where you were the maker. +portfolio.context.offerLikeThis=Create new offer like this... +portfolio.context.notYourOffer=You can only duplicate offers where you were the maker. portfolio.closedTrades.deviation.help=Percentage price deviation from market @@ -2948,9 +2948,9 @@ popup.shutDownInProgress.headline=Shut down in progress popup.shutDownInProgress.msg=Shutting down application can take a few seconds.\nPlease don't interrupt this process. popup.attention.forTradeWithId=Attention required for trade with ID {0} -popup.attention.reasonForPaymentRuleChange=Version 1.5.5 introduces a critical trade rule change regarding \ - the \"reason for payment\" field in bank transfers. Please leave this field empty -- \ - DO NOT use the trade ID as \"reason for payment\" anymore. +popup.attention.newFeatureDuplicateOffer=Version 1.6.3 introduces a new feature allowing easy re-entry of offers \ + by right-clicking on an existing offer or trade and choosing `Create new offer like this`. This is useful for \ + traders who frequently make the same offer. popup.info.multiplePaymentAccounts.headline=Multiple payment accounts available popup.info.multiplePaymentAccounts.msg=You have multiple payment accounts available for this offer. Please make sure you've picked the right one. diff --git a/desktop/src/main/java/bisq/desktop/main/MainViewModel.java b/desktop/src/main/java/bisq/desktop/main/MainViewModel.java index e787e6ad227..d9e14837def 100644 --- a/desktop/src/main/java/bisq/desktop/main/MainViewModel.java +++ b/desktop/src/main/java/bisq/desktop/main/MainViewModel.java @@ -278,22 +278,14 @@ public void onSetupComplete() { // We only show the popup if the user has already set up any fiat account. For new users it is not a rule // change and for altcoins its not relevant. - String key = "reasonForPaymentChange"; - boolean hasFiatAccount = user.getPaymentAccounts() != null && - user.getPaymentAccounts().stream() - .filter(e -> !(e.getPaymentAccountPayload() instanceof AssetsAccountPayload)) - .findAny() - .isPresent(); - if (hasFiatAccount && DontShowAgainLookup.showAgain(key)) { + String key = "newFeatureDuplicateOffer"; + if (DontShowAgainLookup.showAgain(key)) { UserThread.runAfter(() -> { - new Popup().attention(Res.get("popup.attention.reasonForPaymentRuleChange")). + new Popup().attention(Res.get("popup.attention.newFeatureDuplicateOffer")). dontShowAgainId(key) .closeButtonText(Res.get("shared.iUnderstand")) .show(); }, 1); - } else { - // If user add a fiat account later we don't show the popup as we assume it is a new user. - DontShowAgainLookup.dontShowAgain(key, true); } }