mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-24 15:10:44 +01:00
Merge pull request #5963 from xyzmaker123/transactions-filtering
Add missing filtering on lists
This commit is contained in:
commit
ffd2a92ae9
54 changed files with 1405 additions and 1650 deletions
|
@ -175,16 +175,6 @@ public class TradeUtil {
|
|||
return getCurrencyPair(trade.getOffer().getCurrencyCode());
|
||||
}
|
||||
|
||||
public String getPaymentMethodNameWithCountryCode(Trade trade) {
|
||||
if (trade == null)
|
||||
return "";
|
||||
|
||||
Offer offer = trade.getOffer();
|
||||
checkNotNull(offer);
|
||||
checkNotNull(offer.getPaymentMethod());
|
||||
return offer.getPaymentMethodNameWithCountryCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string describing a trader's role for a given trade.
|
||||
* @param trade Trade
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* 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.components.list;
|
||||
|
||||
import bisq.desktop.components.AutoTooltipLabel;
|
||||
import bisq.desktop.components.InputTextField;
|
||||
import bisq.desktop.util.filtering.FilterableListItem;
|
||||
|
||||
import bisq.core.locale.Res;
|
||||
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.layout.HBox;
|
||||
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.collections.transformation.FilteredList;
|
||||
|
||||
public class FilterBox extends HBox {
|
||||
private final InputTextField textField;
|
||||
private FilteredList<? extends FilterableListItem> filteredList;
|
||||
|
||||
private ChangeListener<String> listener;
|
||||
|
||||
public FilterBox() {
|
||||
super();
|
||||
setSpacing(5.0);
|
||||
|
||||
AutoTooltipLabel label = new AutoTooltipLabel(Res.get("shared.filter"));
|
||||
HBox.setMargin(label, new Insets(5.0, 0, 0, 10.0));
|
||||
|
||||
textField = new InputTextField();
|
||||
textField.setMinWidth(500);
|
||||
|
||||
getChildren().addAll(label, textField);
|
||||
}
|
||||
|
||||
public void initialize(FilteredList<? extends FilterableListItem> filteredList,
|
||||
TableView<? extends FilterableListItem> tableView) {
|
||||
this.filteredList = filteredList;
|
||||
listener = (observable, oldValue, newValue) -> {
|
||||
tableView.getSelectionModel().clearSelection();
|
||||
applyFilteredListPredicate(textField.getText());
|
||||
};
|
||||
}
|
||||
|
||||
public void activate() {
|
||||
textField.textProperty().addListener(listener);
|
||||
applyFilteredListPredicate(textField.getText());
|
||||
}
|
||||
|
||||
public void deactivate() {
|
||||
textField.textProperty().removeListener(listener);
|
||||
}
|
||||
|
||||
private void applyFilteredListPredicate(String filterString) {
|
||||
filteredList.setPredicate(item -> item.match(filterString));
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package bisq.desktop.main.funds.deposit;
|
||||
|
||||
import bisq.desktop.util.filtering.FilterableListItem;
|
||||
import bisq.desktop.components.indicator.TxConfidenceIndicator;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
|
||||
|
@ -34,6 +35,8 @@ import org.bitcoinj.core.TransactionConfidence;
|
|||
|
||||
import com.google.common.base.Suppliers;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import javafx.scene.control.Tooltip;
|
||||
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
|
@ -44,7 +47,7 @@ import java.util.function.Supplier;
|
|||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
class DepositListItem {
|
||||
class DepositListItem implements FilterableListItem {
|
||||
private final StringProperty balance = new SimpleStringProperty();
|
||||
private final BtcWalletService walletService;
|
||||
private Coin balanceAsCoin;
|
||||
|
@ -149,4 +152,18 @@ class DepositListItem {
|
|||
public int getNumTxOutputs() {
|
||||
return numTxOutputs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean match(String filterString) {
|
||||
if (filterString.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getAddressString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getUsage(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
return getBalance().contains(filterString);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,12 +23,13 @@
|
|||
<?import javafx.scene.layout.GridPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import bisq.desktop.components.list.FilterBox?>
|
||||
<VBox fx:id="root" fx:controller="bisq.desktop.main.funds.deposit.DepositView"
|
||||
spacing="10" xmlns:fx="http://javafx.com/fxml">
|
||||
<padding>
|
||||
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0"/>
|
||||
</padding>
|
||||
|
||||
<FilterBox fx:id="filterBox" />
|
||||
<TableView fx:id="tableView" VBox.vgrow="ALWAYS">
|
||||
<columns>
|
||||
<TableColumn fx:id="addressColumn" minWidth="320"/>
|
||||
|
|
|
@ -25,6 +25,7 @@ import bisq.desktop.components.ExternalHyperlink;
|
|||
import bisq.desktop.components.HyperlinkWithIcon;
|
||||
import bisq.desktop.components.InputTextField;
|
||||
import bisq.desktop.components.TitledGroupBg;
|
||||
import bisq.desktop.components.list.FilterBox;
|
||||
import bisq.desktop.main.overlays.popups.Popup;
|
||||
import bisq.desktop.main.overlays.windows.QRCodeWindow;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
|
@ -80,6 +81,7 @@ import javafx.beans.value.ChangeListener;
|
|||
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.collections.transformation.FilteredList;
|
||||
import javafx.collections.transformation.SortedList;
|
||||
|
||||
import javafx.util.Callback;
|
||||
|
@ -91,7 +93,10 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static bisq.desktop.util.FormBuilder.*;
|
||||
import static bisq.desktop.util.FormBuilder.addAddressTextField;
|
||||
import static bisq.desktop.util.FormBuilder.addButtonCheckBoxWithBox;
|
||||
import static bisq.desktop.util.FormBuilder.addInputTextField;
|
||||
import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
|
||||
|
||||
@FxmlView
|
||||
public class DepositView extends ActivatableView<VBox, Void> {
|
||||
|
@ -99,6 +104,8 @@ public class DepositView extends ActivatableView<VBox, Void> {
|
|||
@FXML
|
||||
GridPane gridPane;
|
||||
@FXML
|
||||
FilterBox filterBox;
|
||||
@FXML
|
||||
TableView<DepositListItem> tableView;
|
||||
@FXML
|
||||
TableColumn<DepositListItem, DepositListItem> addressColumn, balanceColumn, confirmationsColumn, usageColumn;
|
||||
|
@ -114,7 +121,8 @@ public class DepositView extends ActivatableView<VBox, Void> {
|
|||
private final CoinFormatter formatter;
|
||||
private String paymentLabelString;
|
||||
private final ObservableList<DepositListItem> observableList = FXCollections.observableArrayList();
|
||||
private final SortedList<DepositListItem> sortedList = new SortedList<>(observableList);
|
||||
private final FilteredList<DepositListItem> filteredList = new FilteredList<>(observableList);
|
||||
private final SortedList<DepositListItem> sortedList = new SortedList<>(filteredList);
|
||||
private BalanceListener balanceListener;
|
||||
private Subscription amountTextFieldSubscription;
|
||||
private ChangeListener<DepositListItem> tableViewSelectionListener;
|
||||
|
@ -135,7 +143,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
|
|||
|
||||
@Override
|
||||
public void initialize() {
|
||||
|
||||
filterBox.initialize(filteredList, tableView);
|
||||
paymentLabelString = Res.get("funds.deposit.fundBisqWallet");
|
||||
addressColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.address")));
|
||||
balanceColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.balanceWithCur", Res.getBaseCurrencyCode())));
|
||||
|
@ -238,6 +246,8 @@ public class DepositView extends ActivatableView<VBox, Void> {
|
|||
|
||||
@Override
|
||||
protected void activate() {
|
||||
filterBox.activate();
|
||||
|
||||
tableView.getSelectionModel().selectedItemProperty().addListener(tableViewSelectionListener);
|
||||
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
||||
|
||||
|
@ -255,6 +265,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
|
|||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
filterBox.deactivate();
|
||||
tableView.getSelectionModel().selectedItemProperty().removeListener(tableViewSelectionListener);
|
||||
sortedList.comparatorProperty().unbind();
|
||||
observableList.forEach(DepositListItem::cleanup);
|
||||
|
@ -267,7 +278,6 @@ public class DepositView extends ActivatableView<VBox, Void> {
|
|||
// UI handlers
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
private void fillForm(String address) {
|
||||
titledGroupBg.setVisible(true);
|
||||
titledGroupBg.setManaged(true);
|
||||
|
|
|
@ -17,8 +17,10 @@
|
|||
|
||||
package bisq.desktop.main.funds.locked;
|
||||
|
||||
import bisq.desktop.util.filtering.FilterableListItem;
|
||||
import bisq.desktop.components.AutoTooltipLabel;
|
||||
import bisq.desktop.util.DisplayUtils;
|
||||
import bisq.desktop.util.filtering.FilteringUtils;
|
||||
|
||||
import bisq.core.btc.listeners.BalanceListener;
|
||||
import bisq.core.btc.model.AddressEntry;
|
||||
|
@ -32,13 +34,15 @@ import org.bitcoinj.core.Address;
|
|||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import javafx.scene.control.Label;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
class LockedListItem {
|
||||
class LockedListItem implements FilterableListItem {
|
||||
private final BalanceListener balanceListener;
|
||||
private final BtcWalletService btcWalletService;
|
||||
private final CoinFormatter formatter;
|
||||
|
@ -117,4 +121,28 @@ class LockedListItem {
|
|||
DisplayUtils.formatDateTime(trade.getDate()) :
|
||||
Res.get("shared.noDateAvailable");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean match(String filterString) {
|
||||
if (filterString.isEmpty())
|
||||
return true;
|
||||
|
||||
if (StringUtils.containsIgnoreCase(getDetails(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringUtils.containsIgnoreCase(getDateString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringUtils.containsIgnoreCase(getAddressString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringUtils.containsIgnoreCase(getBalanceString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return FilteringUtils.match(getTrade(), filterString);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,12 +25,13 @@
|
|||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import bisq.desktop.components.list.FilterBox?>
|
||||
<VBox fx:id="root" fx:controller="bisq.desktop.main.funds.locked.LockedView"
|
||||
spacing="10" xmlns:fx="http://javafx.com/fxml">
|
||||
<padding>
|
||||
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0"/>
|
||||
</padding>
|
||||
|
||||
<FilterBox fx:id="filterBox" />
|
||||
<TableView fx:id="tableView" VBox.vgrow="ALWAYS">
|
||||
<columns>
|
||||
<TableColumn fx:id="dateColumn" minWidth="180" maxWidth="180"/>
|
||||
|
|
|
@ -23,6 +23,7 @@ import bisq.desktop.components.AutoTooltipButton;
|
|||
import bisq.desktop.components.AutoTooltipLabel;
|
||||
import bisq.desktop.components.ExternalHyperlink;
|
||||
import bisq.desktop.components.HyperlinkWithIcon;
|
||||
import bisq.desktop.components.list.FilterBox;
|
||||
import bisq.desktop.main.overlays.windows.OfferDetailsWindow;
|
||||
import bisq.desktop.main.overlays.windows.TradeDetailsWindow;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
|
@ -71,6 +72,7 @@ import javafx.beans.property.ReadOnlyObjectWrapper;
|
|||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.collections.transformation.FilteredList;
|
||||
import javafx.collections.transformation.SortedList;
|
||||
|
||||
import javafx.util.Callback;
|
||||
|
@ -83,6 +85,8 @@ import java.util.stream.Collectors;
|
|||
|
||||
@FxmlView
|
||||
public class LockedView extends ActivatableView<VBox, Void> {
|
||||
@FXML
|
||||
FilterBox filterBox;
|
||||
@FXML
|
||||
TableView<LockedListItem> tableView;
|
||||
@FXML
|
||||
|
@ -102,7 +106,8 @@ public class LockedView extends ActivatableView<VBox, Void> {
|
|||
private final OfferDetailsWindow offerDetailsWindow;
|
||||
private final TradeDetailsWindow tradeDetailsWindow;
|
||||
private final ObservableList<LockedListItem> observableList = FXCollections.observableArrayList();
|
||||
private final SortedList<LockedListItem> sortedList = new SortedList<>(observableList);
|
||||
private final FilteredList<LockedListItem> filteredList = new FilteredList<>(observableList);
|
||||
private final SortedList<LockedListItem> sortedList = new SortedList<>(filteredList);
|
||||
private BalanceListener balanceListener;
|
||||
private ListChangeListener<OpenOffer> openOfferListChangeListener;
|
||||
private ListChangeListener<Trade> tradeListChangeListener;
|
||||
|
@ -131,6 +136,7 @@ public class LockedView extends ActivatableView<VBox, Void> {
|
|||
|
||||
@Override
|
||||
public void initialize() {
|
||||
filterBox.initialize(filteredList, tableView);
|
||||
dateColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.dateTime")));
|
||||
detailsColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.details")));
|
||||
addressColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.address")));
|
||||
|
@ -168,6 +174,7 @@ public class LockedView extends ActivatableView<VBox, Void> {
|
|||
|
||||
@Override
|
||||
protected void activate() {
|
||||
filterBox.activate();
|
||||
openOfferManager.getObservableList().addListener(openOfferListChangeListener);
|
||||
tradeManager.getObservableList().addListener(tradeListChangeListener);
|
||||
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
||||
|
@ -206,6 +213,7 @@ public class LockedView extends ActivatableView<VBox, Void> {
|
|||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
filterBox.deactivate();
|
||||
openOfferManager.getObservableList().removeListener(openOfferListChangeListener);
|
||||
tradeManager.getObservableList().removeListener(tradeListChangeListener);
|
||||
sortedList.comparatorProperty().unbind();
|
||||
|
|
|
@ -17,8 +17,10 @@
|
|||
|
||||
package bisq.desktop.main.funds.reserved;
|
||||
|
||||
import bisq.desktop.util.filtering.FilterableListItem;
|
||||
import bisq.desktop.components.AutoTooltipLabel;
|
||||
import bisq.desktop.util.DisplayUtils;
|
||||
import bisq.desktop.util.filtering.FilteringUtils;
|
||||
|
||||
import bisq.core.btc.listeners.BalanceListener;
|
||||
import bisq.core.btc.model.AddressEntry;
|
||||
|
@ -31,13 +33,15 @@ import org.bitcoinj.core.Address;
|
|||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import javafx.scene.control.Label;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
class ReservedListItem {
|
||||
class ReservedListItem implements FilterableListItem {
|
||||
private final BalanceListener balanceListener;
|
||||
private final BtcWalletService btcWalletService;
|
||||
private final CoinFormatter formatter;
|
||||
|
@ -114,4 +118,24 @@ class ReservedListItem {
|
|||
Res.get("funds.reserved.reserved", openOffer.getShortId()) :
|
||||
Res.get("shared.noDetailsAvailable");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean match(String filterString) {
|
||||
if (filterString.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getDetails(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getAddressString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getDateAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getBalanceString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
return FilteringUtils.match(getOpenOffer().getOffer(), filterString);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,12 +25,13 @@
|
|||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import bisq.desktop.components.list.FilterBox?>
|
||||
<VBox fx:id="root" fx:controller="bisq.desktop.main.funds.reserved.ReservedView"
|
||||
spacing="10" xmlns:fx="http://javafx.com/fxml">
|
||||
<padding>
|
||||
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0"/>
|
||||
</padding>
|
||||
|
||||
<FilterBox fx:id="filterBox" />
|
||||
<TableView fx:id="tableView" VBox.vgrow="ALWAYS">
|
||||
<columns>
|
||||
<TableColumn fx:id="dateColumn" minWidth="180" maxWidth="180"/>
|
||||
|
|
|
@ -23,6 +23,7 @@ import bisq.desktop.components.AutoTooltipButton;
|
|||
import bisq.desktop.components.AutoTooltipLabel;
|
||||
import bisq.desktop.components.ExternalHyperlink;
|
||||
import bisq.desktop.components.HyperlinkWithIcon;
|
||||
import bisq.desktop.components.list.FilterBox;
|
||||
import bisq.desktop.main.overlays.windows.OfferDetailsWindow;
|
||||
import bisq.desktop.main.overlays.windows.TradeDetailsWindow;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
|
@ -71,6 +72,7 @@ import javafx.beans.property.ReadOnlyObjectWrapper;
|
|||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.collections.transformation.FilteredList;
|
||||
import javafx.collections.transformation.SortedList;
|
||||
|
||||
import javafx.util.Callback;
|
||||
|
@ -83,6 +85,8 @@ import java.util.stream.Collectors;
|
|||
|
||||
@FxmlView
|
||||
public class ReservedView extends ActivatableView<VBox, Void> {
|
||||
@FXML
|
||||
FilterBox filterBox;
|
||||
@FXML
|
||||
TableView<ReservedListItem> tableView;
|
||||
@FXML
|
||||
|
@ -102,7 +106,8 @@ public class ReservedView extends ActivatableView<VBox, Void> {
|
|||
private final OfferDetailsWindow offerDetailsWindow;
|
||||
private final TradeDetailsWindow tradeDetailsWindow;
|
||||
private final ObservableList<ReservedListItem> observableList = FXCollections.observableArrayList();
|
||||
private final SortedList<ReservedListItem> sortedList = new SortedList<>(observableList);
|
||||
private final FilteredList<ReservedListItem> filteredList = new FilteredList<>(observableList);
|
||||
private final SortedList<ReservedListItem> sortedList = new SortedList<>(filteredList);
|
||||
private BalanceListener balanceListener;
|
||||
private ListChangeListener<OpenOffer> openOfferListChangeListener;
|
||||
private ListChangeListener<Trade> tradeListChangeListener;
|
||||
|
@ -131,6 +136,7 @@ public class ReservedView extends ActivatableView<VBox, Void> {
|
|||
|
||||
@Override
|
||||
public void initialize() {
|
||||
filterBox.initialize(filteredList, tableView);
|
||||
dateColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.dateTime")));
|
||||
detailsColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.details")));
|
||||
addressColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.address")));
|
||||
|
@ -168,6 +174,7 @@ public class ReservedView extends ActivatableView<VBox, Void> {
|
|||
|
||||
@Override
|
||||
protected void activate() {
|
||||
filterBox.activate();
|
||||
openOfferManager.getObservableList().addListener(openOfferListChangeListener);
|
||||
tradeManager.getObservableList().addListener(tradeListChangeListener);
|
||||
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
||||
|
@ -206,6 +213,7 @@ public class ReservedView extends ActivatableView<VBox, Void> {
|
|||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
filterBox.deactivate();
|
||||
openOfferManager.getObservableList().removeListener(openOfferListChangeListener);
|
||||
tradeManager.getObservableList().removeListener(tradeListChangeListener);
|
||||
sortedList.comparatorProperty().unbind();
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
* 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.funds.transactions;
|
||||
|
||||
import bisq.core.btc.wallet.BtcWalletService;
|
||||
import bisq.core.trade.model.Tradable;
|
||||
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
class DisplayedTransactions extends ObservableListDecorator<TransactionsListItem> {
|
||||
private final BtcWalletService btcWalletService;
|
||||
private final TradableRepository tradableRepository;
|
||||
private final TransactionListItemFactory transactionListItemFactory;
|
||||
private final TransactionAwareTradableFactory transactionAwareTradableFactory;
|
||||
|
||||
DisplayedTransactions(BtcWalletService btcWalletService, TradableRepository tradableRepository,
|
||||
TransactionListItemFactory transactionListItemFactory,
|
||||
TransactionAwareTradableFactory transactionAwareTradableFactory) {
|
||||
this.btcWalletService = btcWalletService;
|
||||
this.tradableRepository = tradableRepository;
|
||||
this.transactionListItemFactory = transactionListItemFactory;
|
||||
this.transactionAwareTradableFactory = transactionAwareTradableFactory;
|
||||
}
|
||||
|
||||
void update() {
|
||||
List<TransactionsListItem> transactionsListItems = getTransactionListItems();
|
||||
// are sorted by getRecentTransactions
|
||||
forEach(TransactionsListItem::cleanup);
|
||||
setAll(transactionsListItems);
|
||||
}
|
||||
|
||||
private List<TransactionsListItem> getTransactionListItems() {
|
||||
Set<Transaction> transactions = btcWalletService.getTransactions(false);
|
||||
return transactions.stream()
|
||||
.map(this::convertTransactionToListItem)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private TransactionsListItem convertTransactionToListItem(Transaction transaction) {
|
||||
Set<Tradable> tradables = tradableRepository.getAll();
|
||||
|
||||
TransactionAwareTradable maybeTradable = tradables.stream()
|
||||
.map(transactionAwareTradableFactory::create)
|
||||
.filter(tradable -> tradable.isRelatedToTransaction(transaction))
|
||||
.findAny()
|
||||
.orElse(null);
|
||||
|
||||
return transactionListItemFactory.create(transaction, maybeTradable);
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* 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.funds.transactions;
|
||||
|
||||
import bisq.core.btc.wallet.BtcWalletService;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
@Singleton
|
||||
public class DisplayedTransactionsFactory {
|
||||
private final BtcWalletService btcWalletService;
|
||||
private final TradableRepository tradableRepository;
|
||||
private final TransactionListItemFactory transactionListItemFactory;
|
||||
private final TransactionAwareTradableFactory transactionAwareTradableFactory;
|
||||
|
||||
@Inject
|
||||
DisplayedTransactionsFactory(BtcWalletService btcWalletService,
|
||||
TradableRepository tradableRepository,
|
||||
TransactionListItemFactory transactionListItemFactory,
|
||||
TransactionAwareTradableFactory transactionAwareTradableFactory) {
|
||||
this.btcWalletService = btcWalletService;
|
||||
this.tradableRepository = tradableRepository;
|
||||
this.transactionListItemFactory = transactionListItemFactory;
|
||||
this.transactionAwareTradableFactory = transactionAwareTradableFactory;
|
||||
}
|
||||
|
||||
DisplayedTransactions create() {
|
||||
return new DisplayedTransactions(btcWalletService, tradableRepository, transactionListItemFactory,
|
||||
transactionAwareTradableFactory);
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* 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.funds.transactions;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.collections.transformation.SortedList;
|
||||
|
||||
import java.util.AbstractList;
|
||||
import java.util.Collection;
|
||||
|
||||
class ObservableListDecorator<T> extends AbstractList<T> {
|
||||
private final ObservableList<T> delegate = FXCollections.observableArrayList();
|
||||
|
||||
SortedList<T> asSortedList() {
|
||||
return new SortedList<>(delegate);
|
||||
}
|
||||
|
||||
void setAll(Collection<? extends T> elements) {
|
||||
delegate.setAll(elements);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get(int index) {
|
||||
return delegate.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return delegate.size();
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* 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.funds.transactions;
|
||||
|
||||
import bisq.core.btc.wallet.BtcWalletService;
|
||||
import bisq.core.offer.OpenOffer;
|
||||
import bisq.core.support.dispute.arbitration.ArbitrationManager;
|
||||
import bisq.core.support.dispute.refund.RefundManager;
|
||||
import bisq.core.trade.model.Tradable;
|
||||
import bisq.core.trade.model.TradeModel;
|
||||
|
||||
import bisq.common.crypto.PubKeyRing;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
|
||||
@Singleton
|
||||
public class TransactionAwareTradableFactory {
|
||||
private final ArbitrationManager arbitrationManager;
|
||||
private final RefundManager refundManager;
|
||||
private final BtcWalletService btcWalletService;
|
||||
private final PubKeyRing pubKeyRing;
|
||||
|
||||
@Inject
|
||||
TransactionAwareTradableFactory(ArbitrationManager arbitrationManager,
|
||||
RefundManager refundManager,
|
||||
BtcWalletService btcWalletService,
|
||||
PubKeyRing pubKeyRing) {
|
||||
this.arbitrationManager = arbitrationManager;
|
||||
this.refundManager = refundManager;
|
||||
this.btcWalletService = btcWalletService;
|
||||
this.pubKeyRing = pubKeyRing;
|
||||
}
|
||||
|
||||
TransactionAwareTradable create(Tradable tradable) {
|
||||
if (tradable instanceof OpenOffer) {
|
||||
return new TransactionAwareOpenOffer((OpenOffer) tradable);
|
||||
} else if (tradable instanceof TradeModel) {
|
||||
return new TransactionAwareTrade((TradeModel) tradable,
|
||||
arbitrationManager,
|
||||
refundManager,
|
||||
btcWalletService,
|
||||
pubKeyRing);
|
||||
} else {
|
||||
return new DummyTransactionAwareTradable(tradable);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* 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.funds.transactions;
|
||||
|
||||
import bisq.core.btc.wallet.BsqWalletService;
|
||||
import bisq.core.btc.wallet.BtcWalletService;
|
||||
import bisq.core.dao.DaoFacade;
|
||||
import bisq.core.user.Preferences;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
@Singleton
|
||||
public class TransactionListItemFactory {
|
||||
private final BtcWalletService btcWalletService;
|
||||
private final BsqWalletService bsqWalletService;
|
||||
private final DaoFacade daoFacade;
|
||||
private final CoinFormatter formatter;
|
||||
private final Preferences preferences;
|
||||
|
||||
@Inject
|
||||
TransactionListItemFactory(BtcWalletService btcWalletService,
|
||||
BsqWalletService bsqWalletService,
|
||||
DaoFacade daoFacade,
|
||||
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter,
|
||||
Preferences preferences) {
|
||||
this.btcWalletService = btcWalletService;
|
||||
this.bsqWalletService = bsqWalletService;
|
||||
this.daoFacade = daoFacade;
|
||||
this.formatter = formatter;
|
||||
this.preferences = preferences;
|
||||
}
|
||||
|
||||
TransactionsListItem create(Transaction transaction, @Nullable TransactionAwareTradable tradable) {
|
||||
return new TransactionsListItem(transaction,
|
||||
btcWalletService,
|
||||
bsqWalletService,
|
||||
tradable,
|
||||
daoFacade,
|
||||
formatter,
|
||||
preferences.getIgnoreDustThreshold());
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package bisq.desktop.main.funds.transactions;
|
||||
|
||||
import bisq.desktop.util.filtering.FilterableListItem;
|
||||
import bisq.desktop.components.indicator.TxConfidenceIndicator;
|
||||
import bisq.desktop.util.DisplayUtils;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
|
@ -43,6 +44,8 @@ import org.bitcoinj.core.TransactionOutput;
|
|||
|
||||
import com.google.common.base.Suppliers;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import javafx.scene.control.Tooltip;
|
||||
|
||||
import java.util.Date;
|
||||
|
@ -55,7 +58,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||
import javax.annotation.Nullable;
|
||||
|
||||
@Slf4j
|
||||
class TransactionsListItem {
|
||||
class TransactionsListItem implements FilterableListItem {
|
||||
private final BtcWalletService btcWalletService;
|
||||
private final CoinFormatter formatter;
|
||||
private String dateString;
|
||||
|
@ -377,4 +380,30 @@ class TransactionsListItem {
|
|||
public String getMemo() {
|
||||
return memo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean match(String filterString) {
|
||||
if (filterString.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getTxId(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getDetails(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (getMemo() != null && StringUtils.containsIgnoreCase(getMemo(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getDirection(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getDateString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getAmount(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
return StringUtils.containsIgnoreCase(getAddressString(), filterString);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,11 +25,13 @@
|
|||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import bisq.desktop.components.list.FilterBox?>
|
||||
<VBox fx:id="root" fx:controller="bisq.desktop.main.funds.transactions.TransactionsView"
|
||||
spacing="10" alignment="CENTER_RIGHT" xmlns:fx="http://javafx.com/fxml">
|
||||
<padding>
|
||||
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0"/>
|
||||
</padding>
|
||||
<FilterBox fx:id="filterBox" />
|
||||
<TableView fx:id="tableView" VBox.vgrow="ALWAYS">
|
||||
<columns>
|
||||
<TableColumn fx:id="dateColumn" minWidth="180" maxWidth="180"/>
|
||||
|
|
|
@ -24,6 +24,7 @@ import bisq.desktop.components.AutoTooltipButton;
|
|||
import bisq.desktop.components.AutoTooltipLabel;
|
||||
import bisq.desktop.components.ExternalHyperlink;
|
||||
import bisq.desktop.components.HyperlinkWithIcon;
|
||||
import bisq.desktop.components.list.FilterBox;
|
||||
import bisq.desktop.main.overlays.popups.Popup;
|
||||
import bisq.desktop.main.overlays.windows.BsqTradeDetailsWindow;
|
||||
import bisq.desktop.main.overlays.windows.OfferDetailsWindow;
|
||||
|
@ -31,16 +32,24 @@ import bisq.desktop.main.overlays.windows.TradeDetailsWindow;
|
|||
import bisq.desktop.util.GUIUtil;
|
||||
|
||||
import bisq.core.btc.setup.WalletsSetup;
|
||||
import bisq.core.btc.wallet.BsqWalletService;
|
||||
import bisq.core.btc.wallet.BtcWalletService;
|
||||
import bisq.core.dao.DaoFacade;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.offer.OpenOffer;
|
||||
import bisq.core.support.dispute.arbitration.ArbitrationManager;
|
||||
import bisq.core.support.dispute.refund.RefundManager;
|
||||
import bisq.core.trade.model.Tradable;
|
||||
import bisq.core.trade.model.TradeModel;
|
||||
import bisq.core.trade.model.bisq_v1.Trade;
|
||||
import bisq.core.trade.model.bsq_swap.BsqSwapTrade;
|
||||
import bisq.core.user.Preferences;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
import bisq.network.p2p.P2PService;
|
||||
|
||||
import bisq.common.crypto.PubKeyRing;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import org.bitcoinj.core.TransactionConfidence;
|
||||
|
@ -49,6 +58,7 @@ import org.bitcoinj.wallet.listeners.WalletChangeEventListener;
|
|||
import com.googlecode.jcsv.writer.CSVEntryConverter;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||
|
||||
|
@ -76,17 +86,24 @@ import javafx.beans.property.ReadOnlyObjectWrapper;
|
|||
|
||||
import javafx.event.EventHandler;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.collections.transformation.FilteredList;
|
||||
import javafx.collections.transformation.SortedList;
|
||||
|
||||
import javafx.util.Callback;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@FxmlView
|
||||
public class TransactionsView extends ActivatableView<VBox, Void> {
|
||||
@FXML
|
||||
FilterBox filterBox;
|
||||
@FXML
|
||||
TableView<TransactionsListItem> tableView;
|
||||
@FXML
|
||||
|
@ -98,13 +115,21 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||
@FXML
|
||||
AutoTooltipButton exportButton;
|
||||
|
||||
private final DisplayedTransactions displayedTransactions;
|
||||
private final SortedList<TransactionsListItem> sortedDisplayedTransactions;
|
||||
private final ObservableList<TransactionsListItem> observableList = FXCollections.observableArrayList();
|
||||
private final FilteredList<TransactionsListItem> filteredList = new FilteredList<>(observableList);
|
||||
private final SortedList<TransactionsListItem> sortedList = new SortedList<>(filteredList);
|
||||
|
||||
private final BtcWalletService btcWalletService;
|
||||
private final BsqWalletService bsqWalletService;
|
||||
private final CoinFormatter formatter;
|
||||
private final DaoFacade daoFacade;
|
||||
private final P2PService p2PService;
|
||||
private final WalletsSetup walletsSetup;
|
||||
private final Preferences preferences;
|
||||
private final TradableRepository tradableRepository;
|
||||
private final ArbitrationManager arbitrationManager;
|
||||
private final RefundManager refundManager;
|
||||
private final PubKeyRing pubKeyRing;
|
||||
private final TradeDetailsWindow tradeDetailsWindow;
|
||||
private final BsqTradeDetailsWindow bsqTradeDetailsWindow;
|
||||
private final OfferDetailsWindow offerDetailsWindow;
|
||||
|
@ -120,26 +145,38 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||
|
||||
@Inject
|
||||
private TransactionsView(BtcWalletService btcWalletService,
|
||||
BsqWalletService bsqWalletService,
|
||||
DaoFacade daoFacade,
|
||||
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter,
|
||||
P2PService p2PService,
|
||||
WalletsSetup walletsSetup,
|
||||
Preferences preferences,
|
||||
TradableRepository tradableRepository,
|
||||
ArbitrationManager arbitrationManager,
|
||||
RefundManager refundManager,
|
||||
PubKeyRing pubKeyRing,
|
||||
TradeDetailsWindow tradeDetailsWindow,
|
||||
BsqTradeDetailsWindow bsqTradeDetailsWindow,
|
||||
OfferDetailsWindow offerDetailsWindow,
|
||||
DisplayedTransactionsFactory displayedTransactionsFactory) {
|
||||
OfferDetailsWindow offerDetailsWindow) {
|
||||
this.btcWalletService = btcWalletService;
|
||||
this.bsqWalletService = bsqWalletService;
|
||||
this.daoFacade = daoFacade;
|
||||
this.formatter = formatter;
|
||||
this.p2PService = p2PService;
|
||||
this.walletsSetup = walletsSetup;
|
||||
this.preferences = preferences;
|
||||
this.tradableRepository = tradableRepository;
|
||||
this.arbitrationManager = arbitrationManager;
|
||||
this.refundManager = refundManager;
|
||||
this.pubKeyRing = pubKeyRing;
|
||||
this.tradeDetailsWindow = tradeDetailsWindow;
|
||||
this.bsqTradeDetailsWindow = bsqTradeDetailsWindow;
|
||||
this.offerDetailsWindow = offerDetailsWindow;
|
||||
this.displayedTransactions = displayedTransactionsFactory.create();
|
||||
this.sortedDisplayedTransactions = displayedTransactions.asSortedList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
filterBox.initialize(filteredList, tableView);
|
||||
dateColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.dateTime")));
|
||||
detailsColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.details")));
|
||||
addressColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.address")));
|
||||
|
@ -179,7 +216,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||
tableView.getSortOrder().add(dateColumn);
|
||||
|
||||
walletChangeEventListener = wallet -> {
|
||||
displayedTransactions.update();
|
||||
updateList();
|
||||
};
|
||||
|
||||
keyEventEventHandler = event -> {
|
||||
|
@ -202,9 +239,10 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||
|
||||
@Override
|
||||
protected void activate() {
|
||||
sortedDisplayedTransactions.comparatorProperty().bind(tableView.comparatorProperty());
|
||||
tableView.setItems(sortedDisplayedTransactions);
|
||||
displayedTransactions.update();
|
||||
filterBox.activate();
|
||||
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
||||
tableView.setItems(sortedList);
|
||||
updateList();
|
||||
|
||||
btcWalletService.addChangeEventListener(walletChangeEventListener);
|
||||
|
||||
|
@ -212,7 +250,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||
if (scene != null)
|
||||
scene.addEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler);
|
||||
|
||||
numItems.setText(Res.get("shared.numItemsLabel", sortedDisplayedTransactions.size()));
|
||||
numItems.setText(Res.get("shared.numItemsLabel", sortedList.size()));
|
||||
exportButton.setOnAction(event -> {
|
||||
final ObservableList<TableColumn<TransactionsListItem, ?>> tableColumns = tableView.getColumns();
|
||||
final int reportColumns = tableColumns.size() - 1; // CSV report excludes the last column (an icon)
|
||||
|
@ -235,14 +273,15 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||
};
|
||||
|
||||
GUIUtil.exportCSV("transactions.csv", headerConverter, contentConverter,
|
||||
new TransactionsListItem(), sortedDisplayedTransactions, (Stage) root.getScene().getWindow());
|
||||
new TransactionsListItem(), sortedList, (Stage) root.getScene().getWindow());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
sortedDisplayedTransactions.comparatorProperty().unbind();
|
||||
displayedTransactions.forEach(TransactionsListItem::cleanup);
|
||||
filterBox.deactivate();
|
||||
sortedList.comparatorProperty().unbind();
|
||||
observableList.forEach(TransactionsListItem::cleanup);
|
||||
btcWalletService.removeChangeEventListener(walletChangeEventListener);
|
||||
|
||||
if (scene != null)
|
||||
|
@ -251,6 +290,48 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||
exportButton.setOnAction(null);
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
List<TransactionsListItem> transactionsListItems = btcWalletService.getTransactions(false)
|
||||
.stream()
|
||||
.map(transaction -> {
|
||||
Set<Tradable> tradables = tradableRepository.getAll();
|
||||
|
||||
TransactionAwareTradable maybeTradable = tradables.stream()
|
||||
.map(tradable -> {
|
||||
if (tradable instanceof OpenOffer) {
|
||||
return new TransactionAwareOpenOffer((OpenOffer) tradable);
|
||||
} else if (tradable instanceof TradeModel) {
|
||||
return new TransactionAwareTrade(
|
||||
(TradeModel) tradable,
|
||||
arbitrationManager,
|
||||
refundManager,
|
||||
btcWalletService,
|
||||
pubKeyRing
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(tradable -> tradable != null && tradable.isRelatedToTransaction(transaction))
|
||||
.findAny()
|
||||
.orElse(null);
|
||||
|
||||
return new TransactionsListItem(
|
||||
transaction,
|
||||
btcWalletService,
|
||||
bsqWalletService,
|
||||
maybeTradable,
|
||||
daoFacade,
|
||||
formatter,
|
||||
preferences.getIgnoreDustThreshold()
|
||||
);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
// are sorted by getRecentTransactions
|
||||
transactionsListItems.forEach(TransactionsListItem::cleanup);
|
||||
observableList.setAll(transactionsListItems);
|
||||
}
|
||||
|
||||
private void openTxInBlockExplorer(TransactionsListItem item) {
|
||||
if (item.getTxId() != null)
|
||||
GUIUtil.openWebPage(preferences.getBlockChainExplorer().txUrl + item.getTxId(), false);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package bisq.desktop.main.funds.withdrawal;
|
||||
|
||||
import bisq.desktop.util.filtering.FilterableListItem;
|
||||
import bisq.desktop.components.AutoTooltipLabel;
|
||||
|
||||
import bisq.core.btc.listeners.BalanceListener;
|
||||
|
@ -29,12 +30,14 @@ import org.bitcoinj.core.Address;
|
|||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import javafx.scene.control.Label;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
class WithdrawalListItem {
|
||||
class WithdrawalListItem implements FilterableListItem {
|
||||
private final BalanceListener balanceListener;
|
||||
private final Label balanceLabel;
|
||||
private final AddressEntry addressEntry;
|
||||
|
@ -118,7 +121,23 @@ class WithdrawalListItem {
|
|||
return balance;
|
||||
}
|
||||
|
||||
public String getBalanceAsString() {
|
||||
return formatter.formatCoin(balance);
|
||||
}
|
||||
|
||||
public String getAddressString() {
|
||||
return addressString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean match(String filterString) {
|
||||
if (filterString.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getBalanceAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
return StringUtils.containsIgnoreCase(getAddressString(), filterString);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,12 +23,14 @@
|
|||
<?import javafx.scene.layout.GridPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import bisq.desktop.components.list.FilterBox?>
|
||||
<VBox fx:id="root" fx:controller="bisq.desktop.main.funds.withdrawal.WithdrawalView"
|
||||
spacing="10" xmlns:fx="http://javafx.com/fxml">
|
||||
<padding>
|
||||
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0"/>
|
||||
</padding>
|
||||
|
||||
<FilterBox fx:id="filterBox" />
|
||||
<TableView fx:id="tableView" VBox.vgrow="ALWAYS">
|
||||
<columns>
|
||||
<TableColumn fx:id="selectColumn" minWidth="60" maxWidth="60" sortable="false"/>
|
||||
|
|
|
@ -25,6 +25,7 @@ import bisq.desktop.components.ExternalHyperlink;
|
|||
import bisq.desktop.components.HyperlinkWithIcon;
|
||||
import bisq.desktop.components.InputTextField;
|
||||
import bisq.desktop.components.TitledGroupBg;
|
||||
import bisq.desktop.components.list.FilterBox;
|
||||
import bisq.desktop.main.overlays.popups.Popup;
|
||||
import bisq.desktop.main.overlays.windows.TxDetails;
|
||||
import bisq.desktop.main.overlays.windows.WalletPasswordWindow;
|
||||
|
@ -96,6 +97,7 @@ import javafx.beans.value.ChangeListener;
|
|||
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.collections.transformation.FilteredList;
|
||||
import javafx.collections.transformation.SortedList;
|
||||
|
||||
import javafx.util.Callback;
|
||||
|
@ -117,10 +119,11 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||
|
||||
@FxmlView
|
||||
public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||
|
||||
@FXML
|
||||
GridPane gridPane;
|
||||
@FXML
|
||||
FilterBox filterBox;
|
||||
@FXML
|
||||
TableView<WithdrawalListItem> tableView;
|
||||
@FXML
|
||||
TableColumn<WithdrawalListItem, WithdrawalListItem> addressColumn, balanceColumn, selectColumn;
|
||||
|
@ -138,7 +141,8 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
|||
private final BtcAddressValidator btcAddressValidator;
|
||||
private final WalletPasswordWindow walletPasswordWindow;
|
||||
private final ObservableList<WithdrawalListItem> observableList = FXCollections.observableArrayList();
|
||||
private final SortedList<WithdrawalListItem> sortedList = new SortedList<>(observableList);
|
||||
private final FilteredList<WithdrawalListItem> filteredList = new FilteredList<>(observableList);
|
||||
private final SortedList<WithdrawalListItem> sortedList = new SortedList<>(filteredList);
|
||||
private final Set<WithdrawalListItem> selectedItems = new HashSet<>();
|
||||
private BalanceListener balanceListener;
|
||||
private Set<String> fromAddresses = new HashSet<>();
|
||||
|
@ -183,7 +187,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
|||
|
||||
@Override
|
||||
public void initialize() {
|
||||
|
||||
filterBox.initialize(filteredList, tableView);
|
||||
final TitledGroupBg titledGroupBg = addTitledGroupBg(gridPane, rowIndex, 4, Res.get("funds.deposit.withdrawFromWallet"));
|
||||
titledGroupBg.getStyleClass().add("last");
|
||||
|
||||
|
@ -343,6 +347,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
|||
|
||||
@Override
|
||||
protected void activate() {
|
||||
filterBox.activate();
|
||||
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
||||
tableView.setItems(sortedList);
|
||||
updateList();
|
||||
|
@ -374,6 +379,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
|||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
filterBox.deactivate();
|
||||
sortedList.comparatorProperty().unbind();
|
||||
observableList.forEach(WithdrawalListItem::cleanup);
|
||||
btcWalletService.removeBalanceListener(balanceListener);
|
||||
|
|
|
@ -21,13 +21,17 @@ import bisq.desktop.common.model.ActivatableDataModel;
|
|||
|
||||
import bisq.core.btc.listeners.BsqBalanceListener;
|
||||
import bisq.core.btc.wallet.BsqWalletService;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OfferDirection;
|
||||
import bisq.core.trade.ClosedTradableManager;
|
||||
import bisq.core.trade.bsq_swap.BsqSwapTradeManager;
|
||||
import bisq.core.trade.model.bsq_swap.BsqSwapTrade;
|
||||
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 javafx.collections.FXCollections;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
|
@ -36,17 +40,26 @@ import java.util.stream.Collectors;
|
|||
|
||||
class UnconfirmedBsqSwapsDataModel extends ActivatableDataModel {
|
||||
|
||||
final BsqSwapTradeManager bsqSwapTradeManager;
|
||||
private final BsqSwapTradeManager bsqSwapTradeManager;
|
||||
private final BsqWalletService bsqWalletService;
|
||||
private final ObservableList<UnconfirmedBsqSwapsListItem> list = FXCollections.observableArrayList();
|
||||
private final ListChangeListener<BsqSwapTrade> tradesListChangeListener;
|
||||
private final BsqBalanceListener bsqBalanceListener;
|
||||
private final BsqFormatter bsqFormatter;
|
||||
private final CoinFormatter btcFormatter;
|
||||
private final ClosedTradableManager closedTradableManager;
|
||||
|
||||
@Inject
|
||||
public UnconfirmedBsqSwapsDataModel(BsqSwapTradeManager bsqSwapTradeManager,
|
||||
BsqWalletService bsqWalletService) {
|
||||
BsqWalletService bsqWalletService,
|
||||
BsqFormatter bsqFormatter,
|
||||
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter,
|
||||
ClosedTradableManager closedTradableManager) {
|
||||
this.bsqSwapTradeManager = bsqSwapTradeManager;
|
||||
this.bsqWalletService = bsqWalletService;
|
||||
this.bsqFormatter = bsqFormatter;
|
||||
this.btcFormatter = btcFormatter;
|
||||
this.closedTradableManager = closedTradableManager;
|
||||
|
||||
tradesListChangeListener = change -> applyList();
|
||||
bsqBalanceListener = (availableBalance, availableNonBsqBalance, unverifiedBalance,
|
||||
|
@ -71,15 +84,18 @@ class UnconfirmedBsqSwapsDataModel extends ActivatableDataModel {
|
|||
return list;
|
||||
}
|
||||
|
||||
public OfferDirection getDirection(Offer offer) {
|
||||
return bsqSwapTradeManager.wasMyOffer(offer) ? offer.getDirection() : offer.getMirroredDirection();
|
||||
}
|
||||
|
||||
private void applyList() {
|
||||
list.clear();
|
||||
|
||||
list.addAll(bsqSwapTradeManager.getUnconfirmedBsqSwapTrades()
|
||||
.map(bsqSwapTrade -> new UnconfirmedBsqSwapsListItem(bsqWalletService, bsqSwapTrade))
|
||||
.map(bsqSwapTrade -> new UnconfirmedBsqSwapsListItem(
|
||||
bsqSwapTrade,
|
||||
bsqWalletService,
|
||||
btcFormatter,
|
||||
bsqFormatter,
|
||||
bsqSwapTradeManager,
|
||||
closedTradableManager
|
||||
))
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
// we sort by date, the earliest first
|
||||
|
|
|
@ -18,34 +18,63 @@
|
|||
package bisq.desktop.main.portfolio.bsqswaps;
|
||||
|
||||
import bisq.desktop.components.indicator.TxConfidenceIndicator;
|
||||
import bisq.desktop.util.DisplayUtils;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
import bisq.desktop.util.filtering.FilterableListItem;
|
||||
import bisq.desktop.util.filtering.FilteringUtils;
|
||||
|
||||
import bisq.core.btc.listeners.TxConfidenceListener;
|
||||
import bisq.core.btc.wallet.BsqWalletService;
|
||||
import bisq.core.locale.CurrencyUtil;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OfferDirection;
|
||||
import bisq.core.trade.ClosedTradableManager;
|
||||
import bisq.core.trade.bsq_swap.BsqSwapTradeManager;
|
||||
import bisq.core.trade.model.bsq_swap.BsqSwapTrade;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.VolumeUtil;
|
||||
import bisq.core.util.coin.BsqFormatter;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.TransactionConfidence;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import javafx.scene.control.Tooltip;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
class UnconfirmedBsqSwapsListItem {
|
||||
class UnconfirmedBsqSwapsListItem implements FilterableListItem {
|
||||
@Getter
|
||||
private final BsqSwapTrade bsqSwapTrade;
|
||||
private final BsqWalletService bsqWalletService;
|
||||
private final CoinFormatter btcFormatter;
|
||||
private final BsqFormatter bsqFormatter;
|
||||
private final BsqSwapTradeManager bsqSwapTradeManager;
|
||||
private final ClosedTradableManager closedTradableManager;
|
||||
private final String txId;
|
||||
@Getter
|
||||
private int confirmations = 0;
|
||||
@Getter
|
||||
private TxConfidenceIndicator txConfidenceIndicator;
|
||||
private TxConfidenceListener txConfidenceListener;
|
||||
private final TxConfidenceIndicator txConfidenceIndicator;
|
||||
private final TxConfidenceListener txConfidenceListener;
|
||||
|
||||
UnconfirmedBsqSwapsListItem(BsqWalletService bsqWalletService, BsqSwapTrade bsqSwapTrade) {
|
||||
UnconfirmedBsqSwapsListItem(
|
||||
BsqSwapTrade bsqSwapTrade,
|
||||
BsqWalletService bsqWalletService,
|
||||
CoinFormatter btcFormatter,
|
||||
BsqFormatter bsqFormatter,
|
||||
BsqSwapTradeManager bsqSwapTradeManager,
|
||||
ClosedTradableManager closedTradableManager) {
|
||||
this.bsqSwapTrade = bsqSwapTrade;
|
||||
this.bsqWalletService = bsqWalletService;
|
||||
this.btcFormatter = btcFormatter;
|
||||
this.bsqFormatter = bsqFormatter;
|
||||
this.bsqSwapTradeManager = bsqSwapTradeManager;
|
||||
this.closedTradableManager = closedTradableManager;
|
||||
|
||||
txId = bsqSwapTrade.getTxId();
|
||||
txConfidenceIndicator = new TxConfidenceIndicator();
|
||||
|
@ -65,13 +94,6 @@ class UnconfirmedBsqSwapsListItem {
|
|||
updateConfidence(bsqWalletService.getConfidenceForTxId(txId), tooltip);
|
||||
}
|
||||
|
||||
UnconfirmedBsqSwapsListItem() {
|
||||
bsqSwapTrade = null;
|
||||
bsqWalletService = null;
|
||||
txId = null;
|
||||
|
||||
}
|
||||
|
||||
private void updateConfidence(@Nullable TransactionConfidence confidence, Tooltip tooltip) {
|
||||
if (confidence != null) {
|
||||
GUIUtil.updateConfidence(confidence, tooltip, txConfidenceIndicator);
|
||||
|
@ -83,4 +105,91 @@ class UnconfirmedBsqSwapsListItem {
|
|||
bsqWalletService.removeTxConfidenceListener(txConfidenceListener);
|
||||
}
|
||||
|
||||
public String getTradeId() {
|
||||
return bsqSwapTrade.getShortId();
|
||||
}
|
||||
|
||||
public String getAmountAsString() {
|
||||
return btcFormatter.formatCoin(bsqSwapTrade.getAmount());
|
||||
}
|
||||
|
||||
public String getPriceAsString() {
|
||||
return FormattingUtils.formatPrice(bsqSwapTrade.getPrice());
|
||||
}
|
||||
|
||||
public String getVolumeAsString() {
|
||||
return VolumeUtil.formatVolumeWithCode(bsqSwapTrade.getVolume());
|
||||
}
|
||||
|
||||
public String getTxFeeAsString() {
|
||||
return btcFormatter.formatCoinWithCode(Coin.valueOf(bsqSwapTrade.getBsqSwapProtocolModel().getTxFee()));
|
||||
}
|
||||
|
||||
public String getTradeFeeAsString() {
|
||||
if (bsqSwapTradeManager.wasMyOffer(bsqSwapTrade.getOffer())) {
|
||||
return bsqFormatter.formatCoinWithCode(bsqSwapTrade.getMakerFeeAsLong());
|
||||
} else {
|
||||
return bsqFormatter.formatCoinWithCode(bsqSwapTrade.getTakerFeeAsLong());
|
||||
}
|
||||
}
|
||||
|
||||
public String getDirectionLabel() {
|
||||
Offer offer = bsqSwapTrade.getOffer();
|
||||
OfferDirection direction = bsqSwapTradeManager.wasMyOffer(offer) ? offer.getDirection() : offer.getMirroredDirection();
|
||||
return DisplayUtils.getDirectionWithCode(direction, bsqSwapTrade.getOffer().getCurrencyCode());
|
||||
}
|
||||
|
||||
public String getDateAsString() {
|
||||
return DisplayUtils.formatDateTime(bsqSwapTrade.getDate());
|
||||
}
|
||||
|
||||
public String getMarketLabel() {
|
||||
return CurrencyUtil.getCurrencyPair(bsqSwapTrade.getOffer().getCurrencyCode());
|
||||
}
|
||||
|
||||
public int getConfidence() {
|
||||
return getConfirmations();
|
||||
}
|
||||
|
||||
public int getNumPastTrades() {
|
||||
return closedTradableManager.getNumPastTrades(bsqSwapTrade);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean match(String filterString) {
|
||||
if (filterString.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getDateAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getMarketLabel(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getPriceAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getVolumeAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getAmountAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getTradeFeeAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getTxFeeAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(String.valueOf(getConfidence()), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getDirectionLabel(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (FilteringUtils.match(getBsqSwapTrade(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
return FilteringUtils.match(getBsqSwapTrade().getOffer(), filterString);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,28 +18,21 @@
|
|||
-->
|
||||
|
||||
<?import bisq.desktop.components.AutoTooltipButton?>
|
||||
<?import bisq.desktop.components.AutoTooltipLabel?>
|
||||
<?import bisq.desktop.components.InputTextField?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.TableColumn?>
|
||||
<?import javafx.scene.control.TableView?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Pane?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import bisq.desktop.components.list.FilterBox?>
|
||||
<VBox fx:id="root" fx:controller="bisq.desktop.main.portfolio.bsqswaps.UnconfirmedBsqSwapsView"
|
||||
spacing="10" alignment="CENTER_RIGHT" xmlns:fx="http://javafx.com/fxml">
|
||||
<padding>
|
||||
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0"/>
|
||||
</padding>
|
||||
|
||||
<HBox fx:id="searchBox">
|
||||
<AutoTooltipLabel fx:id="filterLabel"/>
|
||||
<InputTextField fx:id="filterTextField" minWidth="500"/>
|
||||
<Pane fx:id="searchBoxSpacer"/>
|
||||
</HBox>
|
||||
|
||||
<FilterBox fx:id="filterBox" />
|
||||
<TableView fx:id="tableView" VBox.vgrow="ALWAYS">
|
||||
<columns>
|
||||
<TableColumn fx:id="tradeIdColumn" minWidth="110" maxWidth="120"/>
|
||||
|
|
|
@ -22,14 +22,14 @@ import bisq.desktop.common.view.FxmlView;
|
|||
import bisq.desktop.components.AutoTooltipButton;
|
||||
import bisq.desktop.components.AutoTooltipLabel;
|
||||
import bisq.desktop.components.HyperlinkWithIcon;
|
||||
import bisq.desktop.components.InputTextField;
|
||||
import bisq.desktop.components.PeerInfoIconTrading;
|
||||
import bisq.desktop.components.list.FilterBox;
|
||||
import bisq.desktop.main.overlays.windows.BsqTradeDetailsWindow;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
|
||||
import bisq.core.account.witness.AccountAgeWitnessService;
|
||||
import bisq.core.alert.PrivateNotificationManager;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.trade.model.bsq_swap.BsqSwapTrade;
|
||||
import bisq.core.user.Preferences;
|
||||
|
||||
|
@ -53,7 +53,6 @@ import javafx.scene.control.TableColumn;
|
|||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
@ -115,13 +114,7 @@ public class UnconfirmedBsqSwapsView extends ActivatableViewAndModel<VBox, Uncon
|
|||
confidenceColumn,
|
||||
avatarColumn;
|
||||
@FXML
|
||||
HBox searchBox;
|
||||
@FXML
|
||||
AutoTooltipLabel filterLabel;
|
||||
@FXML
|
||||
InputTextField filterTextField;
|
||||
@FXML
|
||||
Pane searchBoxSpacer;
|
||||
FilterBox filterBox;
|
||||
@FXML
|
||||
AutoTooltipButton exportButton;
|
||||
@FXML
|
||||
|
@ -132,9 +125,9 @@ public class UnconfirmedBsqSwapsView extends ActivatableViewAndModel<VBox, Uncon
|
|||
private final BsqTradeDetailsWindow window;
|
||||
private final Preferences preferences;
|
||||
private final PrivateNotificationManager privateNotificationManager;
|
||||
private final AccountAgeWitnessService accountAgeWitnessService;
|
||||
private SortedList<UnconfirmedBsqSwapsListItem> sortedList;
|
||||
private FilteredList<UnconfirmedBsqSwapsListItem> filteredList;
|
||||
private ChangeListener<String> filterTextFieldListener;
|
||||
private ChangeListener<Number> widthListener;
|
||||
|
||||
@Inject
|
||||
|
@ -142,11 +135,13 @@ public class UnconfirmedBsqSwapsView extends ActivatableViewAndModel<VBox, Uncon
|
|||
BsqTradeDetailsWindow bsqTradeDetailsWindow,
|
||||
Preferences preferences,
|
||||
PrivateNotificationManager privateNotificationManager,
|
||||
AccountAgeWitnessService accountAgeWitnessService,
|
||||
@Named(Config.USE_DEV_PRIVILEGE_KEYS) boolean useDevPrivilegeKeys) {
|
||||
super(model);
|
||||
this.window = bsqTradeDetailsWindow;
|
||||
this.preferences = preferences;
|
||||
this.privateNotificationManager = privateNotificationManager;
|
||||
this.accountAgeWitnessService = accountAgeWitnessService;
|
||||
this.useDevPrivilegeKeys = useDevPrivilegeKeys;
|
||||
}
|
||||
|
||||
|
@ -183,20 +178,17 @@ public class UnconfirmedBsqSwapsView extends ActivatableViewAndModel<VBox, Uncon
|
|||
tradeIdColumn.setComparator(Comparator.comparing(o -> o.getBsqSwapTrade().getId()));
|
||||
dateColumn.setComparator(Comparator.comparing(o -> o.getBsqSwapTrade().getDate()));
|
||||
directionColumn.setComparator(Comparator.comparing(o -> o.getBsqSwapTrade().getOffer().getDirection()));
|
||||
marketColumn.setComparator(Comparator.comparing(model::getMarketLabel));
|
||||
priceColumn.setComparator(Comparator.comparing(model::getPrice, Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
marketColumn.setComparator(Comparator.comparing(UnconfirmedBsqSwapsListItem::getMarketLabel));
|
||||
priceColumn.setComparator(Comparator.comparing(UnconfirmedBsqSwapsListItem::getPriceAsString, Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
volumeColumn.setComparator(nullsFirstComparingAsTrade(BsqSwapTrade::getVolume));
|
||||
amountColumn.setComparator(Comparator.comparing(model::getAmount, Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
avatarColumn.setComparator(Comparator.comparing(
|
||||
o -> model.getNumPastTrades(o.getBsqSwapTrade()),
|
||||
Comparator.nullsFirst(Comparator.naturalOrder())
|
||||
));
|
||||
amountColumn.setComparator(Comparator.comparing(UnconfirmedBsqSwapsListItem::getAmountAsString, Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
avatarColumn.setComparator(Comparator.comparing(UnconfirmedBsqSwapsListItem::getNumPastTrades, Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
txFeeColumn.setComparator(nullsFirstComparing(BsqSwapTrade::getTxFeePerVbyte));
|
||||
txFeeColumn.setComparator(Comparator.comparing(model::getTxFee, Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
txFeeColumn.setComparator(Comparator.comparing(UnconfirmedBsqSwapsListItem::getTxFeeAsString, Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
|
||||
//
|
||||
tradeFeeColumn.setComparator(Comparator.comparing(item -> {
|
||||
String tradeFee = model.getTradeFee(item);
|
||||
String tradeFee = item.getTradeFeeAsString();
|
||||
// We want to separate BSQ and BTC fees so we use a prefix
|
||||
if (item.getBsqSwapTrade().getOffer().isCurrencyForMakerFeeBtc()) {
|
||||
return "BTC" + tradeFee;
|
||||
|
@ -204,17 +196,11 @@ public class UnconfirmedBsqSwapsView extends ActivatableViewAndModel<VBox, Uncon
|
|||
return "BSQ" + tradeFee;
|
||||
}
|
||||
}, Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
confidenceColumn.setComparator(Comparator.comparing(model::getConfidence));
|
||||
confidenceColumn.setComparator(Comparator.comparing(UnconfirmedBsqSwapsListItem::getConfidence));
|
||||
|
||||
dateColumn.setSortType(TableColumn.SortType.DESCENDING);
|
||||
tableView.getSortOrder().add(dateColumn);
|
||||
|
||||
filterLabel.setText(Res.get("shared.filter"));
|
||||
HBox.setMargin(filterLabel, new Insets(5, 0, 0, 10));
|
||||
filterTextFieldListener = (observable, oldValue, newValue) -> applyFilteredListPredicate(filterTextField.getText());
|
||||
searchBox.setSpacing(5);
|
||||
HBox.setHgrow(searchBoxSpacer, Priority.ALWAYS);
|
||||
|
||||
numItems.setId("num-offers");
|
||||
numItems.setPadding(new Insets(-5, 0, 0, 10));
|
||||
HBox.setHgrow(footerSpacer, Priority.ALWAYS);
|
||||
|
@ -224,13 +210,16 @@ public class UnconfirmedBsqSwapsView extends ActivatableViewAndModel<VBox, Uncon
|
|||
|
||||
@Override
|
||||
protected void activate() {
|
||||
filteredList = new FilteredList<>(model.getList());
|
||||
filteredList = new FilteredList<>(model.dataModel.getList());
|
||||
|
||||
sortedList = new SortedList<>(filteredList);
|
||||
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
||||
|
||||
tableView.setItems(sortedList);
|
||||
|
||||
filterBox.initialize(filteredList, tableView); // here because filteredList is instantiated here
|
||||
filterBox.activate();
|
||||
|
||||
numItems.setText(Res.get("shared.numItemsLabel", sortedList.size()));
|
||||
exportButton.setOnAction(event -> {
|
||||
CSVEntryConverter<UnconfirmedBsqSwapsListItem> headerConverter = item -> {
|
||||
|
@ -242,25 +231,23 @@ public class UnconfirmedBsqSwapsView extends ActivatableViewAndModel<VBox, Uncon
|
|||
};
|
||||
CSVEntryConverter<UnconfirmedBsqSwapsListItem> contentConverter = item -> {
|
||||
String[] columns = new String[ColumnNames.values().length];
|
||||
columns[ColumnNames.TRADE_ID.ordinal()] = model.getTradeId(item);
|
||||
columns[ColumnNames.DATE.ordinal()] = model.getDate(item);
|
||||
columns[ColumnNames.MARKET.ordinal()] = model.getMarketLabel(item);
|
||||
columns[ColumnNames.PRICE.ordinal()] = model.getPrice(item);
|
||||
columns[ColumnNames.AMOUNT.ordinal()] = model.getAmount(item);
|
||||
columns[ColumnNames.VOLUME.ordinal()] = model.getVolume(item);
|
||||
columns[ColumnNames.TX_FEE.ordinal()] = model.getTxFee(item);
|
||||
columns[ColumnNames.TRADE_FEE.ordinal()] = model.getTradeFee(item);
|
||||
columns[ColumnNames.OFFER_TYPE.ordinal()] = model.getDirectionLabel(item);
|
||||
columns[ColumnNames.CONF.ordinal()] = String.valueOf(model.getConfidence(item));
|
||||
columns[ColumnNames.TRADE_ID.ordinal()] = item.getTradeId();
|
||||
columns[ColumnNames.DATE.ordinal()] = item.getDateAsString();
|
||||
columns[ColumnNames.MARKET.ordinal()] = item.getMarketLabel();
|
||||
columns[ColumnNames.PRICE.ordinal()] = item.getPriceAsString();
|
||||
columns[ColumnNames.AMOUNT.ordinal()] = item.getAmountAsString();
|
||||
columns[ColumnNames.VOLUME.ordinal()] = item.getVolumeAsString();
|
||||
columns[ColumnNames.TX_FEE.ordinal()] = item.getTxFeeAsString();
|
||||
columns[ColumnNames.TRADE_FEE.ordinal()] = item.getTradeFeeAsString();
|
||||
columns[ColumnNames.OFFER_TYPE.ordinal()] = item.getDirectionLabel();
|
||||
columns[ColumnNames.CONF.ordinal()] = String.valueOf(item.getConfidence());
|
||||
return columns;
|
||||
};
|
||||
|
||||
GUIUtil.exportCSV("bsqSwapHistory.csv", headerConverter, contentConverter,
|
||||
new UnconfirmedBsqSwapsListItem(), sortedList, (Stage) root.getScene().getWindow());
|
||||
null, sortedList, (Stage) root.getScene().getWindow());
|
||||
});
|
||||
|
||||
filterTextField.textProperty().addListener(filterTextFieldListener);
|
||||
applyFilteredListPredicate(filterTextField.getText());
|
||||
root.widthProperty().addListener(widthListener);
|
||||
onWidthChange(root.getWidth());
|
||||
}
|
||||
|
@ -270,7 +257,7 @@ public class UnconfirmedBsqSwapsView extends ActivatableViewAndModel<VBox, Uncon
|
|||
sortedList.comparatorProperty().unbind();
|
||||
exportButton.setOnAction(null);
|
||||
|
||||
filterTextField.textProperty().removeListener(filterTextFieldListener);
|
||||
filterBox.deactivate();
|
||||
root.widthProperty().removeListener(widthListener);
|
||||
}
|
||||
|
||||
|
@ -295,57 +282,6 @@ public class UnconfirmedBsqSwapsView extends ActivatableViewAndModel<VBox, Uncon
|
|||
tradeFeeColumn.setVisible(width > 1300);
|
||||
}
|
||||
|
||||
private void applyFilteredListPredicate(String filterString) {
|
||||
filteredList.setPredicate(item -> {
|
||||
if (filterString.isEmpty())
|
||||
return true;
|
||||
|
||||
BsqSwapTrade bsqSwapTrade = item.getBsqSwapTrade();
|
||||
Offer offer = bsqSwapTrade.getOffer();
|
||||
if (offer.getId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getDate(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getMarketLabel(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getPrice(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getVolume(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getAmount(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getTradeFee(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getTxFee(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (String.valueOf(model.getConfidence(item)).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getDirectionLabel(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (offer.getPaymentMethod().getDisplayString().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (bsqSwapTrade.getTxId() != null && bsqSwapTrade.getTxId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (bsqSwapTrade.getTradingPeerNodeAddress().getFullAddress().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
private void setTradeIdColumnCellFactory() {
|
||||
tradeIdColumn.getStyleClass().add("first-column");
|
||||
tradeIdColumn.setCellValueFactory((offerListItem) -> new ReadOnlyObjectWrapper<>(offerListItem.getValue()));
|
||||
|
@ -362,7 +298,7 @@ public class UnconfirmedBsqSwapsView extends ActivatableViewAndModel<VBox, Uncon
|
|||
public void updateItem(final UnconfirmedBsqSwapsListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null && !empty) {
|
||||
field = new HyperlinkWithIcon(model.getTradeId(item));
|
||||
field = new HyperlinkWithIcon(item.getTradeId());
|
||||
field.setOnAction(event -> {
|
||||
window.show(item.getBsqSwapTrade());
|
||||
});
|
||||
|
@ -390,8 +326,8 @@ public class UnconfirmedBsqSwapsView extends ActivatableViewAndModel<VBox, Uncon
|
|||
@Override
|
||||
public void updateItem(final UnconfirmedBsqSwapsListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null)
|
||||
setGraphic(new AutoTooltipLabel(model.getDate(item)));
|
||||
if (item != null && !empty)
|
||||
setGraphic(new AutoTooltipLabel(item.getDateAsString()));
|
||||
else
|
||||
setGraphic(null);
|
||||
}
|
||||
|
@ -411,7 +347,11 @@ public class UnconfirmedBsqSwapsView extends ActivatableViewAndModel<VBox, Uncon
|
|||
@Override
|
||||
public void updateItem(final UnconfirmedBsqSwapsListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
setGraphic(new AutoTooltipLabel(model.getMarketLabel(item)));
|
||||
if (item != null && !empty) {
|
||||
setGraphic(new AutoTooltipLabel(item.getMarketLabel()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -457,7 +397,7 @@ public class UnconfirmedBsqSwapsView extends ActivatableViewAndModel<VBox, Uncon
|
|||
|
||||
if (newItem != null && !empty/* && newItem.getAtomicTrade() instanceof Trade*/) {
|
||||
var bsqSwapTrade = newItem.getBsqSwapTrade();
|
||||
int numPastTrades = model.getNumPastTrades(bsqSwapTrade);
|
||||
int numPastTrades = newItem.getNumPastTrades();
|
||||
final NodeAddress tradingPeerNodeAddress = bsqSwapTrade.getTradingPeerNodeAddress();
|
||||
String role = Res.get("peerInfoIcon.tooltip.tradePeer");
|
||||
Node peerInfoIcon = new PeerInfoIconTrading(tradingPeerNodeAddress,
|
||||
|
@ -466,7 +406,7 @@ public class UnconfirmedBsqSwapsView extends ActivatableViewAndModel<VBox, Uncon
|
|||
privateNotificationManager,
|
||||
bsqSwapTrade.getOffer(),
|
||||
preferences,
|
||||
model.accountAgeWitnessService,
|
||||
accountAgeWitnessService,
|
||||
useDevPrivilegeKeys);
|
||||
setPadding(new Insets(1, 15, 0, 0));
|
||||
setGraphic(peerInfoIcon);
|
||||
|
@ -491,7 +431,11 @@ public class UnconfirmedBsqSwapsView extends ActivatableViewAndModel<VBox, Uncon
|
|||
@Override
|
||||
public void updateItem(final UnconfirmedBsqSwapsListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
setGraphic(new AutoTooltipLabel(model.getAmount(item)));
|
||||
if (item != null && !empty) {
|
||||
setGraphic(new AutoTooltipLabel(item.getAmountAsString()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -509,7 +453,11 @@ public class UnconfirmedBsqSwapsView extends ActivatableViewAndModel<VBox, Uncon
|
|||
@Override
|
||||
public void updateItem(final UnconfirmedBsqSwapsListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
setGraphic(new AutoTooltipLabel(model.getPrice(item)));
|
||||
if (item != null && !empty) {
|
||||
setGraphic(new AutoTooltipLabel(item.getPriceAsString()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -527,8 +475,8 @@ public class UnconfirmedBsqSwapsView extends ActivatableViewAndModel<VBox, Uncon
|
|||
@Override
|
||||
public void updateItem(final UnconfirmedBsqSwapsListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null)
|
||||
setGraphic(new AutoTooltipLabel(model.getVolume(item)));
|
||||
if (item != null && !empty)
|
||||
setGraphic(new AutoTooltipLabel(item.getVolumeAsString()));
|
||||
else
|
||||
setGraphic(null);
|
||||
}
|
||||
|
@ -548,7 +496,10 @@ public class UnconfirmedBsqSwapsView extends ActivatableViewAndModel<VBox, Uncon
|
|||
@Override
|
||||
public void updateItem(final UnconfirmedBsqSwapsListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
setGraphic(new AutoTooltipLabel(model.getDirectionLabel(item)));
|
||||
if (item != null && !empty)
|
||||
setGraphic(new AutoTooltipLabel(item.getDirectionLabel()));
|
||||
else
|
||||
setGraphic(null);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -566,7 +517,10 @@ public class UnconfirmedBsqSwapsView extends ActivatableViewAndModel<VBox, Uncon
|
|||
@Override
|
||||
public void updateItem(final UnconfirmedBsqSwapsListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
setGraphic(new AutoTooltipLabel(model.getTxFee(item)));
|
||||
if (item != null && !empty)
|
||||
setGraphic(new AutoTooltipLabel(item.getTxFeeAsString()));
|
||||
else
|
||||
setGraphic(null);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -584,7 +538,10 @@ public class UnconfirmedBsqSwapsView extends ActivatableViewAndModel<VBox, Uncon
|
|||
@Override
|
||||
public void updateItem(final UnconfirmedBsqSwapsListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
setGraphic(new AutoTooltipLabel(model.getTradeFee(item)));
|
||||
if (item != null && !empty)
|
||||
setGraphic(new AutoTooltipLabel(item.getTradeFeeAsString()));
|
||||
else
|
||||
setGraphic(null);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -19,121 +19,12 @@ package bisq.desktop.main.portfolio.bsqswaps;
|
|||
|
||||
import bisq.desktop.common.model.ActivatableWithDataModel;
|
||||
import bisq.desktop.common.model.ViewModel;
|
||||
import bisq.desktop.util.DisplayUtils;
|
||||
|
||||
import bisq.core.account.witness.AccountAgeWitnessService;
|
||||
import bisq.core.locale.CurrencyUtil;
|
||||
import bisq.core.trade.ClosedTradableManager;
|
||||
import bisq.core.trade.model.bsq_swap.BsqSwapTrade;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.VolumeUtil;
|
||||
import bisq.core.util.coin.BsqFormatter;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
class UnconfirmedBsqSwapsViewModel extends ActivatableWithDataModel<UnconfirmedBsqSwapsDataModel> implements ViewModel {
|
||||
private final BsqFormatter bsqFormatter;
|
||||
private final CoinFormatter btcFormatter;
|
||||
final AccountAgeWitnessService accountAgeWitnessService;
|
||||
private final ClosedTradableManager closedTradableManager;
|
||||
|
||||
@Inject
|
||||
public UnconfirmedBsqSwapsViewModel(UnconfirmedBsqSwapsDataModel dataModel,
|
||||
AccountAgeWitnessService accountAgeWitnessService,
|
||||
ClosedTradableManager closedTradableManager,
|
||||
BsqFormatter bsqFormatter,
|
||||
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter) {
|
||||
public UnconfirmedBsqSwapsViewModel(UnconfirmedBsqSwapsDataModel dataModel) {
|
||||
super(dataModel);
|
||||
this.accountAgeWitnessService = accountAgeWitnessService;
|
||||
this.closedTradableManager = closedTradableManager;
|
||||
this.bsqFormatter = bsqFormatter;
|
||||
this.btcFormatter = btcFormatter;
|
||||
}
|
||||
|
||||
public ObservableList<UnconfirmedBsqSwapsListItem> getList() {
|
||||
return dataModel.getList();
|
||||
}
|
||||
|
||||
String getTradeId(UnconfirmedBsqSwapsListItem item) {
|
||||
return item.getBsqSwapTrade().getShortId();
|
||||
}
|
||||
|
||||
String getAmount(UnconfirmedBsqSwapsListItem item) {
|
||||
if (item == null)
|
||||
return "";
|
||||
|
||||
return btcFormatter.formatCoin(item.getBsqSwapTrade().getAmount());
|
||||
}
|
||||
|
||||
String getPrice(UnconfirmedBsqSwapsListItem item) {
|
||||
if (item == null)
|
||||
return "";
|
||||
|
||||
return FormattingUtils.formatPrice(item.getBsqSwapTrade().getPrice());
|
||||
}
|
||||
|
||||
String getVolume(UnconfirmedBsqSwapsListItem item) {
|
||||
if (item == null)
|
||||
return "";
|
||||
|
||||
return VolumeUtil.formatVolumeWithCode(item.getBsqSwapTrade().getVolume());
|
||||
}
|
||||
|
||||
String getTxFee(UnconfirmedBsqSwapsListItem item) {
|
||||
if (item == null)
|
||||
return "";
|
||||
|
||||
return btcFormatter.formatCoinWithCode(Coin.valueOf(item.getBsqSwapTrade().getBsqSwapProtocolModel().getTxFee()));
|
||||
}
|
||||
|
||||
String getTradeFee(UnconfirmedBsqSwapsListItem item) {
|
||||
if (item == null)
|
||||
return "";
|
||||
|
||||
if (wasMyOffer(item.getBsqSwapTrade())) {
|
||||
return bsqFormatter.formatCoinWithCode(item.getBsqSwapTrade().getMakerFeeAsLong());
|
||||
} else {
|
||||
return bsqFormatter.formatCoinWithCode(item.getBsqSwapTrade().getTakerFeeAsLong());
|
||||
}
|
||||
}
|
||||
|
||||
String getDirectionLabel(UnconfirmedBsqSwapsListItem item) {
|
||||
if (item == null)
|
||||
return "";
|
||||
|
||||
return DisplayUtils.getDirectionWithCode(dataModel.getDirection(item.getBsqSwapTrade().getOffer()),
|
||||
item.getBsqSwapTrade().getOffer().getCurrencyCode());
|
||||
}
|
||||
|
||||
String getDate(UnconfirmedBsqSwapsListItem item) {
|
||||
return DisplayUtils.formatDateTime(item.getBsqSwapTrade().getDate());
|
||||
}
|
||||
|
||||
String getMarketLabel(UnconfirmedBsqSwapsListItem item) {
|
||||
if (item == null)
|
||||
return "";
|
||||
|
||||
return CurrencyUtil.getCurrencyPair(item.getBsqSwapTrade().getOffer().getCurrencyCode());
|
||||
}
|
||||
|
||||
int getConfidence(UnconfirmedBsqSwapsListItem item) {
|
||||
if ((item == null))
|
||||
return 0;
|
||||
return item.getConfirmations();
|
||||
}
|
||||
|
||||
int getNumPastTrades(BsqSwapTrade bsqSwapTrade) {
|
||||
return closedTradableManager.getNumPastTrades(bsqSwapTrade);
|
||||
}
|
||||
|
||||
boolean wasMyOffer(BsqSwapTrade bsqSwapTrade) {
|
||||
return dataModel.bsqSwapTradeManager.wasMyOffer(bsqSwapTrade.getOffer());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,10 +24,9 @@ import bisq.core.btc.listeners.BsqBalanceListener;
|
|||
import bisq.core.btc.wallet.BsqWalletService;
|
||||
import bisq.core.monetary.Price;
|
||||
import bisq.core.monetary.Volume;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OfferDirection;
|
||||
import bisq.core.provider.price.MarketPrice;
|
||||
import bisq.core.provider.price.PriceFeedService;
|
||||
import bisq.core.trade.ClosedTradableFormatter;
|
||||
import bisq.core.trade.ClosedTradableManager;
|
||||
import bisq.core.trade.ClosedTradableUtil;
|
||||
import bisq.core.trade.bsq_swap.BsqSwapTradeManager;
|
||||
|
@ -44,30 +43,33 @@ import javafx.collections.FXCollections;
|
|||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class ClosedTradesDataModel extends ActivatableDataModel {
|
||||
|
||||
final ClosedTradableManager closedTradableManager;
|
||||
final ClosedTradableFormatter closedTradableFormatter;
|
||||
private final BsqWalletService bsqWalletService;
|
||||
private final BsqSwapTradeManager bsqSwapTradeManager;
|
||||
private final Preferences preferences;
|
||||
private final PriceFeedService priceFeedService;
|
||||
final AccountAgeWitnessService accountAgeWitnessService;
|
||||
private final ObservableList<Tradable> list = FXCollections.observableArrayList();
|
||||
private final ObservableList<ClosedTradesListItem> list = FXCollections.observableArrayList();
|
||||
private final ListChangeListener<Tradable> tradesListChangeListener;
|
||||
private final BsqBalanceListener bsqBalanceListener;
|
||||
|
||||
@Inject
|
||||
public ClosedTradesDataModel(ClosedTradableManager closedTradableManager,
|
||||
ClosedTradableFormatter closedTradableFormatter,
|
||||
BsqSwapTradeManager bsqSwapTradeManager,
|
||||
BsqWalletService bsqWalletService,
|
||||
Preferences preferences,
|
||||
PriceFeedService priceFeedService,
|
||||
AccountAgeWitnessService accountAgeWitnessService) {
|
||||
this.closedTradableManager = closedTradableManager;
|
||||
this.closedTradableFormatter = closedTradableFormatter;
|
||||
this.bsqSwapTradeManager = bsqSwapTradeManager;
|
||||
this.bsqWalletService = bsqWalletService;
|
||||
this.preferences = preferences;
|
||||
|
@ -95,16 +97,16 @@ class ClosedTradesDataModel extends ActivatableDataModel {
|
|||
bsqWalletService.removeBsqBalanceListener(bsqBalanceListener);
|
||||
}
|
||||
|
||||
ObservableList<Tradable> getList() {
|
||||
ObservableList<ClosedTradesListItem> getList() {
|
||||
return list;
|
||||
}
|
||||
|
||||
OfferDirection getDirection(Offer offer) {
|
||||
return closedTradableManager.wasMyOffer(offer) ? offer.getDirection() : offer.getMirroredDirection();
|
||||
List<Tradable> getListAsTradables() {
|
||||
return list.stream().map(ClosedTradesListItem::getTradable).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
Coin getTotalAmount() {
|
||||
return ClosedTradableUtil.getTotalAmount(list);
|
||||
return ClosedTradableUtil.getTotalAmount(getListAsTradables());
|
||||
}
|
||||
|
||||
Optional<Volume> getVolumeInUserFiatCurrency(Coin amount) {
|
||||
|
@ -126,15 +128,11 @@ class ClosedTradesDataModel extends ActivatableDataModel {
|
|||
}
|
||||
|
||||
Coin getTotalTxFee() {
|
||||
return ClosedTradableUtil.getTotalTxFee(list);
|
||||
return ClosedTradableUtil.getTotalTxFee(getListAsTradables());
|
||||
}
|
||||
|
||||
Coin getTotalTradeFee(boolean expectBtcFee) {
|
||||
return closedTradableManager.getTotalTradeFee(list, expectBtcFee);
|
||||
}
|
||||
|
||||
int getNumPastTrades(Tradable tradable) {
|
||||
return closedTradableManager.getNumPastTrades(tradable);
|
||||
return closedTradableManager.getTotalTradeFee(getListAsTradables(), expectBtcFee);
|
||||
}
|
||||
|
||||
boolean isCurrencyForTradeFeeBtc(Tradable item) {
|
||||
|
@ -143,13 +141,17 @@ class ClosedTradesDataModel extends ActivatableDataModel {
|
|||
|
||||
private void applyList() {
|
||||
list.clear();
|
||||
list.addAll(getTradableStream().collect(Collectors.toList()));
|
||||
list.addAll(
|
||||
bsqSwapTradeManager.getConfirmedBsqSwapTrades()
|
||||
.map(tradable -> new ClosedTradesListItem(tradable, closedTradableFormatter, closedTradableManager))
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
list.addAll(
|
||||
closedTradableManager.getObservableList().stream()
|
||||
.map(tradable -> new ClosedTradesListItem(tradable, closedTradableFormatter, closedTradableManager))
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
// We sort by date, the earliest first
|
||||
list.sort((o1, o2) -> o2.getDate().compareTo(o1.getDate()));
|
||||
}
|
||||
|
||||
private Stream<Tradable> getTradableStream() {
|
||||
return Stream.concat(bsqSwapTradeManager.getConfirmedBsqSwapTrades(),
|
||||
closedTradableManager.getObservableList().stream());
|
||||
list.sort((o1, o2) -> o2.getTradable().getDate().compareTo(o1.getTradable().getDate()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* 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.closedtrades;
|
||||
|
||||
import bisq.desktop.util.DisplayUtils;
|
||||
import bisq.desktop.util.filtering.FilterableListItem;
|
||||
import bisq.desktop.util.filtering.FilteringUtils;
|
||||
|
||||
import bisq.core.locale.CurrencyUtil;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OfferDirection;
|
||||
import bisq.core.trade.ClosedTradableFormatter;
|
||||
import bisq.core.trade.ClosedTradableManager;
|
||||
import bisq.core.trade.model.Tradable;
|
||||
import bisq.core.trade.model.bisq_v1.Trade;
|
||||
import bisq.core.trade.model.bsq_swap.BsqSwapTrade;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
public class ClosedTradesListItem implements FilterableListItem {
|
||||
@Getter
|
||||
private final Tradable tradable;
|
||||
private final ClosedTradableFormatter closedTradableFormatter;
|
||||
private final ClosedTradableManager closedTradableManager;
|
||||
|
||||
public ClosedTradesListItem(
|
||||
Tradable tradable,
|
||||
ClosedTradableFormatter closedTradableFormatter,
|
||||
ClosedTradableManager closedTradableManager) {
|
||||
|
||||
this.tradable = tradable;
|
||||
this.closedTradableFormatter = closedTradableFormatter;
|
||||
this.closedTradableManager = closedTradableManager;
|
||||
}
|
||||
|
||||
public String getTradeId() {
|
||||
return tradable.getShortId();
|
||||
}
|
||||
|
||||
public String getAmountAsString() {
|
||||
return closedTradableFormatter.getAmountAsString(tradable);
|
||||
}
|
||||
|
||||
public String getPriceAsString() {
|
||||
return closedTradableFormatter.getPriceAsString(tradable);
|
||||
}
|
||||
|
||||
public String getPriceDeviationAsString() {
|
||||
return closedTradableFormatter.getPriceDeviationAsString(tradable);
|
||||
}
|
||||
|
||||
public String getVolumeAsString(boolean appendCode) {
|
||||
return closedTradableFormatter.getVolumeAsString(tradable, appendCode);
|
||||
}
|
||||
|
||||
public String getVolumeCurrencyAsString() {
|
||||
return closedTradableFormatter.getVolumeCurrencyAsString(tradable);
|
||||
}
|
||||
|
||||
public String getTxFeeAsString() {
|
||||
return closedTradableFormatter.getTxFeeAsString(tradable);
|
||||
}
|
||||
|
||||
public String getTradeFeeAsString(boolean appendCode) {
|
||||
return closedTradableFormatter.getTradeFeeAsString(tradable, appendCode);
|
||||
}
|
||||
|
||||
public String getBuyerSecurityDepositAsString() {
|
||||
return closedTradableFormatter.getBuyerSecurityDepositAsString(tradable);
|
||||
}
|
||||
|
||||
public String getSellerSecurityDepositAsString() {
|
||||
return closedTradableFormatter.getSellerSecurityDepositAsString(tradable);
|
||||
}
|
||||
|
||||
public String getDirectionLabel() {
|
||||
Offer offer = tradable.getOffer();
|
||||
OfferDirection direction = closedTradableManager.wasMyOffer(offer)
|
||||
? offer.getDirection()
|
||||
: offer.getMirroredDirection();
|
||||
String currencyCode = tradable.getOffer().getCurrencyCode();
|
||||
return DisplayUtils.getDirectionWithCode(direction, currencyCode);
|
||||
}
|
||||
|
||||
public String getDateAsString() {
|
||||
return DisplayUtils.formatDateTime(tradable.getDate());
|
||||
}
|
||||
|
||||
public String getMarketLabel() {
|
||||
return CurrencyUtil.getCurrencyPair(tradable.getOffer().getCurrencyCode());
|
||||
}
|
||||
|
||||
public String getState() {
|
||||
return closedTradableFormatter.getStateAsString(tradable);
|
||||
}
|
||||
|
||||
public int getNumPastTrades() {
|
||||
return closedTradableManager.getNumPastTrades(tradable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean match(String filterString) {
|
||||
if (filterString.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getDateAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getMarketLabel(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getPriceAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getPriceDeviationAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getVolumeAsString(true), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getAmountAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getTradeFeeAsString(true), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getTxFeeAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getBuyerSecurityDepositAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getSellerSecurityDepositAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getState(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getDirectionLabel(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (FilteringUtils.match(getTradable().getOffer(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (getTradable() instanceof BsqSwapTrade && FilteringUtils.match((BsqSwapTrade) getTradable(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
return getTradable() instanceof Trade && FilteringUtils.match((Trade) getTradable(), filterString);
|
||||
}
|
||||
}
|
|
@ -18,28 +18,21 @@
|
|||
-->
|
||||
|
||||
<?import bisq.desktop.components.AutoTooltipButton?>
|
||||
<?import bisq.desktop.components.AutoTooltipLabel?>
|
||||
<?import bisq.desktop.components.InputTextField?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.TableColumn?>
|
||||
<?import javafx.scene.control.TableView?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Pane?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import bisq.desktop.components.list.FilterBox?>
|
||||
<VBox fx:id="root" fx:controller="bisq.desktop.main.portfolio.closedtrades.ClosedTradesView"
|
||||
spacing="10" alignment="CENTER_RIGHT" xmlns:fx="http://javafx.com/fxml">
|
||||
<padding>
|
||||
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0"/>
|
||||
</padding>
|
||||
|
||||
<HBox fx:id="searchBox">
|
||||
<AutoTooltipLabel fx:id="filterLabel"/>
|
||||
<InputTextField fx:id="filterTextField" minWidth="500"/>
|
||||
<Pane fx:id="searchBoxSpacer"/>
|
||||
</HBox>
|
||||
|
||||
<FilterBox fx:id="filterBox" />
|
||||
<TableView fx:id="tableView" VBox.vgrow="ALWAYS">
|
||||
<columns>
|
||||
<TableColumn fx:id="tradeIdColumn" minWidth="110" maxWidth="120"/>
|
||||
|
|
|
@ -24,8 +24,8 @@ import bisq.desktop.components.AutoTooltipButton;
|
|||
import bisq.desktop.components.AutoTooltipLabel;
|
||||
import bisq.desktop.components.AutoTooltipTableColumn;
|
||||
import bisq.desktop.components.HyperlinkWithIcon;
|
||||
import bisq.desktop.components.InputTextField;
|
||||
import bisq.desktop.components.PeerInfoIconTrading;
|
||||
import bisq.desktop.components.list.FilterBox;
|
||||
import bisq.desktop.main.overlays.popups.Popup;
|
||||
import bisq.desktop.main.overlays.windows.BsqTradeDetailsWindow;
|
||||
import bisq.desktop.main.overlays.windows.ClosedTradesSummaryWindow;
|
||||
|
@ -41,7 +41,6 @@ import bisq.core.offer.OfferPayloadBase;
|
|||
import bisq.core.offer.OpenOffer;
|
||||
import bisq.core.trade.model.Tradable;
|
||||
import bisq.core.trade.model.TradeModel;
|
||||
import bisq.core.trade.model.bisq_v1.Contract;
|
||||
import bisq.core.trade.model.bisq_v1.Trade;
|
||||
import bisq.core.trade.model.bsq_swap.BsqSwapTrade;
|
||||
import bisq.core.user.Preferences;
|
||||
|
@ -51,8 +50,6 @@ import bisq.network.p2p.NodeAddress;
|
|||
import bisq.common.config.Config;
|
||||
import bisq.common.crypto.KeyRing;
|
||||
|
||||
import com.google.protobuf.Message;
|
||||
|
||||
import com.googlecode.jcsv.writer.CSVEntryConverter;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
@ -75,7 +72,6 @@ import javafx.scene.control.TableRow;
|
|||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
@ -94,7 +90,6 @@ import javafx.collections.transformation.SortedList;
|
|||
import javafx.util.Callback;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static bisq.desktop.util.FormBuilder.getRegularIconButton;
|
||||
|
@ -133,20 +128,14 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
}
|
||||
|
||||
@FXML
|
||||
TableView<Tradable> tableView;
|
||||
TableView<ClosedTradesListItem> tableView;
|
||||
@FXML
|
||||
TableColumn<Tradable, Tradable> priceColumn, deviationColumn, amountColumn, volumeColumn,
|
||||
TableColumn<ClosedTradesListItem, ClosedTradesListItem> priceColumn, deviationColumn, amountColumn, volumeColumn,
|
||||
txFeeColumn, tradeFeeColumn, buyerSecurityDepositColumn, sellerSecurityDepositColumn,
|
||||
marketColumn, directionColumn, dateColumn, tradeIdColumn, stateColumn,
|
||||
duplicateColumn, avatarColumn;
|
||||
@FXML
|
||||
HBox searchBox;
|
||||
@FXML
|
||||
AutoTooltipLabel filterLabel;
|
||||
@FXML
|
||||
InputTextField filterTextField;
|
||||
@FXML
|
||||
Pane searchBoxSpacer;
|
||||
FilterBox filterBox;
|
||||
@FXML
|
||||
AutoTooltipButton exportButton, summaryButton;
|
||||
@FXML
|
||||
|
@ -161,9 +150,8 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
private final Preferences preferences;
|
||||
private final TradeDetailsWindow tradeDetailsWindow;
|
||||
private final PrivateNotificationManager privateNotificationManager;
|
||||
private SortedList<Tradable> sortedList;
|
||||
private FilteredList<Tradable> filteredList;
|
||||
private ChangeListener<String> filterTextFieldListener;
|
||||
private SortedList<ClosedTradesListItem> sortedList;
|
||||
private FilteredList<ClosedTradesListItem> filteredList;
|
||||
private ChangeListener<Number> widthListener;
|
||||
|
||||
@Inject
|
||||
|
@ -226,52 +214,49 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
setDuplicateColumnCellFactory();
|
||||
setAvatarColumnCellFactory();
|
||||
|
||||
tradeIdColumn.setComparator(Comparator.comparing(Tradable::getId));
|
||||
dateColumn.setComparator(Comparator.comparing(Tradable::getDate));
|
||||
directionColumn.setComparator(Comparator.comparing(o -> o.getOffer().getDirection()));
|
||||
marketColumn.setComparator(Comparator.comparing(model::getMarketLabel));
|
||||
priceColumn.setComparator(Comparator.comparing(model::getPrice, Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
tradeIdColumn.setComparator(Comparator.comparing(ClosedTradesListItem::getTradeId));
|
||||
dateColumn.setComparator(Comparator.comparing(ClosedTradesListItem::getDateAsString));
|
||||
directionColumn.setComparator(Comparator.comparing(o -> o.getTradable().getOffer().getDirection()));
|
||||
marketColumn.setComparator(Comparator.comparing(ClosedTradesListItem::getMarketLabel));
|
||||
priceColumn.setComparator(Comparator.comparing(ClosedTradesListItem::getPriceAsString, Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
deviationColumn.setComparator(Comparator.comparing(o ->
|
||||
o.getOffer().isUseMarketBasedPrice() ? o.getOffer().getMarketPriceMargin() : 1,
|
||||
o.getTradable().getOffer().isUseMarketBasedPrice() ? o.getTradable().getOffer().getMarketPriceMargin() : 1,
|
||||
Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
volumeColumn.setComparator(nullsFirstComparingAsTrade(TradeModel::getVolume));
|
||||
amountColumn.setComparator(Comparator.comparing(model::getAmount, Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
avatarColumn.setComparator(Comparator.comparing(
|
||||
model.dataModel::getNumPastTrades,
|
||||
Comparator.nullsFirst(Comparator.naturalOrder())
|
||||
));
|
||||
amountColumn.setComparator(Comparator.comparing(ClosedTradesListItem::getAmountAsString, Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
avatarColumn.setComparator(Comparator.comparing(ClosedTradesListItem::getNumPastTrades, Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
txFeeColumn.setComparator(nullsFirstComparing(o ->
|
||||
o instanceof TradeModel ? ((TradeModel) o).getTxFee() : o.getOffer().getTxFee()
|
||||
o.getTradable() instanceof TradeModel ? ((TradeModel) o.getTradable()).getTxFee() : o.getTradable().getOffer().getTxFee()
|
||||
));
|
||||
txFeeColumn.setComparator(Comparator.comparing(model::getTxFee, Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
txFeeColumn.setComparator(Comparator.comparing(ClosedTradesListItem::getTxFeeAsString, Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
|
||||
//
|
||||
tradeFeeColumn.setComparator(Comparator.comparing(item -> {
|
||||
String tradeFee = model.getTradeFee(item, true);
|
||||
String tradeFee = item.getTradeFeeAsString(true);
|
||||
// We want to separate BSQ and BTC fees so we use a prefix
|
||||
if (item.getOffer().isCurrencyForMakerFeeBtc()) {
|
||||
if (item.getTradable().getOffer().isCurrencyForMakerFeeBtc()) {
|
||||
return "BTC" + tradeFee;
|
||||
} else {
|
||||
return "BSQ" + tradeFee;
|
||||
}
|
||||
}, Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
buyerSecurityDepositColumn.setComparator(nullsFirstComparing(o ->
|
||||
o.getOffer() != null ? o.getOffer().getBuyerSecurityDeposit() : null
|
||||
o.getTradable().getOffer() != null ? o.getTradable().getOffer().getBuyerSecurityDeposit() : null
|
||||
));
|
||||
sellerSecurityDepositColumn.setComparator(nullsFirstComparing(o ->
|
||||
o.getOffer() != null ? o.getOffer().getSellerSecurityDeposit() : null
|
||||
o.getTradable().getOffer() != null ? o.getTradable().getOffer().getSellerSecurityDeposit() : null
|
||||
));
|
||||
stateColumn.setComparator(Comparator.comparing(model::getState));
|
||||
stateColumn.setComparator(Comparator.comparing(ClosedTradesListItem::getState));
|
||||
|
||||
dateColumn.setSortType(TableColumn.SortType.DESCENDING);
|
||||
tableView.getSortOrder().add(dateColumn);
|
||||
|
||||
tableView.setRowFactory(
|
||||
tableView -> {
|
||||
TableRow<Tradable> row = new TableRow<>();
|
||||
TableRow<ClosedTradesListItem> row = new TableRow<>();
|
||||
ContextMenu rowMenu = new ContextMenu();
|
||||
MenuItem duplicateItem = new MenuItem(Res.get("portfolio.context.offerLikeThis"));
|
||||
duplicateItem.setOnAction((ActionEvent event) -> onDuplicateOffer(row.getItem().getOffer()));
|
||||
duplicateItem.setOnAction((ActionEvent event) -> onDuplicateOffer(row.getItem().getTradable().getOffer()));
|
||||
rowMenu.getItems().add(duplicateItem);
|
||||
row.contextMenuProperty().bind(
|
||||
Bindings.when(Bindings.isNotNull(row.itemProperty()))
|
||||
|
@ -280,12 +265,6 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
return row;
|
||||
});
|
||||
|
||||
filterLabel.setText(Res.get("shared.filter"));
|
||||
HBox.setMargin(filterLabel, new Insets(5, 0, 0, 10));
|
||||
filterTextFieldListener = (observable, oldValue, newValue) -> applyFilteredListPredicate(filterTextField.getText());
|
||||
searchBox.setSpacing(5);
|
||||
HBox.setHgrow(searchBoxSpacer, Priority.ALWAYS);
|
||||
|
||||
numItems.setId("num-offers");
|
||||
numItems.setPadding(new Insets(-5, 0, 0, 10));
|
||||
HBox.setHgrow(footerSpacer, Priority.ALWAYS);
|
||||
|
@ -303,48 +282,49 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
|
||||
tableView.setItems(sortedList);
|
||||
|
||||
filterBox.initialize(filteredList, tableView); // here because filteredList is instantiated here
|
||||
filterBox.activate();
|
||||
|
||||
numItems.setText(Res.get("shared.numItemsLabel", sortedList.size()));
|
||||
exportButton.setOnAction(event -> {
|
||||
CSVEntryConverter<Tradable> headerConverter = item -> {
|
||||
CSVEntryConverter<ClosedTradesListItem> headerConverter = item -> {
|
||||
String[] columns = new String[ColumnNames.values().length];
|
||||
for (ColumnNames m : ColumnNames.values()) {
|
||||
columns[m.ordinal()] = m.toString();
|
||||
}
|
||||
return columns;
|
||||
};
|
||||
CSVEntryConverter<Tradable> contentConverter = item -> {
|
||||
CSVEntryConverter<ClosedTradesListItem> contentConverter = item -> {
|
||||
String[] columns = new String[ColumnNames.values().length];
|
||||
columns[ColumnNames.TRADE_ID.ordinal()] = model.getTradeId(item);
|
||||
columns[ColumnNames.DATE.ordinal()] = model.getDate(item);
|
||||
columns[ColumnNames.MARKET.ordinal()] = model.getMarketLabel(item);
|
||||
columns[ColumnNames.PRICE.ordinal()] = model.getPrice(item);
|
||||
columns[ColumnNames.DEVIATION.ordinal()] = model.getPriceDeviation(item);
|
||||
columns[ColumnNames.AMOUNT.ordinal()] = model.getAmount(item);
|
||||
columns[ColumnNames.VOLUME.ordinal()] = model.getVolume(item, false);
|
||||
columns[ColumnNames.VOLUME_CURRENCY.ordinal()] = model.getVolumeCurrency(item);
|
||||
columns[ColumnNames.TX_FEE.ordinal()] = model.getTxFee(item);
|
||||
if (model.dataModel.isCurrencyForTradeFeeBtc(item)) {
|
||||
columns[ColumnNames.TRADE_FEE_BTC.ordinal()] = model.getTradeFee(item, false);
|
||||
columns[ColumnNames.TRADE_ID.ordinal()] = item.getTradeId();
|
||||
columns[ColumnNames.DATE.ordinal()] = item.getDateAsString();
|
||||
columns[ColumnNames.MARKET.ordinal()] = item.getMarketLabel();
|
||||
columns[ColumnNames.PRICE.ordinal()] = item.getPriceAsString();
|
||||
columns[ColumnNames.DEVIATION.ordinal()] = item.getPriceDeviationAsString();
|
||||
columns[ColumnNames.AMOUNT.ordinal()] = item.getAmountAsString();
|
||||
columns[ColumnNames.VOLUME.ordinal()] = item.getVolumeAsString(false);
|
||||
columns[ColumnNames.VOLUME_CURRENCY.ordinal()] = item.getVolumeCurrencyAsString();
|
||||
columns[ColumnNames.TX_FEE.ordinal()] = item.getTxFeeAsString();
|
||||
if (model.dataModel.isCurrencyForTradeFeeBtc(item.getTradable())) {
|
||||
columns[ColumnNames.TRADE_FEE_BTC.ordinal()] = item.getTradeFeeAsString(false);
|
||||
columns[ColumnNames.TRADE_FEE_BSQ.ordinal()] = "";
|
||||
} else {
|
||||
columns[ColumnNames.TRADE_FEE_BTC.ordinal()] = "";
|
||||
columns[ColumnNames.TRADE_FEE_BSQ.ordinal()] = model.getTradeFee(item, false);
|
||||
columns[ColumnNames.TRADE_FEE_BSQ.ordinal()] = item.getTradeFeeAsString(false);
|
||||
}
|
||||
columns[ColumnNames.BUYER_SEC.ordinal()] = model.getBuyerSecurityDeposit(item);
|
||||
columns[ColumnNames.SELLER_SEC.ordinal()] = model.getSellerSecurityDeposit(item);
|
||||
columns[ColumnNames.OFFER_TYPE.ordinal()] = model.getDirectionLabel(item);
|
||||
columns[ColumnNames.STATUS.ordinal()] = model.getState(item);
|
||||
columns[ColumnNames.BUYER_SEC.ordinal()] = item.getBuyerSecurityDepositAsString();
|
||||
columns[ColumnNames.SELLER_SEC.ordinal()] = item.getSellerSecurityDepositAsString();
|
||||
columns[ColumnNames.OFFER_TYPE.ordinal()] = item.getDirectionLabel();
|
||||
columns[ColumnNames.STATUS.ordinal()] = item.getState();
|
||||
return columns;
|
||||
};
|
||||
|
||||
GUIUtil.exportCSV("tradeHistory.csv", headerConverter, contentConverter,
|
||||
getDummyTradable(), sortedList, (Stage) root.getScene().getWindow());
|
||||
null, sortedList, (Stage) root.getScene().getWindow());
|
||||
});
|
||||
|
||||
summaryButton.setOnAction(event -> new ClosedTradesSummaryWindow(model).show());
|
||||
|
||||
filterTextField.textProperty().addListener(filterTextFieldListener);
|
||||
applyFilteredListPredicate(filterTextField.getText());
|
||||
root.widthProperty().addListener(widthListener);
|
||||
onWidthChange(root.getWidth());
|
||||
}
|
||||
|
@ -355,20 +335,20 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
exportButton.setOnAction(null);
|
||||
summaryButton.setOnAction(null);
|
||||
|
||||
filterTextField.textProperty().removeListener(filterTextFieldListener);
|
||||
filterBox.deactivate();
|
||||
root.widthProperty().removeListener(widthListener);
|
||||
}
|
||||
|
||||
private static <T extends Comparable<T>> Comparator<Tradable> nullsFirstComparing(Function<Tradable, T> keyExtractor) {
|
||||
private static <T extends Comparable<T>> Comparator<ClosedTradesListItem> nullsFirstComparing(Function<ClosedTradesListItem, T> keyExtractor) {
|
||||
return Comparator.comparing(
|
||||
o -> o != null ? keyExtractor.apply(o) : null,
|
||||
Comparator.nullsFirst(Comparator.naturalOrder())
|
||||
);
|
||||
}
|
||||
|
||||
private static <T extends Comparable<T>> Comparator<Tradable> nullsFirstComparingAsTrade(Function<TradeModel, T> keyExtractor) {
|
||||
private static <T extends Comparable<T>> Comparator<ClosedTradesListItem> nullsFirstComparingAsTrade(Function<TradeModel, T> keyExtractor) {
|
||||
return Comparator.comparing(
|
||||
o -> o instanceof TradeModel ? keyExtractor.apply((TradeModel) o) : null,
|
||||
o -> o.getTradable() instanceof TradeModel ? keyExtractor.apply((TradeModel) o.getTradable()) : null,
|
||||
Comparator.nullsFirst(Comparator.naturalOrder())
|
||||
);
|
||||
}
|
||||
|
@ -380,103 +360,6 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
sellerSecurityDepositColumn.setVisible(width > 1500);
|
||||
}
|
||||
|
||||
private void applyFilteredListPredicate(String filterString) {
|
||||
filteredList.setPredicate(tradable -> {
|
||||
if (filterString.isEmpty())
|
||||
return true;
|
||||
|
||||
Offer offer = tradable.getOffer();
|
||||
if (offer.getId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getDate(tradable).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getMarketLabel(tradable).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getPrice(tradable).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getPriceDeviation(tradable).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (model.getVolume(tradable, true).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getAmount(tradable).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getTradeFee(tradable, true).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getTxFee(tradable).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getBuyerSecurityDeposit(tradable).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getSellerSecurityDeposit(tradable).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getState(tradable).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getDirectionLabel(tradable).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (offer.getPaymentMethod().getDisplayString().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (offer.getOfferFeePaymentTxId() != null &&
|
||||
offer.getOfferFeePaymentTxId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (tradable instanceof BsqSwapTrade) {
|
||||
BsqSwapTrade bsqSwapTrade = (BsqSwapTrade) tradable;
|
||||
if (bsqSwapTrade.getTxId() != null && bsqSwapTrade.getTxId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (bsqSwapTrade.getTradingPeerNodeAddress().getFullAddress().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (tradable instanceof Trade) {
|
||||
Trade trade = (Trade) tradable;
|
||||
if (trade.getTakerFeeTxId() != null && trade.getTakerFeeTxId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (trade.getDepositTxId() != null && trade.getDepositTxId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (trade.getPayoutTxId() != null && trade.getPayoutTxId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Contract contract = trade.getContract();
|
||||
boolean isBuyerOnion = false;
|
||||
boolean isSellerOnion = false;
|
||||
boolean matchesBuyersPaymentAccountData = false;
|
||||
boolean matchesSellersPaymentAccountData = false;
|
||||
if (contract != null) {
|
||||
isBuyerOnion = contract.getBuyerNodeAddress().getFullAddress().contains(filterString);
|
||||
isSellerOnion = contract.getSellerNodeAddress().getFullAddress().contains(filterString);
|
||||
matchesBuyersPaymentAccountData = contract.getBuyerPaymentAccountPayload() != null &&
|
||||
contract.getBuyerPaymentAccountPayload().getPaymentDetails().contains(filterString);
|
||||
matchesSellersPaymentAccountData = contract.getSellerPaymentAccountPayload() != null &&
|
||||
contract.getSellerPaymentAccountPayload().getPaymentDetails().contains(filterString);
|
||||
}
|
||||
return isBuyerOnion || isSellerOnion ||
|
||||
matchesBuyersPaymentAccountData || matchesSellersPaymentAccountData;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setTradeIdColumnCellFactory() {
|
||||
tradeIdColumn.getStyleClass().add("first-column");
|
||||
tradeIdColumn.setCellValueFactory((offerListItem) -> new ReadOnlyObjectWrapper<>(offerListItem.getValue()));
|
||||
|
@ -484,17 +367,18 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
new Callback<>() {
|
||||
|
||||
@Override
|
||||
public TableCell<Tradable, Tradable> call(TableColumn<Tradable,
|
||||
Tradable> column) {
|
||||
public TableCell<ClosedTradesListItem, ClosedTradesListItem> call(TableColumn<ClosedTradesListItem,
|
||||
ClosedTradesListItem> column) {
|
||||
return new TableCell<>() {
|
||||
private HyperlinkWithIcon field;
|
||||
|
||||
@Override
|
||||
public void updateItem(final Tradable tradable, boolean empty) {
|
||||
super.updateItem(tradable, empty);
|
||||
if (tradable != null && !empty) {
|
||||
field = new HyperlinkWithIcon(model.getTradeId(tradable));
|
||||
public void updateItem(final ClosedTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null && !empty) {
|
||||
field = new HyperlinkWithIcon(item.getTradeId());
|
||||
field.setOnAction(event -> {
|
||||
Tradable tradable = item.getTradable();
|
||||
if (tradable instanceof Trade) {
|
||||
tradeDetailsWindow.show((Trade) tradable);
|
||||
} else if (tradable instanceof BsqSwapTrade) {
|
||||
|
@ -517,18 +401,18 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
}
|
||||
|
||||
private void setDateColumnCellFactory() {
|
||||
dateColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
dateColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
dateColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
public TableCell<Tradable, Tradable> call(
|
||||
TableColumn<Tradable, Tradable> column) {
|
||||
public TableCell<ClosedTradesListItem, ClosedTradesListItem> call(
|
||||
TableColumn<ClosedTradesListItem, ClosedTradesListItem> column) {
|
||||
return new TableCell<>() {
|
||||
@Override
|
||||
public void updateItem(final Tradable item, boolean empty) {
|
||||
public void updateItem(final ClosedTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null)
|
||||
setGraphic(new AutoTooltipLabel(model.getDate(item)));
|
||||
setGraphic(new AutoTooltipLabel(item.getDateAsString()));
|
||||
else
|
||||
setGraphic(null);
|
||||
}
|
||||
|
@ -538,17 +422,21 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
}
|
||||
|
||||
private void setMarketColumnCellFactory() {
|
||||
marketColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
marketColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
marketColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
public TableCell<Tradable, Tradable> call(
|
||||
TableColumn<Tradable, Tradable> column) {
|
||||
public TableCell<ClosedTradesListItem, ClosedTradesListItem> call(
|
||||
TableColumn<ClosedTradesListItem, ClosedTradesListItem> column) {
|
||||
return new TableCell<>() {
|
||||
@Override
|
||||
public void updateItem(final Tradable item, boolean empty) {
|
||||
public void updateItem(final ClosedTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
setGraphic(new AutoTooltipLabel(model.getMarketLabel(item)));
|
||||
if (item != null && !empty) {
|
||||
setGraphic(new AutoTooltipLabel(item.getMarketLabel()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -556,18 +444,18 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
}
|
||||
|
||||
private void setStateColumnCellFactory() {
|
||||
stateColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
stateColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
stateColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
public TableCell<Tradable, Tradable> call(
|
||||
TableColumn<Tradable, Tradable> column) {
|
||||
public TableCell<ClosedTradesListItem, ClosedTradesListItem> call(
|
||||
TableColumn<ClosedTradesListItem, ClosedTradesListItem> column) {
|
||||
return new TableCell<>() {
|
||||
@Override
|
||||
public void updateItem(final Tradable item, boolean empty) {
|
||||
public void updateItem(final ClosedTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null)
|
||||
setGraphic(new AutoTooltipLabel(model.getState(item)));
|
||||
setGraphic(new AutoTooltipLabel(item.getState()));
|
||||
else
|
||||
setGraphic(null);
|
||||
}
|
||||
|
@ -582,21 +470,21 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
duplicateColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
public TableCell<Tradable, Tradable> call(TableColumn<Tradable, Tradable> column) {
|
||||
public TableCell<ClosedTradesListItem, ClosedTradesListItem> call(TableColumn<ClosedTradesListItem, ClosedTradesListItem> column) {
|
||||
return new TableCell<>() {
|
||||
Button button;
|
||||
|
||||
@Override
|
||||
public void updateItem(final Tradable item, boolean empty) {
|
||||
public void updateItem(final ClosedTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
|
||||
if (item != null && !empty && isMyOfferAsMaker(item.getOffer().getOfferPayloadBase())) {
|
||||
if (item != null && !empty && isMyOfferAsMaker(item.getTradable().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()));
|
||||
button.setOnAction(event -> onDuplicateOffer(item.getTradable().getOffer()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
if (button != null) {
|
||||
|
@ -611,22 +499,22 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
}
|
||||
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
private TableColumn<Tradable, Tradable> setAvatarColumnCellFactory() {
|
||||
private TableColumn<ClosedTradesListItem, ClosedTradesListItem> setAvatarColumnCellFactory() {
|
||||
avatarColumn.getStyleClass().addAll("last-column", "avatar-column");
|
||||
avatarColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
avatarColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
avatarColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
public TableCell<Tradable, Tradable> call(TableColumn<Tradable, Tradable> column) {
|
||||
public TableCell<ClosedTradesListItem, ClosedTradesListItem> call(TableColumn<ClosedTradesListItem, ClosedTradesListItem> column) {
|
||||
return new TableCell<>() {
|
||||
|
||||
@Override
|
||||
public void updateItem(final Tradable item, boolean empty) {
|
||||
public void updateItem(final ClosedTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
|
||||
if (!empty && item instanceof TradeModel) {
|
||||
TradeModel tradeModel = (TradeModel) item;
|
||||
int numPastTrades = model.dataModel.getNumPastTrades(tradeModel);
|
||||
if (!empty && item != null && item.getTradable() instanceof TradeModel) {
|
||||
TradeModel tradeModel = (TradeModel) item.getTradable();
|
||||
int numPastTrades = item.getNumPastTrades();
|
||||
NodeAddress tradingPeerNodeAddress = tradeModel.getTradingPeerNodeAddress();
|
||||
String role = Res.get("peerInfoIcon.tooltip.tradePeer");
|
||||
Node peerInfoIcon = new PeerInfoIconTrading(tradingPeerNodeAddress,
|
||||
|
@ -650,17 +538,21 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
}
|
||||
|
||||
private void setAmountColumnCellFactory() {
|
||||
amountColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
amountColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
amountColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
public TableCell<Tradable, Tradable> call(
|
||||
TableColumn<Tradable, Tradable> column) {
|
||||
public TableCell<ClosedTradesListItem, ClosedTradesListItem> call(
|
||||
TableColumn<ClosedTradesListItem, ClosedTradesListItem> column) {
|
||||
return new TableCell<>() {
|
||||
@Override
|
||||
public void updateItem(final Tradable item, boolean empty) {
|
||||
public void updateItem(final ClosedTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
setGraphic(new AutoTooltipLabel(model.getAmount(item)));
|
||||
if (item != null && !empty) {
|
||||
setGraphic(new AutoTooltipLabel(item.getAmountAsString()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -668,17 +560,21 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
}
|
||||
|
||||
private void setPriceColumnCellFactory() {
|
||||
priceColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
priceColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
priceColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
public TableCell<Tradable, Tradable> call(
|
||||
TableColumn<Tradable, Tradable> column) {
|
||||
public TableCell<ClosedTradesListItem, ClosedTradesListItem> call(
|
||||
TableColumn<ClosedTradesListItem, ClosedTradesListItem> column) {
|
||||
return new TableCell<>() {
|
||||
@Override
|
||||
public void updateItem(final Tradable item, boolean empty) {
|
||||
public void updateItem(final ClosedTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
setGraphic(new AutoTooltipLabel(model.getPrice(item)));
|
||||
if (item != null && !empty) {
|
||||
setGraphic(new AutoTooltipLabel(item.getPriceAsString()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -686,17 +582,21 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
}
|
||||
|
||||
private void setDeviationColumnCellFactory() {
|
||||
deviationColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
deviationColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
deviationColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
public TableCell<Tradable, Tradable> call(
|
||||
TableColumn<Tradable, Tradable> column) {
|
||||
public TableCell<ClosedTradesListItem, ClosedTradesListItem> call(
|
||||
TableColumn<ClosedTradesListItem, ClosedTradesListItem> column) {
|
||||
return new TableCell<>() {
|
||||
@Override
|
||||
public void updateItem(final Tradable item, boolean empty) {
|
||||
public void updateItem(final ClosedTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
setGraphic(new AutoTooltipLabel(model.getPriceDeviation(item)));
|
||||
if (item != null && !empty) {
|
||||
setGraphic(new AutoTooltipLabel(item.getPriceDeviationAsString()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -704,18 +604,18 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
}
|
||||
|
||||
private void setVolumeColumnCellFactory() {
|
||||
volumeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
volumeColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
volumeColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
public TableCell<Tradable, Tradable> call(
|
||||
TableColumn<Tradable, Tradable> column) {
|
||||
public TableCell<ClosedTradesListItem, ClosedTradesListItem> call(
|
||||
TableColumn<ClosedTradesListItem, ClosedTradesListItem> column) {
|
||||
return new TableCell<>() {
|
||||
@Override
|
||||
public void updateItem(final Tradable item, boolean empty) {
|
||||
public void updateItem(final ClosedTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null)
|
||||
setGraphic(new AutoTooltipLabel(model.getVolume(item, true)));
|
||||
setGraphic(new AutoTooltipLabel(item.getVolumeAsString(true)));
|
||||
else
|
||||
setGraphic(null);
|
||||
}
|
||||
|
@ -725,17 +625,21 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
}
|
||||
|
||||
private void setDirectionColumnCellFactory() {
|
||||
directionColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
directionColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
directionColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
public TableCell<Tradable, Tradable> call(
|
||||
TableColumn<Tradable, Tradable> column) {
|
||||
public TableCell<ClosedTradesListItem, ClosedTradesListItem> call(
|
||||
TableColumn<ClosedTradesListItem, ClosedTradesListItem> column) {
|
||||
return new TableCell<>() {
|
||||
@Override
|
||||
public void updateItem(final Tradable item, boolean empty) {
|
||||
public void updateItem(final ClosedTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
setGraphic(new AutoTooltipLabel(model.getDirectionLabel(item)));
|
||||
if (item != null && !empty) {
|
||||
setGraphic(new AutoTooltipLabel(item.getDirectionLabel()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -743,17 +647,21 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
}
|
||||
|
||||
private void setTxFeeColumnCellFactory() {
|
||||
txFeeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
txFeeColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
txFeeColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
public TableCell<Tradable, Tradable> call(
|
||||
TableColumn<Tradable, Tradable> column) {
|
||||
public TableCell<ClosedTradesListItem, ClosedTradesListItem> call(
|
||||
TableColumn<ClosedTradesListItem, ClosedTradesListItem> column) {
|
||||
return new TableCell<>() {
|
||||
@Override
|
||||
public void updateItem(final Tradable item, boolean empty) {
|
||||
public void updateItem(final ClosedTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
setGraphic(new AutoTooltipLabel(model.getTxFee(item)));
|
||||
if (item != null && !empty) {
|
||||
setGraphic(new AutoTooltipLabel(item.getTxFeeAsString()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -761,17 +669,21 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
}
|
||||
|
||||
private void setTradeFeeColumnCellFactory() {
|
||||
tradeFeeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
tradeFeeColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
tradeFeeColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
public TableCell<Tradable, Tradable> call(
|
||||
TableColumn<Tradable, Tradable> column) {
|
||||
public TableCell<ClosedTradesListItem, ClosedTradesListItem> call(
|
||||
TableColumn<ClosedTradesListItem, ClosedTradesListItem> column) {
|
||||
return new TableCell<>() {
|
||||
@Override
|
||||
public void updateItem(final Tradable item, boolean empty) {
|
||||
public void updateItem(final ClosedTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
setGraphic(new AutoTooltipLabel(model.getTradeFee(item, true)));
|
||||
if (item != null && !empty) {
|
||||
setGraphic(new AutoTooltipLabel(item.getTradeFeeAsString(true)));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -779,17 +691,21 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
}
|
||||
|
||||
private void setBuyerSecurityDepositColumnCellFactory() {
|
||||
buyerSecurityDepositColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
buyerSecurityDepositColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
buyerSecurityDepositColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
public TableCell<Tradable, Tradable> call(
|
||||
TableColumn<Tradable, Tradable> column) {
|
||||
public TableCell<ClosedTradesListItem, ClosedTradesListItem> call(
|
||||
TableColumn<ClosedTradesListItem, ClosedTradesListItem> column) {
|
||||
return new TableCell<>() {
|
||||
@Override
|
||||
public void updateItem(final Tradable item, boolean empty) {
|
||||
public void updateItem(final ClosedTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
setGraphic(new AutoTooltipLabel(model.getBuyerSecurityDeposit(item)));
|
||||
if (item != null && !empty) {
|
||||
setGraphic(new AutoTooltipLabel(item.getBuyerSecurityDepositAsString()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -797,17 +713,21 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
}
|
||||
|
||||
private void setSellerSecurityDepositColumnCellFactory() {
|
||||
sellerSecurityDepositColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
sellerSecurityDepositColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
sellerSecurityDepositColumn.setCellFactory(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
public TableCell<Tradable, Tradable> call(
|
||||
TableColumn<Tradable, Tradable> column) {
|
||||
public TableCell<ClosedTradesListItem, ClosedTradesListItem> call(
|
||||
TableColumn<ClosedTradesListItem, ClosedTradesListItem> column) {
|
||||
return new TableCell<>() {
|
||||
@Override
|
||||
public void updateItem(final Tradable item, boolean empty) {
|
||||
public void updateItem(final ClosedTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
setGraphic(new AutoTooltipLabel(model.getSellerSecurityDeposit(item)));
|
||||
if (item != null && !empty) {
|
||||
setGraphic(new AutoTooltipLabel(item.getSellerSecurityDepositAsString()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -830,33 +750,4 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
private boolean isMyOfferAsMaker(OfferPayloadBase offerPayloadBase) {
|
||||
return offerPayloadBase.getPubKeyRing().equals(keyRing.getPubKeyRing());
|
||||
}
|
||||
|
||||
private Tradable getDummyTradable() {
|
||||
return new Tradable() {
|
||||
@Override
|
||||
public Offer getOffer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getDate() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getShortId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message toProtoMessage() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,13 +19,9 @@ package bisq.desktop.main.portfolio.closedtrades;
|
|||
|
||||
import bisq.desktop.common.model.ActivatableWithDataModel;
|
||||
import bisq.desktop.common.model.ViewModel;
|
||||
import bisq.desktop.util.DisplayUtils;
|
||||
|
||||
import bisq.core.locale.CurrencyUtil;
|
||||
import bisq.core.monetary.Volume;
|
||||
import bisq.core.offer.OfferDirection;
|
||||
import bisq.core.trade.ClosedTradableFormatter;
|
||||
import bisq.core.trade.model.Tradable;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
|
@ -43,69 +39,6 @@ public class ClosedTradesViewModel extends ActivatableWithDataModel<ClosedTrades
|
|||
this.closedTradableFormatter = closedTradableFormatter;
|
||||
}
|
||||
|
||||
String getTradeId(Tradable item) {
|
||||
return item.getShortId();
|
||||
}
|
||||
|
||||
String getAmount(Tradable item) {
|
||||
return item != null ? closedTradableFormatter.getAmountAsString(item) : "";
|
||||
}
|
||||
|
||||
String getPrice(Tradable item) {
|
||||
return item != null ? closedTradableFormatter.getPriceAsString(item) : "";
|
||||
}
|
||||
|
||||
String getPriceDeviation(Tradable item) {
|
||||
return item != null ? closedTradableFormatter.getPriceDeviationAsString(item) : "";
|
||||
}
|
||||
|
||||
String getVolume(Tradable item, boolean appendCode) {
|
||||
return item != null ? closedTradableFormatter.getVolumeAsString(item, appendCode) : "";
|
||||
}
|
||||
|
||||
String getVolumeCurrency(Tradable item) {
|
||||
return item != null ? closedTradableFormatter.getVolumeCurrencyAsString(item) : "";
|
||||
}
|
||||
|
||||
String getTxFee(Tradable item) {
|
||||
return item != null ? closedTradableFormatter.getTxFeeAsString(item) : "";
|
||||
}
|
||||
|
||||
String getTradeFee(Tradable item, boolean appendCode) {
|
||||
return item != null ? closedTradableFormatter.getTradeFeeAsString(item, appendCode) : "";
|
||||
}
|
||||
|
||||
String getBuyerSecurityDeposit(Tradable item) {
|
||||
return item != null ? closedTradableFormatter.getBuyerSecurityDepositAsString(item) : "";
|
||||
}
|
||||
|
||||
String getSellerSecurityDeposit(Tradable item) {
|
||||
return item != null ? closedTradableFormatter.getSellerSecurityDepositAsString(item) : "";
|
||||
}
|
||||
|
||||
String getDirectionLabel(Tradable item) {
|
||||
if ((item != null)) {
|
||||
OfferDirection direction = dataModel.getDirection(item.getOffer());
|
||||
String currencyCode = item.getOffer().getCurrencyCode();
|
||||
return DisplayUtils.getDirectionWithCode(direction, currencyCode);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
String getDate(Tradable item) {
|
||||
return DisplayUtils.formatDateTime(item.getDate());
|
||||
}
|
||||
|
||||
String getMarketLabel(Tradable item) {
|
||||
return item != null ? CurrencyUtil.getCurrencyPair(item.getOffer().getCurrencyCode()) : "";
|
||||
}
|
||||
|
||||
String getState(Tradable item) {
|
||||
return item != null ? closedTradableFormatter.getStateAsString(item) : "";
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Used in ClosedTradesSummaryWindow
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -121,7 +54,7 @@ public class ClosedTradesViewModel extends ActivatableWithDataModel<ClosedTrades
|
|||
}
|
||||
|
||||
public Map<String, String> getTotalVolumeByCurrency() {
|
||||
return closedTradableFormatter.getTotalVolumeByCurrencyAsString(dataModel.getList());
|
||||
return closedTradableFormatter.getTotalVolumeByCurrencyAsString(dataModel.getListAsTradables());
|
||||
}
|
||||
|
||||
public String getTotalTxFee(Coin totalTradeAmount) {
|
||||
|
|
|
@ -19,11 +19,11 @@ package bisq.desktop.main.portfolio.failedtrades;
|
|||
|
||||
import bisq.desktop.common.model.ActivatableDataModel;
|
||||
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OfferDirection;
|
||||
import bisq.core.trade.TradeManager;
|
||||
import bisq.core.trade.bisq_v1.FailedTradesManager;
|
||||
import bisq.core.trade.model.bisq_v1.Trade;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
import bisq.network.p2p.P2PService;
|
||||
|
@ -32,6 +32,8 @@ import bisq.common.crypto.KeyRing;
|
|||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
|
@ -45,6 +47,7 @@ class FailedTradesDataModel extends ActivatableDataModel {
|
|||
private final TradeManager tradeManager;
|
||||
private final P2PService p2PService;
|
||||
private final KeyRing keyRing;
|
||||
private final CoinFormatter btcFormatter;
|
||||
|
||||
private final ObservableList<FailedTradesListItem> list = FXCollections.observableArrayList();
|
||||
private final ListChangeListener<Trade> tradesListChangeListener;
|
||||
|
@ -53,11 +56,13 @@ class FailedTradesDataModel extends ActivatableDataModel {
|
|||
public FailedTradesDataModel(FailedTradesManager failedTradesManager,
|
||||
TradeManager tradeManager,
|
||||
P2PService p2PService,
|
||||
KeyRing keyRing) {
|
||||
KeyRing keyRing,
|
||||
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter) {
|
||||
this.failedTradesManager = failedTradesManager;
|
||||
this.tradeManager = tradeManager;
|
||||
this.p2PService = p2PService;
|
||||
this.keyRing = keyRing;
|
||||
this.btcFormatter = btcFormatter;
|
||||
|
||||
tradesListChangeListener = change -> applyList();
|
||||
}
|
||||
|
@ -77,14 +82,15 @@ class FailedTradesDataModel extends ActivatableDataModel {
|
|||
return list;
|
||||
}
|
||||
|
||||
public OfferDirection getDirection(Offer offer) {
|
||||
return failedTradesManager.wasMyOffer(offer) ? offer.getDirection() : offer.getMirroredDirection();
|
||||
}
|
||||
|
||||
private void applyList() {
|
||||
list.clear();
|
||||
|
||||
list.addAll(failedTradesManager.getObservableList().stream().map(FailedTradesListItem::new).collect(Collectors.toList()));
|
||||
list.addAll(
|
||||
failedTradesManager.getObservableList().stream()
|
||||
.map(trade -> new FailedTradesListItem(trade, btcFormatter, failedTradesManager))
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
|
||||
// we sort by date, earliest first
|
||||
list.sort((o1, o2) -> o2.getTrade().getDate().compareTo(o1.getTrade().getDate()));
|
||||
|
|
|
@ -17,19 +17,92 @@
|
|||
|
||||
package bisq.desktop.main.portfolio.failedtrades;
|
||||
|
||||
import bisq.desktop.util.DisplayUtils;
|
||||
import bisq.desktop.util.filtering.FilterableListItem;
|
||||
import bisq.desktop.util.filtering.FilteringUtils;
|
||||
|
||||
import bisq.core.locale.CurrencyUtil;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OfferDirection;
|
||||
import bisq.core.trade.bisq_v1.FailedTradesManager;
|
||||
import bisq.core.trade.model.bisq_v1.Trade;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.VolumeUtil;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
class FailedTradesListItem {
|
||||
class FailedTradesListItem implements FilterableListItem {
|
||||
@Getter
|
||||
private final Trade trade;
|
||||
private final CoinFormatter btcFormatter;
|
||||
private final FailedTradesManager failedTradesManager;
|
||||
|
||||
FailedTradesListItem(Trade trade) {
|
||||
FailedTradesListItem(Trade trade, CoinFormatter btcFormatter, FailedTradesManager failedTradesManager) {
|
||||
this.trade = trade;
|
||||
this.btcFormatter = btcFormatter;
|
||||
this.failedTradesManager = failedTradesManager;
|
||||
}
|
||||
|
||||
FailedTradesListItem() {
|
||||
this.trade = null;
|
||||
public String getDateAsString() {
|
||||
return DisplayUtils.formatDateTime(trade.getDate());
|
||||
}
|
||||
|
||||
public String getMarketLabel() {
|
||||
return CurrencyUtil.getCurrencyPair(trade.getOffer().getCurrencyCode());
|
||||
}
|
||||
|
||||
public String getAmountAsString() {
|
||||
return btcFormatter.formatCoin(trade.getAmount());
|
||||
}
|
||||
|
||||
public String getPriceAsString() {
|
||||
return FormattingUtils.formatPrice(trade.getPrice());
|
||||
}
|
||||
|
||||
public String getVolumeAsString() {
|
||||
return VolumeUtil.formatVolumeWithCode(trade.getVolume());
|
||||
}
|
||||
|
||||
public String getDirectionLabel() {
|
||||
Offer offer = trade.getOffer();
|
||||
OfferDirection direction = failedTradesManager.wasMyOffer(offer) ? offer.getDirection() : offer.getMirroredDirection();
|
||||
return DisplayUtils.getDirectionWithCode(direction, trade.getOffer().getCurrencyCode());
|
||||
}
|
||||
|
||||
public String getState() {
|
||||
return Res.get("portfolio.failed.Failed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean match(String filterString) {
|
||||
if (filterString.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getDateAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getMarketLabel(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getPriceAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getVolumeAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getAmountAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getDirectionLabel(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (FilteringUtils.match(getTrade().getOffer(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
return FilteringUtils.match(getTrade(), filterString);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,26 +18,20 @@
|
|||
-->
|
||||
|
||||
<?import bisq.desktop.components.AutoTooltipButton?>
|
||||
<?import bisq.desktop.components.AutoTooltipLabel?>
|
||||
<?import bisq.desktop.components.InputTextField?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.TableColumn?>
|
||||
<?import javafx.scene.control.TableView?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Pane?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import bisq.desktop.components.list.FilterBox?>
|
||||
<VBox fx:id="root" fx:controller="bisq.desktop.main.portfolio.failedtrades.FailedTradesView"
|
||||
spacing="10" xmlns:fx="http://javafx.com/fxml">
|
||||
<padding>
|
||||
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0"/>
|
||||
</padding>
|
||||
<HBox fx:id="searchBox">
|
||||
<AutoTooltipLabel fx:id="filterLabel"/>
|
||||
<InputTextField fx:id="filterTextField" minWidth="500"/>
|
||||
<Pane fx:id="searchBoxSpacer"/>
|
||||
</HBox>
|
||||
<FilterBox fx:id="filterBox" />
|
||||
<TableView fx:id="tableView" VBox.vgrow="ALWAYS">
|
||||
<columns>
|
||||
<TableColumn fx:id="tradeIdColumn" minWidth="120" maxWidth="120"/>
|
||||
|
|
|
@ -22,15 +22,13 @@ import bisq.desktop.common.view.FxmlView;
|
|||
import bisq.desktop.components.AutoTooltipButton;
|
||||
import bisq.desktop.components.AutoTooltipLabel;
|
||||
import bisq.desktop.components.HyperlinkWithIcon;
|
||||
import bisq.desktop.components.InputTextField;
|
||||
import bisq.desktop.components.list.FilterBox;
|
||||
import bisq.desktop.main.overlays.popups.Popup;
|
||||
import bisq.desktop.main.overlays.windows.TradeDetailsWindow;
|
||||
import bisq.desktop.util.FormBuilder;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.trade.model.bisq_v1.Contract;
|
||||
import bisq.core.trade.model.bisq_v1.Trade;
|
||||
|
||||
import bisq.common.config.Config;
|
||||
|
@ -58,7 +56,6 @@ import javafx.scene.control.Tooltip;
|
|||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
@ -66,7 +63,6 @@ import javafx.scene.layout.VBox;
|
|||
import javafx.geometry.Insets;
|
||||
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
|
||||
import javafx.event.EventHandler;
|
||||
|
||||
|
@ -87,13 +83,7 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
TableColumn<FailedTradesListItem, FailedTradesListItem> priceColumn, amountColumn, volumeColumn,
|
||||
marketColumn, directionColumn, dateColumn, tradeIdColumn, stateColumn, removeTradeColumn;
|
||||
@FXML
|
||||
HBox searchBox;
|
||||
@FXML
|
||||
AutoTooltipLabel filterLabel;
|
||||
@FXML
|
||||
InputTextField filterTextField;
|
||||
@FXML
|
||||
Pane searchBoxSpacer;
|
||||
FilterBox filterBox;
|
||||
@FXML
|
||||
Label numItems;
|
||||
@FXML
|
||||
|
@ -105,7 +95,6 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
private SortedList<FailedTradesListItem> sortedList;
|
||||
private FilteredList<FailedTradesListItem> filteredList;
|
||||
private EventHandler<KeyEvent> keyEventEventHandler;
|
||||
private ChangeListener<String> filterTextFieldListener;
|
||||
private Scene scene;
|
||||
private final boolean allowFaultyDelayedTxs;
|
||||
|
||||
|
@ -147,8 +136,8 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
priceColumn.setComparator(Comparator.comparing(o -> o.getTrade().getPrice()));
|
||||
volumeColumn.setComparator(Comparator.comparing(o -> o.getTrade().getVolume(), Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
amountColumn.setComparator(Comparator.comparing(o -> o.getTrade().getAmount(), Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
stateColumn.setComparator(Comparator.comparing(model::getState));
|
||||
marketColumn.setComparator(Comparator.comparing(model::getMarketLabel));
|
||||
stateColumn.setComparator(Comparator.comparing(FailedTradesListItem::getState));
|
||||
marketColumn.setComparator(Comparator.comparing(FailedTradesListItem::getMarketLabel));
|
||||
|
||||
dateColumn.setSortType(TableColumn.SortType.DESCENDING);
|
||||
tableView.getSortOrder().add(dateColumn);
|
||||
|
@ -173,12 +162,6 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
}
|
||||
};
|
||||
|
||||
filterLabel.setText(Res.get("shared.filter"));
|
||||
HBox.setMargin(filterLabel, new Insets(5, 0, 0, 10));
|
||||
filterTextFieldListener = (observable, oldValue, newValue) -> applyFilteredListPredicate(filterTextField.getText());
|
||||
searchBox.setSpacing(5);
|
||||
HBox.setHgrow(searchBoxSpacer, Priority.ALWAYS);
|
||||
|
||||
numItems.setId("num-offers");
|
||||
numItems.setPadding(new Insets(-5, 0, 0, 10));
|
||||
HBox.setHgrow(footerSpacer, Priority.ALWAYS);
|
||||
|
@ -193,11 +176,14 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
scene.addEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler);
|
||||
}
|
||||
|
||||
filteredList = new FilteredList<>(model.getList());
|
||||
filteredList = new FilteredList<>(model.dataModel.getList());
|
||||
sortedList = new SortedList<>(filteredList);
|
||||
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
||||
tableView.setItems(sortedList);
|
||||
|
||||
filterBox.initialize(filteredList, tableView); // here because filteredList is instantiated here
|
||||
filterBox.activate();
|
||||
|
||||
numItems.setText(Res.get("shared.numItemsLabel", sortedList.size()));
|
||||
exportButton.setOnAction(event -> {
|
||||
ObservableList<TableColumn<FailedTradesListItem, ?>> tableColumns = tableView.getColumns();
|
||||
|
@ -210,27 +196,24 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
};
|
||||
CSVEntryConverter<FailedTradesListItem> contentConverter = item -> {
|
||||
String[] columns = new String[reportColumns];
|
||||
columns[0] = model.getTradeId(item);
|
||||
columns[1] = model.getDate(item);
|
||||
columns[2] = model.getMarketLabel(item);
|
||||
columns[3] = model.getPrice(item);
|
||||
columns[4] = model.getAmount(item);
|
||||
columns[5] = model.getVolume(item);
|
||||
columns[6] = model.getDirectionLabel(item);
|
||||
columns[7] = model.getState(item);
|
||||
columns[0] = item.getTrade().getShortId();
|
||||
columns[1] = item.getDateAsString();
|
||||
columns[2] = item.getMarketLabel();
|
||||
columns[3] = item.getPriceAsString();
|
||||
columns[4] = item.getAmountAsString();
|
||||
columns[5] = item.getVolumeAsString();
|
||||
columns[6] = item.getDirectionLabel();
|
||||
columns[7] = item.getState();
|
||||
return columns;
|
||||
};
|
||||
|
||||
GUIUtil.exportCSV("failedTrades.csv",
|
||||
headerConverter,
|
||||
contentConverter,
|
||||
new FailedTradesListItem(),
|
||||
null,
|
||||
sortedList,
|
||||
(Stage) root.getScene().getWindow());
|
||||
});
|
||||
|
||||
filterTextField.textProperty().addListener(filterTextFieldListener);
|
||||
applyFilteredListPredicate(filterTextField.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -241,72 +224,7 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
|
||||
sortedList.comparatorProperty().unbind();
|
||||
exportButton.setOnAction(null);
|
||||
|
||||
filterTextField.textProperty().removeListener(filterTextFieldListener);
|
||||
}
|
||||
|
||||
private void applyFilteredListPredicate(String filterString) {
|
||||
filteredList.setPredicate(item -> {
|
||||
if (filterString.isEmpty())
|
||||
return true;
|
||||
|
||||
Offer offer = item.getTrade().getOffer();
|
||||
|
||||
if (offer.getId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getDate(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getMarketLabel(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getPrice(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getVolume(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getAmount(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getDirectionLabel(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (offer.getOfferFeePaymentTxId() != null &&
|
||||
offer.getOfferFeePaymentTxId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Trade trade = item.getTrade();
|
||||
|
||||
if (trade.getTakerFeeTxId() != null && trade.getTakerFeeTxId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (trade.getDepositTxId() != null && trade.getDepositTxId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (trade.getPayoutTxId() != null && trade.getPayoutTxId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Contract contract = trade.getContract();
|
||||
|
||||
boolean isBuyerOnion = false;
|
||||
boolean isSellerOnion = false;
|
||||
boolean matchesBuyersPaymentAccountData = false;
|
||||
boolean matchesSellersPaymentAccountData = false;
|
||||
if (contract != null) {
|
||||
isBuyerOnion = contract.getBuyerNodeAddress().getFullAddress().contains(filterString);
|
||||
isSellerOnion = contract.getSellerNodeAddress().getFullAddress().contains(filterString);
|
||||
matchesBuyersPaymentAccountData = contract.getBuyerPaymentAccountPayload() != null &&
|
||||
contract.getBuyerPaymentAccountPayload().getPaymentDetails().contains(filterString);
|
||||
matchesSellersPaymentAccountData = contract.getSellerPaymentAccountPayload() != null &&
|
||||
contract.getSellerPaymentAccountPayload().getPaymentDetails().contains(filterString);
|
||||
}
|
||||
return isBuyerOnion || isSellerOnion ||
|
||||
matchesBuyersPaymentAccountData || matchesSellersPaymentAccountData;
|
||||
});
|
||||
filterBox.deactivate();
|
||||
}
|
||||
|
||||
private void onUnfail() {
|
||||
|
@ -367,7 +285,7 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
public void updateItem(final FailedTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null && !empty) {
|
||||
field = new HyperlinkWithIcon(model.getTradeId(item));
|
||||
field = new HyperlinkWithIcon(item.getTrade().getId());
|
||||
field.setOnAction(event -> tradeDetailsWindow.show(item.getTrade()));
|
||||
field.setTooltip(new Tooltip(Res.get("tooltip.openPopupForDetails")));
|
||||
setGraphic(field);
|
||||
|
@ -394,7 +312,7 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
public void updateItem(final FailedTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null)
|
||||
setGraphic(new AutoTooltipLabel(model.getDate(item)));
|
||||
setGraphic(new AutoTooltipLabel(item.getDateAsString()));
|
||||
else
|
||||
setGraphic(null);
|
||||
}
|
||||
|
@ -414,7 +332,11 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
@Override
|
||||
public void updateItem(final FailedTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
setGraphic(new AutoTooltipLabel(model.getMarketLabel(item)));
|
||||
if (!empty && item != null) {
|
||||
setGraphic(new AutoTooltipLabel(item.getMarketLabel()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -434,7 +356,7 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
public void updateItem(final FailedTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null)
|
||||
setGraphic(new AutoTooltipLabel(model.getState(item)));
|
||||
setGraphic(new AutoTooltipLabel(item.getState()));
|
||||
else
|
||||
setGraphic(null);
|
||||
}
|
||||
|
@ -455,7 +377,11 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
@Override
|
||||
public void updateItem(final FailedTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
setGraphic(new AutoTooltipLabel(model.getAmount(item)));
|
||||
if (!empty && item != null) {
|
||||
setGraphic(new AutoTooltipLabel(item.getAmountAsString()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -473,7 +399,11 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
@Override
|
||||
public void updateItem(final FailedTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
setGraphic(new AutoTooltipLabel(model.getPrice(item)));
|
||||
if (!empty && item != null) {
|
||||
setGraphic(new AutoTooltipLabel(item.getPriceAsString()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -492,7 +422,7 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
public void updateItem(final FailedTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null)
|
||||
setGraphic(new AutoTooltipLabel(model.getVolume(item)));
|
||||
setGraphic(new AutoTooltipLabel(item.getVolumeAsString()));
|
||||
else
|
||||
setGraphic(null);
|
||||
}
|
||||
|
@ -512,7 +442,11 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
|||
@Override
|
||||
public void updateItem(final FailedTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
setGraphic(new AutoTooltipLabel(model.getDirectionLabel(item)));
|
||||
if (!empty && item != null) {
|
||||
setGraphic(new AutoTooltipLabel(item.getDirectionLabel()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -19,74 +19,12 @@ package bisq.desktop.main.portfolio.failedtrades;
|
|||
|
||||
import bisq.desktop.common.model.ActivatableWithDataModel;
|
||||
import bisq.desktop.common.model.ViewModel;
|
||||
import bisq.desktop.util.DisplayUtils;
|
||||
|
||||
import bisq.core.locale.CurrencyUtil;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.VolumeUtil;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
class FailedTradesViewModel extends ActivatableWithDataModel<FailedTradesDataModel> implements ViewModel {
|
||||
private final CoinFormatter formatter;
|
||||
|
||||
|
||||
@Inject
|
||||
public FailedTradesViewModel(FailedTradesDataModel dataModel,
|
||||
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter) {
|
||||
public FailedTradesViewModel(FailedTradesDataModel dataModel) {
|
||||
super(dataModel);
|
||||
|
||||
this.formatter = formatter;
|
||||
}
|
||||
|
||||
public ObservableList<FailedTradesListItem> getList() {
|
||||
return dataModel.getList();
|
||||
}
|
||||
|
||||
String getTradeId(FailedTradesListItem item) {
|
||||
return item.getTrade().getShortId();
|
||||
}
|
||||
|
||||
String getAmount(FailedTradesListItem item) {
|
||||
if (item != null && item.getTrade() != null)
|
||||
return formatter.formatCoin(item.getTrade().getAmount());
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
String getPrice(FailedTradesListItem item) {
|
||||
return (item != null) ? FormattingUtils.formatPrice(item.getTrade().getPrice()) : "";
|
||||
}
|
||||
|
||||
String getVolume(FailedTradesListItem item) {
|
||||
if (item != null && item.getTrade() != null)
|
||||
return VolumeUtil.formatVolumeWithCode(item.getTrade().getVolume());
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
String getDirectionLabel(FailedTradesListItem item) {
|
||||
return (item != null) ? DisplayUtils.getDirectionWithCode(dataModel.getDirection(item.getTrade().getOffer()), item.getTrade().getOffer().getCurrencyCode()) : "";
|
||||
}
|
||||
|
||||
String getMarketLabel(FailedTradesListItem item) {
|
||||
if ((item == null))
|
||||
return "";
|
||||
|
||||
return CurrencyUtil.getCurrencyPair(item.getTrade().getOffer().getCurrencyCode());
|
||||
}
|
||||
|
||||
String getDate(FailedTradesListItem item) {
|
||||
return DisplayUtils.formatDateTime(item.getTrade().getDate());
|
||||
}
|
||||
|
||||
String getState(FailedTradesListItem item) {
|
||||
return item != null ? Res.get("portfolio.failed.Failed") : "";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,27 +17,152 @@
|
|||
|
||||
package bisq.desktop.main.portfolio.openoffer;
|
||||
|
||||
import bisq.desktop.util.DisplayUtils;
|
||||
import bisq.desktop.util.filtering.FilterableListItem;
|
||||
import bisq.desktop.util.filtering.FilteringUtils;
|
||||
|
||||
import bisq.core.locale.CurrencyUtil;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.monetary.Price;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OfferDirection;
|
||||
import bisq.core.offer.OpenOffer;
|
||||
import bisq.core.offer.OpenOfferManager;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.PriceUtil;
|
||||
import bisq.core.util.VolumeUtil;
|
||||
import bisq.core.util.coin.BsqFormatter;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* We could remove that wrapper if it is not needed for additional UI only fields.
|
||||
*/
|
||||
class OpenOfferListItem {
|
||||
class OpenOfferListItem implements FilterableListItem {
|
||||
@Getter
|
||||
private final OpenOffer openOffer;
|
||||
private final PriceUtil priceUtil;
|
||||
private final CoinFormatter btcFormatter;
|
||||
private final BsqFormatter bsqFormatter;
|
||||
private final OpenOfferManager openOfferManager;
|
||||
|
||||
OpenOfferListItem(OpenOffer openOffer) {
|
||||
|
||||
OpenOfferListItem(OpenOffer openOffer, PriceUtil priceUtil, CoinFormatter btcFormatter, BsqFormatter bsqFormatter, OpenOfferManager openOfferManager) {
|
||||
this.openOffer = openOffer;
|
||||
}
|
||||
|
||||
OpenOfferListItem() {
|
||||
openOffer = null;
|
||||
this.priceUtil = priceUtil;
|
||||
this.btcFormatter = btcFormatter;
|
||||
this.bsqFormatter = bsqFormatter;
|
||||
this.openOfferManager = openOfferManager;
|
||||
}
|
||||
|
||||
public Offer getOffer() {
|
||||
return openOffer.getOffer();
|
||||
}
|
||||
|
||||
public String getDateAsString() {
|
||||
return DisplayUtils.formatDateTime(getOffer().getDate());
|
||||
}
|
||||
|
||||
public String getMarketDescription() {
|
||||
return CurrencyUtil.getCurrencyPair(getOffer().getCurrencyCode());
|
||||
}
|
||||
|
||||
public String getPriceAsString() {
|
||||
Price price = getOffer().getPrice();
|
||||
if (price != null) {
|
||||
return FormattingUtils.formatPrice(price);
|
||||
} else {
|
||||
return Res.get("shared.na");
|
||||
}
|
||||
}
|
||||
|
||||
public Double getPriceDeviationAsDouble() {
|
||||
Offer offer = getOffer();
|
||||
return priceUtil.getMarketBasedPrice(offer, offer.getMirroredDirection()).orElse(0d);
|
||||
}
|
||||
|
||||
public String getPriceDeviationAsString() {
|
||||
Offer offer = getOffer();
|
||||
return priceUtil.getMarketBasedPrice(offer, offer.getMirroredDirection())
|
||||
.map(FormattingUtils::formatPercentagePrice)
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
public String getPaymentMethodAsString() {
|
||||
return getOffer().getPaymentMethodNameWithCountryCode();
|
||||
}
|
||||
|
||||
public String getVolumeAsString() {
|
||||
return VolumeUtil.formatVolume(getOffer(), false, 0) + " " + getOffer().getCurrencyCode();
|
||||
}
|
||||
|
||||
public String getAmountAsString() {
|
||||
return DisplayUtils.formatAmount(getOffer(), btcFormatter);
|
||||
}
|
||||
|
||||
public String getDirectionLabel() {
|
||||
Offer offer = getOffer();
|
||||
OfferDirection direction = openOfferManager.isMyOffer(offer) ? offer.getDirection() : offer.getMirroredDirection();
|
||||
return DisplayUtils.getDirectionWithCode(direction, getOffer().getCurrencyCode());
|
||||
}
|
||||
|
||||
public boolean hasMakerFee() {
|
||||
return getOffer().getMakerFee().isPositive();
|
||||
}
|
||||
|
||||
public String getMakerFeeAsString() {
|
||||
Offer offer = getOffer();
|
||||
return offer.isCurrencyForMakerFeeBtc() ?
|
||||
btcFormatter.formatCoinWithCode(offer.getMakerFee()) :
|
||||
bsqFormatter.formatCoinWithCode(offer.getMakerFee());
|
||||
}
|
||||
|
||||
public boolean isNotPublished() {
|
||||
return openOffer.isDeactivated() || (getOffer().isBsqSwapOffer() && openOffer.isBsqSwapOfferHasMissingFunds());
|
||||
}
|
||||
|
||||
public String getTriggerPriceAsString() {
|
||||
Offer offer = getOffer();
|
||||
long triggerPrice = openOffer.getTriggerPrice();
|
||||
if (!offer.isUseMarketBasedPrice() || triggerPrice <= 0) {
|
||||
return Res.get("shared.na");
|
||||
} else {
|
||||
return PriceUtil.formatMarketPrice(triggerPrice, offer.getCurrencyCode());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean match(String filterString) {
|
||||
if (filterString.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getDateAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getMarketDescription(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getPriceAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getPriceDeviationAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getPaymentMethodAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getVolumeAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getAmountAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getDirectionLabel(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
return FilteringUtils.match(getOffer(), filterString);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,12 +26,18 @@ import bisq.core.offer.OpenOfferManager;
|
|||
import bisq.core.offer.bisq_v1.TriggerPriceService;
|
||||
import bisq.core.offer.bsq_swap.OpenBsqSwapOfferService;
|
||||
import bisq.core.provider.price.PriceFeedService;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.PriceUtil;
|
||||
import bisq.core.util.coin.BsqFormatter;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
import bisq.common.handlers.ErrorMessageHandler;
|
||||
import bisq.common.handlers.ResultHandler;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
import javafx.beans.value.ChangeListener;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
|
@ -44,6 +50,9 @@ class OpenOffersDataModel extends ActivatableDataModel {
|
|||
private final OpenOfferManager openOfferManager;
|
||||
private final OpenBsqSwapOfferService openBsqSwapOfferService;
|
||||
private final PriceFeedService priceFeedService;
|
||||
private final PriceUtil priceUtil;
|
||||
private final CoinFormatter btcFormatter;
|
||||
private final BsqFormatter bsqFormatter;
|
||||
|
||||
private final ObservableList<OpenOfferListItem> list = FXCollections.observableArrayList();
|
||||
private final ListChangeListener<OpenOffer> tradesListChangeListener;
|
||||
|
@ -52,10 +61,16 @@ class OpenOffersDataModel extends ActivatableDataModel {
|
|||
@Inject
|
||||
public OpenOffersDataModel(OpenOfferManager openOfferManager,
|
||||
OpenBsqSwapOfferService openBsqSwapOfferService,
|
||||
PriceFeedService priceFeedService) {
|
||||
PriceFeedService priceFeedService,
|
||||
PriceUtil priceUtil,
|
||||
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter,
|
||||
BsqFormatter bsqFormatter) {
|
||||
this.openOfferManager = openOfferManager;
|
||||
this.openBsqSwapOfferService = openBsqSwapOfferService;
|
||||
this.priceFeedService = priceFeedService;
|
||||
this.priceUtil = priceUtil;
|
||||
this.btcFormatter = btcFormatter;
|
||||
this.bsqFormatter = bsqFormatter;
|
||||
|
||||
tradesListChangeListener = change -> applyList();
|
||||
currenciesUpdateFlagPropertyListener = (observable, oldValue, newValue) -> applyList();
|
||||
|
@ -106,7 +121,11 @@ class OpenOffersDataModel extends ActivatableDataModel {
|
|||
private void applyList() {
|
||||
list.clear();
|
||||
|
||||
list.addAll(openOfferManager.getObservableList().stream().map(OpenOfferListItem::new).collect(Collectors.toList()));
|
||||
list.addAll(
|
||||
openOfferManager.getObservableList().stream()
|
||||
.map(item -> new OpenOfferListItem(item, priceUtil, btcFormatter, bsqFormatter, openOfferManager))
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
|
||||
// we sort by date, earliest first
|
||||
list.sort((o1, o2) -> o2.getOffer().getDate().compareTo(o1.getOffer().getDate()));
|
||||
|
|
|
@ -18,9 +18,8 @@
|
|||
-->
|
||||
|
||||
<?import bisq.desktop.components.AutoTooltipButton?>
|
||||
<?import bisq.desktop.components.AutoTooltipLabel?>
|
||||
<?import bisq.desktop.components.AutoTooltipSlideToggleButton?>
|
||||
<?import bisq.desktop.components.InputTextField?>
|
||||
<?import bisq.desktop.components.list.FilterBox?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.TableColumn?>
|
||||
<?import javafx.scene.control.TableView?>
|
||||
|
@ -34,10 +33,9 @@
|
|||
<padding>
|
||||
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0"/>
|
||||
</padding>
|
||||
<HBox fx:id="searchBox">
|
||||
<AutoTooltipLabel fx:id="filterLabel"/>
|
||||
<InputTextField fx:id="filterTextField" minWidth="500"/>
|
||||
<Pane fx:id="searchBoxSpacer"/>
|
||||
<HBox>
|
||||
<FilterBox fx:id="filterBox" />
|
||||
<Pane HBox.hgrow="ALWAYS"/>
|
||||
<AutoTooltipSlideToggleButton fx:id="selectToggleButton"/>
|
||||
</HBox>
|
||||
<TableView fx:id="tableView" VBox.vgrow="ALWAYS">
|
||||
|
|
|
@ -25,7 +25,7 @@ import bisq.desktop.components.AutoTooltipLabel;
|
|||
import bisq.desktop.components.AutoTooltipSlideToggleButton;
|
||||
import bisq.desktop.components.AutoTooltipTableColumn;
|
||||
import bisq.desktop.components.HyperlinkWithIcon;
|
||||
import bisq.desktop.components.InputTextField;
|
||||
import bisq.desktop.components.list.FilterBox;
|
||||
import bisq.desktop.main.MainView;
|
||||
import bisq.desktop.main.funds.FundsView;
|
||||
import bisq.desktop.main.funds.withdrawal.WithdrawalView;
|
||||
|
@ -62,7 +62,6 @@ import javafx.scene.control.TableView;
|
|||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
@ -121,13 +120,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||
marketColumn, directionColumn, dateColumn, offerIdColumn, deactivateItemColumn,
|
||||
removeItemColumn, editItemColumn, triggerPriceColumn, triggerIconColumn, paymentMethodColumn, duplicateItemColumn;
|
||||
@FXML
|
||||
HBox searchBox;
|
||||
@FXML
|
||||
AutoTooltipLabel filterLabel;
|
||||
@FXML
|
||||
InputTextField filterTextField;
|
||||
@FXML
|
||||
Pane searchBoxSpacer;
|
||||
FilterBox filterBox;
|
||||
@FXML
|
||||
Label numItems;
|
||||
@FXML
|
||||
|
@ -141,8 +134,6 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||
private final OfferDetailsWindow offerDetailsWindow;
|
||||
private final BsqSwapOfferDetailsWindow bsqSwapOfferDetailsWindow;
|
||||
private SortedList<OpenOfferListItem> sortedList;
|
||||
private FilteredList<OpenOfferListItem> filteredList;
|
||||
private ChangeListener<String> filterTextFieldListener;
|
||||
private PortfolioView.OpenOfferActionHandler openOfferActionHandler;
|
||||
private ChangeListener<Number> widthListener;
|
||||
|
||||
|
@ -197,10 +188,10 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||
|
||||
offerIdColumn.setComparator(Comparator.comparing(o -> o.getOffer().getId()));
|
||||
directionColumn.setComparator(Comparator.comparing(o -> o.getOffer().getDirection()));
|
||||
marketColumn.setComparator(Comparator.comparing(model::getMarketLabel));
|
||||
marketColumn.setComparator(Comparator.comparing(OpenOfferListItem::getMarketDescription));
|
||||
amountColumn.setComparator(Comparator.comparing(o -> o.getOffer().getAmount()));
|
||||
priceColumn.setComparator(Comparator.comparing(o -> o.getOffer().getPrice(), Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
deviationColumn.setComparator(Comparator.comparing(model::getPriceDeviationAsDouble, Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
deviationColumn.setComparator(Comparator.comparing(OpenOfferListItem::getPriceDeviationAsDouble, Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
triggerPriceColumn.setComparator(Comparator.comparing(o -> o.getOpenOffer().getTriggerPrice(),
|
||||
Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
volumeColumn.setComparator(Comparator.comparing(o -> o.getOffer().getVolume(), Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
|
@ -224,12 +215,6 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||
return row;
|
||||
});
|
||||
|
||||
filterLabel.setText(Res.get("shared.filter"));
|
||||
HBox.setMargin(filterLabel, new Insets(5, 0, 0, 10));
|
||||
filterTextFieldListener = (observable, oldValue, newValue) -> applyFilteredListPredicate(filterTextField.getText());
|
||||
searchBox.setSpacing(5);
|
||||
HBox.setHgrow(searchBoxSpacer, Priority.ALWAYS);
|
||||
|
||||
selectToggleButton.setPadding(new Insets(0, 90, -20, 0));
|
||||
selectToggleButton.setText(Res.get("shared.enabled"));
|
||||
selectToggleButton.setDisable(true);
|
||||
|
@ -243,11 +228,14 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||
|
||||
@Override
|
||||
protected void activate() {
|
||||
filteredList = new FilteredList<>(model.getList());
|
||||
FilteredList<OpenOfferListItem> filteredList = new FilteredList<>(model.dataModel.getList());
|
||||
sortedList = new SortedList<>(filteredList);
|
||||
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
||||
tableView.setItems(sortedList);
|
||||
|
||||
filterBox.initialize(filteredList, tableView); // here because filteredList is instantiated here
|
||||
filterBox.activate();
|
||||
|
||||
updateSelectToggleButtonState();
|
||||
|
||||
selectToggleButton.setOnAction(event -> {
|
||||
|
@ -272,16 +260,16 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||
};
|
||||
CSVEntryConverter<OpenOfferListItem> contentConverter = item -> {
|
||||
String[] columns = new String[ColumnNames.values().length];
|
||||
columns[ColumnNames.OFFER_ID.ordinal()] = model.getOfferId(item);
|
||||
columns[ColumnNames.DATE.ordinal()] = model.getDate(item);
|
||||
columns[ColumnNames.MARKET.ordinal()] = model.getMarketLabel(item);
|
||||
columns[ColumnNames.PRICE.ordinal()] = model.getPrice(item);
|
||||
columns[ColumnNames.DEVIATION.ordinal()] = model.getPriceDeviation(item);
|
||||
columns[ColumnNames.TRIGGER_PRICE.ordinal()] = model.getTriggerPrice(item);
|
||||
columns[ColumnNames.AMOUNT.ordinal()] = model.getAmount(item);
|
||||
columns[ColumnNames.VOLUME.ordinal()] = model.getVolume(item);
|
||||
columns[ColumnNames.PAYMENT_METHOD.ordinal()] = model.getPaymentMethod(item);
|
||||
columns[ColumnNames.DIRECTION.ordinal()] = model.getDirectionLabel(item);
|
||||
columns[ColumnNames.OFFER_ID.ordinal()] = item.getOffer().getShortId();
|
||||
columns[ColumnNames.DATE.ordinal()] = item.getDateAsString();
|
||||
columns[ColumnNames.MARKET.ordinal()] = item.getMarketDescription();
|
||||
columns[ColumnNames.PRICE.ordinal()] = item.getPriceAsString();
|
||||
columns[ColumnNames.DEVIATION.ordinal()] = item.getPriceDeviationAsString();
|
||||
columns[ColumnNames.TRIGGER_PRICE.ordinal()] = item.getTriggerPriceAsString();
|
||||
columns[ColumnNames.AMOUNT.ordinal()] = item.getAmountAsString();
|
||||
columns[ColumnNames.VOLUME.ordinal()] = item.getVolumeAsString();
|
||||
columns[ColumnNames.PAYMENT_METHOD.ordinal()] = item.getPaymentMethodAsString();
|
||||
columns[ColumnNames.DIRECTION.ordinal()] = item.getDirectionLabel();
|
||||
columns[ColumnNames.STATUS.ordinal()] = String.valueOf(!item.getOpenOffer().isDeactivated());
|
||||
return columns;
|
||||
};
|
||||
|
@ -289,14 +277,11 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||
GUIUtil.exportCSV("openOffers.csv",
|
||||
headerConverter,
|
||||
contentConverter,
|
||||
new OpenOfferListItem(),
|
||||
new OpenOfferListItem(null, null, null, null, null),
|
||||
sortedList,
|
||||
(Stage) root.getScene().getWindow());
|
||||
});
|
||||
|
||||
filterTextField.textProperty().addListener(filterTextFieldListener);
|
||||
applyFilteredListPredicate(filterTextField.getText());
|
||||
|
||||
root.widthProperty().addListener(widthListener);
|
||||
onWidthChange(root.getWidth());
|
||||
}
|
||||
|
@ -306,7 +291,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||
sortedList.comparatorProperty().unbind();
|
||||
exportButton.setOnAction(null);
|
||||
|
||||
filterTextField.textProperty().removeListener(filterTextFieldListener);
|
||||
filterBox.deactivate();
|
||||
root.widthProperty().removeListener(widthListener);
|
||||
}
|
||||
|
||||
|
@ -327,44 +312,6 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||
}
|
||||
}
|
||||
|
||||
private void applyFilteredListPredicate(String filterString) {
|
||||
filteredList.setPredicate(item -> {
|
||||
if (filterString.isEmpty())
|
||||
return true;
|
||||
|
||||
Offer offer = item.getOpenOffer().getOffer();
|
||||
if (offer.getId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getDate(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getMarketLabel(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getPrice(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getPriceDeviation(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getPaymentMethod(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getVolume(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getAmount(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getDirectionLabel(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
return offer.getOfferFeePaymentTxId() != null &&
|
||||
offer.getOfferFeePaymentTxId().contains(filterString);
|
||||
});
|
||||
}
|
||||
|
||||
private void onWidthChange(double width) {
|
||||
triggerPriceColumn.setVisible(width > 1200);
|
||||
}
|
||||
|
@ -393,12 +340,13 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||
}
|
||||
}
|
||||
|
||||
private void onRemoveOpenOffer(OpenOffer openOffer) {
|
||||
private void onRemoveOpenOffer(OpenOfferListItem item) {
|
||||
OpenOffer openOffer = item.getOpenOffer();
|
||||
if (model.isBootstrappedOrShowPopup()) {
|
||||
String key = "RemoveOfferWarning";
|
||||
if (DontShowAgainLookup.showAgain(key)) {
|
||||
String message = model.hasMakerFee(openOffer) ?
|
||||
Res.get("popup.warning.removeOffer", model.getMakerFeeAsString(openOffer)) :
|
||||
String message = item.hasMakerFee() ?
|
||||
Res.get("popup.warning.removeOffer", item.getMakerFeeAsString()) :
|
||||
Res.get("popup.warning.removeNoFeeOffer");
|
||||
new Popup().warning(message)
|
||||
.actionButtonText(Res.get("shared.removeOffer"))
|
||||
|
@ -468,7 +416,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||
public void updateItem(final OpenOfferListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null && !empty) {
|
||||
field = new HyperlinkWithIcon(model.getOfferId(item));
|
||||
field = new HyperlinkWithIcon(item.getOffer().getShortId());
|
||||
field.setOnAction(event -> {
|
||||
if (item.getOffer().isBsqSwapOffer()) {
|
||||
bsqSwapOfferDetailsWindow.show(item.getOffer());
|
||||
|
@ -503,8 +451,8 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||
super.updateItem(item, empty);
|
||||
getStyleClass().removeAll("offer-disabled");
|
||||
if (item != null) {
|
||||
if (model.isNotPublished(item)) getStyleClass().add("offer-disabled");
|
||||
setGraphic(new AutoTooltipLabel(model.getDate(item)));
|
||||
if (item.isNotPublished()) getStyleClass().add("offer-disabled");
|
||||
setGraphic(new AutoTooltipLabel(item.getDateAsString()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
|
@ -528,8 +476,8 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||
getStyleClass().removeAll("offer-disabled");
|
||||
|
||||
if (item != null) {
|
||||
if (model.isNotPublished(item)) getStyleClass().add("offer-disabled");
|
||||
setGraphic(new AutoTooltipLabel(model.getAmount(item)));
|
||||
if (item.isNotPublished()) getStyleClass().add("offer-disabled");
|
||||
setGraphic(new AutoTooltipLabel(item.getAmountAsString()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
|
@ -553,8 +501,8 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||
getStyleClass().removeAll("offer-disabled");
|
||||
|
||||
if (item != null) {
|
||||
if (model.isNotPublished(item)) getStyleClass().add("offer-disabled");
|
||||
setGraphic(new AutoTooltipLabel(model.getPrice(item)));
|
||||
if (item.isNotPublished()) getStyleClass().add("offer-disabled");
|
||||
setGraphic(new AutoTooltipLabel(item.getPriceAsString()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
|
@ -578,8 +526,8 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||
getStyleClass().removeAll("offer-disabled");
|
||||
|
||||
if (item != null) {
|
||||
if (model.isNotPublished(item)) getStyleClass().add("offer-disabled");
|
||||
AutoTooltipLabel autoTooltipLabel = new AutoTooltipLabel(model.getPriceDeviation(item));
|
||||
if (item.isNotPublished()) getStyleClass().add("offer-disabled");
|
||||
AutoTooltipLabel autoTooltipLabel = new AutoTooltipLabel(item.getPriceDeviationAsString());
|
||||
autoTooltipLabel.setOpacity(item.getOffer().isUseMarketBasedPrice() ? 1 : 0.4);
|
||||
setGraphic(autoTooltipLabel);
|
||||
} else {
|
||||
|
@ -604,8 +552,8 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||
super.updateItem(item, empty);
|
||||
getStyleClass().removeAll("offer-disabled");
|
||||
if (item != null) {
|
||||
if (model.isNotPublished(item)) getStyleClass().add("offer-disabled");
|
||||
setGraphic(new AutoTooltipLabel(model.getTriggerPrice(item)));
|
||||
if (item.isNotPublished()) getStyleClass().add("offer-disabled");
|
||||
setGraphic(new AutoTooltipLabel(item.getTriggerPriceAsString()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
|
@ -629,8 +577,8 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||
getStyleClass().removeAll("offer-disabled");
|
||||
|
||||
if (item != null) {
|
||||
if (model.isNotPublished(item)) getStyleClass().add("offer-disabled");
|
||||
setGraphic(new AutoTooltipLabel(model.getVolume(item)));
|
||||
if (item.isNotPublished()) getStyleClass().add("offer-disabled");
|
||||
setGraphic(new AutoTooltipLabel(item.getVolumeAsString()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
|
@ -654,8 +602,8 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||
getStyleClass().removeAll("offer-disabled");
|
||||
|
||||
if (item != null) {
|
||||
if (model.isNotPublished(item)) getStyleClass().add("offer-disabled");
|
||||
setGraphic(new AutoTooltipLabel(model.getPaymentMethod(item)));
|
||||
if (item.isNotPublished()) getStyleClass().add("offer-disabled");
|
||||
setGraphic(new AutoTooltipLabel(item.getPaymentMethodAsString()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
|
@ -679,8 +627,8 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||
getStyleClass().removeAll("offer-disabled");
|
||||
|
||||
if (item != null) {
|
||||
if (model.isNotPublished(item)) getStyleClass().add("offer-disabled");
|
||||
setGraphic(new AutoTooltipLabel(model.getDirectionLabel(item)));
|
||||
if (item.isNotPublished()) getStyleClass().add("offer-disabled");
|
||||
setGraphic(new AutoTooltipLabel(item.getDirectionLabel()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
|
@ -704,8 +652,8 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||
getStyleClass().removeAll("offer-disabled");
|
||||
|
||||
if (item != null) {
|
||||
if (model.isNotPublished(item)) getStyleClass().add("offer-disabled");
|
||||
setGraphic(new AutoTooltipLabel(model.getMarketLabel(item)));
|
||||
if (item.isNotPublished()) getStyleClass().add("offer-disabled");
|
||||
setGraphic(new AutoTooltipLabel(item.getMarketDescription()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
|
@ -785,7 +733,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||
button.setTooltip(new Tooltip(Res.get("shared.removeOffer")));
|
||||
setGraphic(button);
|
||||
}
|
||||
button.setOnAction(event -> onRemoveOpenOffer(item.getOpenOffer()));
|
||||
button.setOnAction(event -> onRemoveOpenOffer(item));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
if (button != null) {
|
||||
|
@ -857,7 +805,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||
button.setTooltip(new Tooltip(Res.get("openOffer.triggered")));
|
||||
} else {
|
||||
button.getGraphic().getStyleClass().remove("warning");
|
||||
button.setTooltip(new Tooltip(Res.get("openOffer.triggerPrice", model.getTriggerPrice(item))));
|
||||
button.setTooltip(new Tooltip(Res.get("openOffer.triggerPrice", item.getTriggerPriceAsString())));
|
||||
}
|
||||
setGraphic(button);
|
||||
}
|
||||
|
|
|
@ -19,54 +19,31 @@ package bisq.desktop.main.portfolio.openoffer;
|
|||
|
||||
import bisq.desktop.common.model.ActivatableWithDataModel;
|
||||
import bisq.desktop.common.model.ViewModel;
|
||||
import bisq.desktop.util.DisplayUtils;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
|
||||
import bisq.core.locale.CurrencyUtil;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.monetary.Price;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OpenOffer;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.PriceUtil;
|
||||
import bisq.core.util.VolumeUtil;
|
||||
import bisq.core.util.coin.BsqFormatter;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
import bisq.network.p2p.P2PService;
|
||||
|
||||
import bisq.common.handlers.ErrorMessageHandler;
|
||||
import bisq.common.handlers.ResultHandler;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
class OpenOffersViewModel extends ActivatableWithDataModel<OpenOffersDataModel> implements ViewModel {
|
||||
private final P2PService p2PService;
|
||||
private final PriceUtil priceUtil;
|
||||
private final CoinFormatter btcFormatter;
|
||||
private final BsqFormatter bsqFormatter;
|
||||
|
||||
|
||||
@Inject
|
||||
public OpenOffersViewModel(OpenOffersDataModel dataModel,
|
||||
P2PService p2PService,
|
||||
PriceUtil priceUtil,
|
||||
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter,
|
||||
BsqFormatter bsqFormatter) {
|
||||
PriceUtil priceUtil) {
|
||||
super(dataModel);
|
||||
|
||||
this.p2PService = p2PService;
|
||||
this.priceUtil = priceUtil;
|
||||
this.btcFormatter = btcFormatter;
|
||||
this.bsqFormatter = bsqFormatter;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -90,122 +67,7 @@ class OpenOffersViewModel extends ActivatableWithDataModel<OpenOffersDataModel>
|
|||
dataModel.onRemoveOpenOffer(openOffer, resultHandler, errorMessageHandler);
|
||||
}
|
||||
|
||||
public ObservableList<OpenOfferListItem> getList() {
|
||||
return dataModel.getList();
|
||||
}
|
||||
|
||||
String getOfferId(OpenOfferListItem item) {
|
||||
return item.getOffer().getShortId();
|
||||
}
|
||||
|
||||
String getAmount(OpenOfferListItem item) {
|
||||
return (item != null) ? DisplayUtils.formatAmount(item.getOffer(), btcFormatter) : "";
|
||||
}
|
||||
|
||||
String getPrice(OpenOfferListItem item) {
|
||||
if ((item == null))
|
||||
return "";
|
||||
|
||||
Offer offer = item.getOffer();
|
||||
Price price = offer.getPrice();
|
||||
if (price != null) {
|
||||
return FormattingUtils.formatPrice(price);
|
||||
} else {
|
||||
return Res.get("shared.na");
|
||||
}
|
||||
}
|
||||
|
||||
String getPriceDeviation(OpenOfferListItem item) {
|
||||
Offer offer = item.getOffer();
|
||||
return priceUtil.getMarketBasedPrice(offer, offer.getMirroredDirection())
|
||||
.map(FormattingUtils::formatPercentagePrice)
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
Double getPriceDeviationAsDouble(OpenOfferListItem item) {
|
||||
Offer offer = item.getOffer();
|
||||
return priceUtil.getMarketBasedPrice(offer, offer.getMirroredDirection()).orElse(0d);
|
||||
}
|
||||
|
||||
String getVolume(OpenOfferListItem item) {
|
||||
return (item != null)
|
||||
? VolumeUtil.formatVolume(item.getOffer(), false, 0) + " " + item.getOffer().getCurrencyCode()
|
||||
: "";
|
||||
}
|
||||
|
||||
String getDirectionLabel(OpenOfferListItem item) {
|
||||
if ((item == null))
|
||||
return "";
|
||||
|
||||
return DisplayUtils.getDirectionWithCode(dataModel.getDirection(item.getOffer()), item.getOffer().getCurrencyCode());
|
||||
}
|
||||
|
||||
String getMarketLabel(OpenOfferListItem item) {
|
||||
if ((item == null))
|
||||
return "";
|
||||
|
||||
return CurrencyUtil.getCurrencyPair(item.getOffer().getCurrencyCode());
|
||||
}
|
||||
|
||||
String getPaymentMethod(OpenOfferListItem item) {
|
||||
String result = "";
|
||||
if (item != null) {
|
||||
Offer offer = item.getOffer();
|
||||
checkNotNull(offer);
|
||||
checkNotNull(offer.getPaymentMethod());
|
||||
result = offer.getPaymentMethodNameWithCountryCode();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
String getDate(OpenOfferListItem item) {
|
||||
return DisplayUtils.formatDateTime(item.getOffer().getDate());
|
||||
}
|
||||
|
||||
boolean isNotPublished(OpenOfferListItem item) {
|
||||
return isDeactivated(item) || isBsqSwapOfferHasMissingFunds(item);
|
||||
}
|
||||
|
||||
boolean isDeactivated(OpenOfferListItem item) {
|
||||
return item != null &&
|
||||
item.getOpenOffer() != null &&
|
||||
item.getOpenOffer().isDeactivated();
|
||||
}
|
||||
|
||||
boolean isBsqSwapOfferHasMissingFunds(OpenOfferListItem item) {
|
||||
return item != null &&
|
||||
item.getOpenOffer() != null &&
|
||||
item.getOpenOffer().getOffer().isBsqSwapOffer() &&
|
||||
item.getOpenOffer().isBsqSwapOfferHasMissingFunds();
|
||||
}
|
||||
|
||||
boolean isBootstrappedOrShowPopup() {
|
||||
return GUIUtil.isBootstrappedOrShowPopup(p2PService);
|
||||
}
|
||||
|
||||
public boolean hasMakerFee(OpenOffer openOffer) {
|
||||
Coin makerFee = openOffer.getOffer().getMakerFee();
|
||||
return makerFee.isPositive();
|
||||
}
|
||||
|
||||
public String getMakerFeeAsString(OpenOffer openOffer) {
|
||||
Offer offer = openOffer.getOffer();
|
||||
return offer.isCurrencyForMakerFeeBtc() ?
|
||||
btcFormatter.formatCoinWithCode(offer.getMakerFee()) :
|
||||
bsqFormatter.formatCoinWithCode(offer.getMakerFee());
|
||||
}
|
||||
|
||||
String getTriggerPrice(OpenOfferListItem item) {
|
||||
if ((item == null)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
Offer offer = item.getOffer();
|
||||
long triggerPrice = item.getOpenOffer().getTriggerPrice();
|
||||
if (!offer.isUseMarketBasedPrice() || triggerPrice <= 0) {
|
||||
return Res.get("shared.na");
|
||||
} else {
|
||||
return PriceUtil.formatMarketPrice(triggerPrice, offer.getCurrencyCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ import bisq.core.trade.protocol.bisq_v1.DisputeProtocol;
|
|||
import bisq.core.trade.protocol.bisq_v1.SellerProtocol;
|
||||
import bisq.core.user.Preferences;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
import bisq.network.p2p.P2PService;
|
||||
|
||||
|
@ -71,6 +72,8 @@ import org.bitcoinj.core.TransactionConfidence;
|
|||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
|
@ -109,6 +112,7 @@ public class PendingTradesDataModel extends ActivatableDataModel {
|
|||
public final WalletPasswordWindow walletPasswordWindow;
|
||||
private final NotificationCenter notificationCenter;
|
||||
private final OfferUtil offerUtil;
|
||||
private final CoinFormatter btcFormatter;
|
||||
|
||||
final ObservableList<PendingTradesListItem> list = FXCollections.observableArrayList();
|
||||
private final ListChangeListener<Trade> tradesListChangeListener;
|
||||
|
@ -145,7 +149,8 @@ public class PendingTradesDataModel extends ActivatableDataModel {
|
|||
Navigation navigation,
|
||||
WalletPasswordWindow walletPasswordWindow,
|
||||
NotificationCenter notificationCenter,
|
||||
OfferUtil offerUtil) {
|
||||
OfferUtil offerUtil,
|
||||
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter) {
|
||||
this.tradeManager = tradeManager;
|
||||
this.btcWalletService = btcWalletService;
|
||||
this.pubKeyRing = pubKeyRing;
|
||||
|
@ -161,6 +166,7 @@ public class PendingTradesDataModel extends ActivatableDataModel {
|
|||
this.walletPasswordWindow = walletPasswordWindow;
|
||||
this.notificationCenter = notificationCenter;
|
||||
this.offerUtil = offerUtil;
|
||||
this.btcFormatter = formatter;
|
||||
|
||||
tradesListChangeListener = change -> onListChanged();
|
||||
notificationCenter.setSelectItemByTradeIdConsumer(this::selectItemByTradeId);
|
||||
|
@ -381,7 +387,7 @@ public class PendingTradesDataModel extends ActivatableDataModel {
|
|||
private void onListChanged() {
|
||||
list.clear();
|
||||
list.addAll(tradeManager.getObservableList().stream()
|
||||
.map(PendingTradesListItem::new)
|
||||
.map(trade -> new PendingTradesListItem(trade, btcFormatter))
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
// we sort by date, earliest first
|
||||
|
|
|
@ -17,39 +17,69 @@
|
|||
|
||||
package bisq.desktop.main.portfolio.pendingtrades;
|
||||
|
||||
import bisq.core.monetary.Price;
|
||||
import bisq.core.monetary.Volume;
|
||||
import bisq.desktop.util.filtering.FilterableListItem;
|
||||
|
||||
import bisq.core.trade.model.bisq_v1.Trade;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static bisq.core.locale.CurrencyUtil.getCurrencyPair;
|
||||
|
||||
/**
|
||||
* We could remove that wrapper if it is not needed for additional UI only fields.
|
||||
*/
|
||||
public class PendingTradesListItem {
|
||||
|
||||
public class PendingTradesListItem implements FilterableListItem {
|
||||
public static final Logger log = LoggerFactory.getLogger(PendingTradesListItem.class);
|
||||
private final CoinFormatter btcFormatter;
|
||||
private final Trade trade;
|
||||
|
||||
public PendingTradesListItem(Trade trade) {
|
||||
public PendingTradesListItem(Trade trade, CoinFormatter btcFormatter) {
|
||||
this.trade = trade;
|
||||
this.btcFormatter = btcFormatter;
|
||||
}
|
||||
|
||||
public Trade getTrade() {
|
||||
return trade;
|
||||
}
|
||||
|
||||
public ReadOnlyObjectProperty<Coin> tradeAmountProperty() {
|
||||
return trade.amountProperty();
|
||||
public String getPriceAsString() {
|
||||
return FormattingUtils.formatPrice(trade.getPrice());
|
||||
}
|
||||
|
||||
public ReadOnlyObjectProperty<Volume> tradeVolumeProperty() {
|
||||
return trade.volumeProperty();
|
||||
public String getAmountAsString() {
|
||||
return btcFormatter.formatCoin(trade.getAmount());
|
||||
}
|
||||
|
||||
public Price getPrice() {
|
||||
return trade.getPrice();
|
||||
public String getPaymentMethod() {
|
||||
return trade.getOffer().getPaymentMethodNameWithCountryCode();
|
||||
}
|
||||
|
||||
public String getMarketDescription() {
|
||||
return getCurrencyPair(trade.getOffer().getCurrencyCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean match(String filterString) {
|
||||
if (filterString.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getTrade().getId(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getAmountAsString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getPaymentMethod(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(getMarketDescription(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
return StringUtils.containsIgnoreCase(getPriceAsString(), filterString);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,12 +21,13 @@
|
|||
<?import javafx.scene.control.TableView?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import bisq.desktop.components.list.FilterBox?>
|
||||
<VBox fx:id="root" fx:controller="bisq.desktop.main.portfolio.pendingtrades.PendingTradesView"
|
||||
spacing="20" xmlns:fx="http://javafx.com/fxml">
|
||||
<padding>
|
||||
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0"/>
|
||||
</padding>
|
||||
|
||||
<FilterBox fx:id="filterBox" />
|
||||
<TableView fx:id="tableView" VBox.vgrow="SOMETIMES">
|
||||
<columns>
|
||||
<TableColumn fx:id="tradeIdColumn" minWidth="100"/>
|
||||
|
|
|
@ -23,6 +23,7 @@ import bisq.desktop.common.view.FxmlView;
|
|||
import bisq.desktop.components.AutoTooltipLabel;
|
||||
import bisq.desktop.components.HyperlinkWithIcon;
|
||||
import bisq.desktop.components.PeerInfoIconTrading;
|
||||
import bisq.desktop.components.list.FilterBox;
|
||||
import bisq.desktop.main.MainView;
|
||||
import bisq.desktop.main.overlays.popups.Popup;
|
||||
import bisq.desktop.main.overlays.windows.TradeDetailsWindow;
|
||||
|
@ -42,9 +43,7 @@ import bisq.core.support.traderchat.TraderChatManager;
|
|||
import bisq.core.trade.model.bisq_v1.Contract;
|
||||
import bisq.core.trade.model.bisq_v1.Trade;
|
||||
import bisq.core.user.Preferences;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.VolumeUtil;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
|
||||
|
@ -102,6 +101,7 @@ import javafx.event.EventHandler;
|
|||
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.collections.transformation.FilteredList;
|
||||
import javafx.collections.transformation.SortedList;
|
||||
|
||||
import javafx.util.Callback;
|
||||
|
@ -119,16 +119,18 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
private final TradeDetailsWindow tradeDetailsWindow;
|
||||
private final Navigation navigation;
|
||||
private final KeyRing keyRing;
|
||||
private final CoinFormatter formatter;
|
||||
private final PrivateNotificationManager privateNotificationManager;
|
||||
private final boolean useDevPrivilegeKeys;
|
||||
private final boolean useDevModeHeader;
|
||||
private final Preferences preferences;
|
||||
@FXML
|
||||
FilterBox filterBox;
|
||||
@FXML
|
||||
TableView<PendingTradesListItem> tableView;
|
||||
@FXML
|
||||
TableColumn<PendingTradesListItem, PendingTradesListItem> priceColumn, volumeColumn, amountColumn, avatarColumn,
|
||||
marketColumn, roleColumn, paymentMethodColumn, tradeIdColumn, dateColumn, chatColumn, moveTradeToFailedColumn;
|
||||
private FilteredList<PendingTradesListItem> filteredList;
|
||||
private SortedList<PendingTradesListItem> sortedList;
|
||||
private TradeSubView selectedSubView;
|
||||
private EventHandler<KeyEvent> keyEventEventHandler;
|
||||
|
@ -161,7 +163,6 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
TradeDetailsWindow tradeDetailsWindow,
|
||||
Navigation navigation,
|
||||
KeyRing keyRing,
|
||||
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter,
|
||||
PrivateNotificationManager privateNotificationManager,
|
||||
Preferences preferences,
|
||||
@Named(Config.USE_DEV_PRIVILEGE_KEYS) boolean useDevPrivilegeKeys,
|
||||
|
@ -170,7 +171,6 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
this.tradeDetailsWindow = tradeDetailsWindow;
|
||||
this.navigation = navigation;
|
||||
this.keyRing = keyRing;
|
||||
this.formatter = formatter;
|
||||
this.privateNotificationManager = privateNotificationManager;
|
||||
this.preferences = preferences;
|
||||
this.useDevPrivilegeKeys = useDevPrivilegeKeys;
|
||||
|
@ -211,14 +211,14 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
dateColumn.setComparator(Comparator.comparing(o -> o.getTrade().getDate()));
|
||||
volumeColumn.setComparator(Comparator.comparing(o -> o.getTrade().getVolume(), Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
amountColumn.setComparator(Comparator.comparing(o -> o.getTrade().getAmount(), Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
priceColumn.setComparator(Comparator.comparing(item -> FormattingUtils.formatPrice(item.getPrice())));
|
||||
priceColumn.setComparator(Comparator.comparing(PendingTradesListItem::getPriceAsString));
|
||||
paymentMethodColumn.setComparator(Comparator.comparing(
|
||||
item -> item.getTrade().getOffer() != null ?
|
||||
Res.get(item.getTrade().getOffer().getPaymentMethod().getId()) :
|
||||
null,
|
||||
Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
|
||||
marketColumn.setComparator(Comparator.comparing(model::getMarketLabel));
|
||||
marketColumn.setComparator(Comparator.comparing(PendingTradesListItem::getMarketDescription));
|
||||
roleColumn.setComparator(Comparator.comparing(model::getMyRole));
|
||||
avatarColumn.setComparator(Comparator.comparing(
|
||||
o -> model.getNumPastTrades(o.getTrade()),
|
||||
|
@ -281,10 +281,14 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
@Override
|
||||
protected void activate() {
|
||||
ObservableList<PendingTradesListItem> list = model.dataModel.list;
|
||||
sortedList = new SortedList<>(list);
|
||||
filteredList = new FilteredList<>(list);
|
||||
sortedList = new SortedList<>(filteredList);
|
||||
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
||||
tableView.setItems(sortedList);
|
||||
|
||||
filterBox.initialize(filteredList, tableView); // here because filteredList is instantiated here
|
||||
filterBox.activate();
|
||||
|
||||
updateMoveTradeToFailedColumnState();
|
||||
|
||||
scene = root.getScene();
|
||||
|
@ -303,10 +307,10 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
|
||||
selectedSubView.setMinHeight(440);
|
||||
VBox.setVgrow(selectedSubView, Priority.ALWAYS);
|
||||
if (root.getChildren().size() == 1)
|
||||
if (root.getChildren().size() == 2)
|
||||
root.getChildren().add(selectedSubView);
|
||||
else if (root.getChildren().size() == 2)
|
||||
root.getChildren().set(1, selectedSubView);
|
||||
else if (root.getChildren().size() == 3)
|
||||
root.getChildren().set(2, selectedSubView);
|
||||
|
||||
// create and register a callback so we can be notified when the subview
|
||||
// wants to open the chat window
|
||||
|
@ -340,6 +344,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
filterBox.deactivate();
|
||||
sortedList.comparatorProperty().unbind();
|
||||
selectedItemSubscription.unsubscribe();
|
||||
selectedTableItemSubscription.unsubscribe();
|
||||
|
@ -683,7 +688,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
public void updateItem(final PendingTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null && !empty)
|
||||
setGraphic(new AutoTooltipLabel(formatter.formatCoin(item.getTrade().getAmount())));
|
||||
setGraphic(new AutoTooltipLabel(item.getAmountAsString()));
|
||||
else
|
||||
setGraphic(null);
|
||||
}
|
||||
|
@ -704,7 +709,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
public void updateItem(final PendingTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null && !empty)
|
||||
setGraphic(new AutoTooltipLabel(FormattingUtils.formatPrice(item.getPrice())));
|
||||
setGraphic(new AutoTooltipLabel(item.getPriceAsString()));
|
||||
else
|
||||
setGraphic(null);
|
||||
}
|
||||
|
@ -751,7 +756,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
public void updateItem(final PendingTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null && !empty)
|
||||
setGraphic(new AutoTooltipLabel(model.getPaymentMethod(item)));
|
||||
setGraphic(new AutoTooltipLabel(item.getPaymentMethod()));
|
||||
else
|
||||
setGraphic(null);
|
||||
}
|
||||
|
@ -771,7 +776,12 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
@Override
|
||||
public void updateItem(final PendingTradesListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
setGraphic(new AutoTooltipLabel(model.getMarketLabel(item)));
|
||||
|
||||
if (item != null && !empty) {
|
||||
setGraphic(new AutoTooltipLabel(item.getMarketDescription()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -245,16 +245,6 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
|||
return sellerState;
|
||||
}
|
||||
|
||||
public String getPayoutAmount() {
|
||||
return dataModel.getTrade() != null
|
||||
? btcFormatter.formatCoinWithCode(dataModel.getTrade().getPayoutAmount())
|
||||
: "";
|
||||
}
|
||||
|
||||
String getMarketLabel(PendingTradesListItem item) {
|
||||
return item == null ? "" : tradeUtil.getMarketDescription(item.getTrade());
|
||||
}
|
||||
|
||||
public String getRemainingTradeDurationAsWords() {
|
||||
checkNotNull(dataModel.getTrade(), "model's trade must not be null");
|
||||
return tradeUtil.getRemainingTradeDurationAsWords(dataModel.getTrade());
|
||||
|
@ -297,10 +287,6 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
|||
}
|
||||
}
|
||||
|
||||
String getPaymentMethod(PendingTradesListItem item) {
|
||||
return item == null ? "" : tradeUtil.getPaymentMethodNameWithCountryCode(item.getTrade());
|
||||
}
|
||||
|
||||
// summary
|
||||
public String getTradeVolume() {
|
||||
return dataModel.getTrade() != null
|
||||
|
|
|
@ -15,26 +15,8 @@
|
|||
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package bisq.desktop.main.funds.transactions;
|
||||
package bisq.desktop.util.filtering;
|
||||
|
||||
import bisq.core.trade.model.Tradable;
|
||||
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
||||
class DummyTransactionAwareTradable implements TransactionAwareTradable {
|
||||
private final Tradable delegate;
|
||||
|
||||
DummyTransactionAwareTradable(Tradable delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRelatedToTransaction(Transaction transaction) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tradable asTradable() {
|
||||
return delegate;
|
||||
}
|
||||
public interface FilterableListItem {
|
||||
boolean match(String filterString);
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* 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.util.filtering;
|
||||
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.trade.model.bisq_v1.Contract;
|
||||
import bisq.core.trade.model.bisq_v1.Trade;
|
||||
import bisq.core.trade.model.bsq_swap.BsqSwapTrade;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
public class FilteringUtils {
|
||||
public static boolean match(Offer offer, String filterString) {
|
||||
if (StringUtils.containsIgnoreCase(offer.getId(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.containsIgnoreCase(offer.getPaymentMethod().getDisplayString(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
return offer.getOfferFeePaymentTxId() != null && StringUtils.containsIgnoreCase(offer.getOfferFeePaymentTxId(), filterString);
|
||||
}
|
||||
|
||||
public static boolean match(BsqSwapTrade bsqSwapTrade, String filterString) {
|
||||
if (bsqSwapTrade.getTxId() != null && StringUtils.containsIgnoreCase(bsqSwapTrade.getTxId(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
return StringUtils.containsIgnoreCase(bsqSwapTrade.getTradingPeerNodeAddress().getFullAddress(), filterString);
|
||||
}
|
||||
|
||||
public static boolean match(Trade trade, String filterString) {
|
||||
if (trade == null) {
|
||||
return false;
|
||||
}
|
||||
if (trade.getTakerFeeTxId() != null && StringUtils.containsIgnoreCase(trade.getTakerFeeTxId(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (trade.getDepositTxId() != null && StringUtils.containsIgnoreCase(trade.getDepositTxId(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (trade.getPayoutTxId() != null && StringUtils.containsIgnoreCase(trade.getPayoutTxId(), filterString)) {
|
||||
return true;
|
||||
}
|
||||
return match(trade.getContract(), filterString);
|
||||
}
|
||||
|
||||
private static boolean match(Contract contract, String filterString) {
|
||||
boolean isBuyerOnion = false;
|
||||
boolean isSellerOnion = false;
|
||||
boolean matchesBuyersPaymentAccountData = false;
|
||||
boolean matchesSellersPaymentAccountData = false;
|
||||
if (contract != null) {
|
||||
isBuyerOnion = StringUtils.containsIgnoreCase(contract.getBuyerNodeAddress().getFullAddress(), filterString);
|
||||
isSellerOnion = StringUtils.containsIgnoreCase(contract.getSellerNodeAddress().getFullAddress(), filterString);
|
||||
matchesBuyersPaymentAccountData = contract.getBuyerPaymentAccountPayload() != null &&
|
||||
StringUtils.containsIgnoreCase(contract.getBuyerPaymentAccountPayload().getPaymentDetails(), filterString);
|
||||
matchesSellersPaymentAccountData = contract.getSellerPaymentAccountPayload() != null &&
|
||||
StringUtils.containsIgnoreCase(contract.getSellerPaymentAccountPayload().getPaymentDetails(), filterString);
|
||||
}
|
||||
return isBuyerOnion || isSellerOnion ||
|
||||
matchesBuyersPaymentAccountData || matchesSellersPaymentAccountData;
|
||||
}
|
||||
}
|
|
@ -5,10 +5,7 @@ import bisq.desktop.common.view.CachingViewLoader;
|
|||
import bisq.desktop.common.view.ViewLoader;
|
||||
import bisq.desktop.common.view.guice.InjectorViewFactory;
|
||||
import bisq.desktop.main.dao.bonding.BondingViewUtils;
|
||||
import bisq.desktop.main.funds.transactions.DisplayedTransactionsFactory;
|
||||
import bisq.desktop.main.funds.transactions.TradableRepository;
|
||||
import bisq.desktop.main.funds.transactions.TransactionAwareTradableFactory;
|
||||
import bisq.desktop.main.funds.transactions.TransactionListItemFactory;
|
||||
import bisq.desktop.main.offer.offerbook.OfferBook;
|
||||
import bisq.desktop.main.overlays.notifications.NotificationCenter;
|
||||
import bisq.desktop.main.overlays.windows.TorNetworkSettingsWindow;
|
||||
|
@ -99,9 +96,6 @@ public class GuiceSetupTest {
|
|||
assertSingleton(DaoPresentation.class);
|
||||
assertSingleton(Transitions.class);
|
||||
assertSingleton(TradableRepository.class);
|
||||
assertSingleton(TransactionListItemFactory.class);
|
||||
assertSingleton(TransactionAwareTradableFactory.class);
|
||||
assertSingleton(DisplayedTransactionsFactory.class);
|
||||
assertSingleton(BondingViewUtils.class);
|
||||
|
||||
// core module
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
* 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.funds.transactions;
|
||||
|
||||
import bisq.core.btc.wallet.BtcWalletService;
|
||||
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
public class DisplayedTransactionsTest {
|
||||
@Test
|
||||
public void testUpdate() {
|
||||
Set<Transaction> transactions = Sets.newHashSet(mock(Transaction.class), mock(Transaction.class));
|
||||
|
||||
BtcWalletService walletService = mock(BtcWalletService.class);
|
||||
when(walletService.getTransactions(false)).thenReturn(transactions);
|
||||
|
||||
TransactionListItemFactory transactionListItemFactory = mock(TransactionListItemFactory.class,
|
||||
RETURNS_DEEP_STUBS);
|
||||
|
||||
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
|
||||
DisplayedTransactions testedEntity = new DisplayedTransactions(
|
||||
walletService,
|
||||
mock(TradableRepository.class),
|
||||
transactionListItemFactory,
|
||||
mock(TransactionAwareTradableFactory.class));
|
||||
|
||||
testedEntity.update();
|
||||
|
||||
assertEquals(transactions.size(), testedEntity.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWhenRepositoryIsEmpty() {
|
||||
BtcWalletService walletService = mock(BtcWalletService.class);
|
||||
when(walletService.getTransactions(false))
|
||||
.thenReturn(Collections.singleton(mock(Transaction.class)));
|
||||
|
||||
TradableRepository tradableRepository = mock(TradableRepository.class);
|
||||
when(tradableRepository.getAll()).thenReturn(FXCollections.emptyObservableSet());
|
||||
|
||||
TransactionListItemFactory transactionListItemFactory = mock(TransactionListItemFactory.class);
|
||||
|
||||
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
|
||||
DisplayedTransactions testedEntity = new DisplayedTransactions(
|
||||
walletService,
|
||||
tradableRepository,
|
||||
transactionListItemFactory,
|
||||
mock(TransactionAwareTradableFactory.class));
|
||||
|
||||
testedEntity.update();
|
||||
|
||||
assertEquals(1, testedEntity.size());
|
||||
verify(transactionListItemFactory).create(any(), nullable(TransactionAwareTradable.class));
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* 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.funds.transactions;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
public class ObservableListDecoratorTest {
|
||||
@Test
|
||||
public void testSetAll() {
|
||||
ObservableListDecorator<Integer> list = new ObservableListDecorator<>();
|
||||
Collection<Integer> state = Lists.newArrayList(3, 2, 1);
|
||||
list.setAll(state);
|
||||
assertEquals(state, list);
|
||||
|
||||
state = Lists.newArrayList(0, 0, 0, 0);
|
||||
list.setAll(state);
|
||||
assertEquals(state, list);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForEach() {
|
||||
ObservableListDecorator<Supplier> list = new ObservableListDecorator<>();
|
||||
Collection<Supplier> state = Lists.newArrayList(mock(Supplier.class), mock(Supplier.class));
|
||||
list.setAll(state);
|
||||
assertEquals(state, list);
|
||||
|
||||
list.forEach(Supplier::get);
|
||||
|
||||
state.forEach(supplier -> verify(supplier).get());
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* 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.funds.transactions;
|
||||
|
||||
import bisq.core.offer.OpenOffer;
|
||||
import bisq.core.support.dispute.arbitration.ArbitrationManager;
|
||||
import bisq.core.trade.model.Tradable;
|
||||
import bisq.core.trade.model.bisq_v1.Trade;
|
||||
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
public class TransactionAwareTradableFactoryTest {
|
||||
@Test
|
||||
public void testCreateWhenNotOpenOfferOrTrade() {
|
||||
ArbitrationManager arbitrationManager = mock(ArbitrationManager.class);
|
||||
|
||||
TransactionAwareTradableFactory factory = new TransactionAwareTradableFactory(arbitrationManager,
|
||||
null, null, null);
|
||||
|
||||
Tradable delegate = mock(Tradable.class);
|
||||
assertFalse(delegate instanceof OpenOffer);
|
||||
assertFalse(delegate instanceof Trade);
|
||||
|
||||
TransactionAwareTradable tradable = factory.create(delegate);
|
||||
|
||||
assertFalse(tradable.isRelatedToTransaction(mock(Transaction.class)));
|
||||
}
|
||||
}
|
|
@ -45,8 +45,6 @@ public class TransactionAwareTradeTest {
|
|||
private ArbitrationManager arbitrationManager;
|
||||
private Trade delegate;
|
||||
private TransactionAwareTradable trade;
|
||||
private RefundManager refundManager;
|
||||
private BtcWalletService btcWalletService;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
@ -55,8 +53,8 @@ public class TransactionAwareTradeTest {
|
|||
|
||||
delegate = mock(Trade.class, RETURNS_DEEP_STUBS);
|
||||
arbitrationManager = mock(ArbitrationManager.class, RETURNS_DEEP_STUBS);
|
||||
refundManager = mock(RefundManager.class, RETURNS_DEEP_STUBS);
|
||||
btcWalletService = mock(BtcWalletService.class, RETURNS_DEEP_STUBS);
|
||||
RefundManager refundManager = mock(RefundManager.class, RETURNS_DEEP_STUBS);
|
||||
BtcWalletService btcWalletService = mock(BtcWalletService.class, RETURNS_DEEP_STUBS);
|
||||
trade = new TransactionAwareTrade(delegate, arbitrationManager, refundManager, btcWalletService, null);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue