Merge branch 'master' into 04-add-sendbtc-impl

This commit is contained in:
ghubstan 2020-12-09 10:44:17 -03:00
commit 144c5a82cc
No known key found for this signature in database
GPG key ID: E35592D6800A861E
27 changed files with 250 additions and 183 deletions

View file

@ -1030,6 +1030,7 @@ public abstract class Trade implements Tradable, Model {
return offer.getOfferFeePaymentTxId() == null ||
getTakerFeeTxId() == null ||
getDepositTxId() == null ||
getDepositTx() == null ||
getDelayedPayoutTxBytes() == null;
}

View file

@ -65,7 +65,7 @@ public class F2FForm extends PaymentMethodForm {
addCompactTopLabelTextFieldWithCopyIcon(gridPane, ++gridRow, Res.get("payment.f2f.contact"),
f2fAccountPayload.getContact());
TextArea textArea = addTopLabelTextArea(gridPane, gridRow, 1, Res.get("payment.f2f.extra"), "").second;
textArea.setPrefHeight(60);
textArea.setMinHeight(70);
textArea.setEditable(false);
textArea.setId("text-area-disabled");
textArea.setText(offer.getF2FExtraInfo());
@ -110,7 +110,7 @@ public class F2FForm extends PaymentMethodForm {
TextArea extraTextArea = addTopLabelTextArea(gridPane, ++gridRow,
Res.get("payment.f2f.optionalExtra"), Res.get("payment.f2f.extra.prompt")).second;
extraTextArea.setPrefHeight(60);
extraTextArea.setMinHeight(70);
((JFXTextArea) extraTextArea).setLabelFloat(false);
//extraTextArea.setValidator(f2fValidator);
extraTextArea.textProperty().addListener((ov, oldValue, newValue) -> {
@ -165,7 +165,7 @@ public class F2FForm extends PaymentMethodForm {
f2fAccount.getCity());
TextArea textArea = addCompactTopLabelTextArea(gridPane, ++gridRow, Res.get("payment.f2f.extra"), "").second;
textArea.setText(f2fAccount.getExtraInfo());
textArea.setPrefHeight(60);
textArea.setMinHeight(70);
textArea.setEditable(false);
addLimitations(true);

View file

@ -47,7 +47,7 @@ public class USPostalMoneyOrderForm extends PaymentMethodForm {
addCompactTopLabelTextFieldWithCopyIcon(gridPane, ++gridRow, Res.get("payment.account.owner"),
((USPostalMoneyOrderAccountPayload) paymentAccountPayload).getHolderName());
TextArea textArea = addCompactTopLabelTextArea(gridPane, ++gridRow, Res.get("payment.postal.address"), "").second;
textArea.setPrefHeight(70);
textArea.setMinHeight(70);
textArea.setEditable(false);
textArea.setId("text-area-disabled");
textArea.setText(((USPostalMoneyOrderAccountPayload) paymentAccountPayload).getPostalAddress());
@ -76,7 +76,7 @@ public class USPostalMoneyOrderForm extends PaymentMethodForm {
postalAddressTextArea = addTopLabelTextArea(gridPane, ++gridRow,
Res.get("payment.postal.address"), "").second;
postalAddressTextArea.setPrefHeight(70);
postalAddressTextArea.setMinHeight(70);
//postalAddressTextArea.setValidator(usPostalMoneyOrderValidator);
postalAddressTextArea.textProperty().addListener((ov, oldValue, newValue) -> {
usPostalMoneyOrderAccount.setPostalAddress(newValue);
@ -108,7 +108,7 @@ public class USPostalMoneyOrderForm extends PaymentMethodForm {
usPostalMoneyOrderAccount.getHolderName());
TextArea textArea = addCompactTopLabelTextArea(gridPane, ++gridRow, Res.get("payment.postal.address"), "").second;
textArea.setText(usPostalMoneyOrderAccount.getPostalAddress());
textArea.setPrefHeight(70);
textArea.setMinHeight(70);
textArea.setEditable(false);
TradeCurrency singleTradeCurrency = usPostalMoneyOrderAccount.getSingleTradeCurrency();
String nameAndCode = singleTradeCurrency != null ? singleTradeCurrency.getNameAndCode() : "null";

View file

@ -157,4 +157,8 @@ class AltCoinAccountsDataModel extends ActivatableDataModel {
public void importAccounts(Stage stage) {
GUIUtil.importAccounts(user, accountsFileName, preferences, stage, persistenceProtoResolver, corruptedStorageFileHandler);
}
public int getNumPaymentAccounts() {
return user.getPaymentAccounts() != null ? user.getPaymentAccounts().size() : 0;
}
}

View file

@ -31,6 +31,6 @@
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0"/>
</padding>
<columnConstraints>
<ColumnConstraints hgrow="NEVER" minWidth="300.0"/>
<ColumnConstraints hgrow="ALWAYS" minWidth="300.0"/>
</columnConstraints>
</GridPane>

View file

@ -177,7 +177,8 @@ public class AltCoinAccountsView extends PaymentAccountsView<GridPane, AltCoinAc
Tuple3<Label, ListView<PaymentAccount>, VBox> tuple = addTopLabelListView(root, gridRow, Res.get("account.altcoin.yourAltcoinAccounts"), Layout.FIRST_ROW_DISTANCE);
paymentAccountsListView = tuple.second;
paymentAccountsListView.setMinHeight(2 * Layout.LIST_ROW_HEIGHT + 14);
int prefNumRows = Math.min(4, Math.max(2, model.dataModel.getNumPaymentAccounts()));
paymentAccountsListView.setMinHeight(prefNumRows * Layout.LIST_ROW_HEIGHT + 28);
setPaymentAccountsCellFactory();
Tuple3<Button, Button, Button> tuple3 = add3ButtonsAfterGroup(root, ++gridRow, Res.get("shared.addNewAccount"),

View file

@ -160,4 +160,8 @@ class FiatAccountsDataModel extends ActivatableDataModel {
public void importAccounts(Stage stage) {
GUIUtil.importAccounts(user, accountsFileName, preferences, stage, persistenceProtoResolver, corruptedStorageFileHandler);
}
public int getNumPaymentAccounts() {
return user.getPaymentAccounts() != null ? user.getPaymentAccounts().size() : 0;
}
}

View file

@ -362,7 +362,8 @@ public class FiatAccountsView extends PaymentAccountsView<GridPane, FiatAccounts
Tuple3<Label, ListView<PaymentAccount>, VBox> tuple = addTopLabelListView(root, gridRow, Res.get("account.fiat.yourFiatAccounts"), Layout.FIRST_ROW_DISTANCE);
paymentAccountsListView = tuple.second;
paymentAccountsListView.setMinHeight(2 * Layout.LIST_ROW_HEIGHT + 14);
int prefNumRows = Math.min(4, Math.max(2, model.dataModel.getNumPaymentAccounts()));
paymentAccountsListView.setMinHeight(prefNumRows * Layout.LIST_ROW_HEIGHT + 28);
setPaymentAccountsCellFactory();
Tuple3<Button, Button, Button> tuple3 = add3ButtonsAfterGroup(root, ++gridRow, Res.get("shared.addNewAccount"),

View file

@ -169,7 +169,6 @@ public class BondsView extends ActivatableView<GridPane, Void> {
column = new AutoTooltipTableColumn<>(Res.get("shared.amountWithCur", "BSQ"));
column.setMinWidth(80);
column.getStyleClass().add("first-column");
column.setComparator(Comparator.comparingLong(v -> v.getBond().getAmount()));
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setCellFactory(new Callback<>() {
@Override
@ -191,7 +190,6 @@ public class BondsView extends ActivatableView<GridPane, Void> {
column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.lockTime"));
column.setMinWidth(40);
column.setComparator(Comparator.comparingInt(v -> v.getBond().getLockTime()));
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setCellFactory(new Callback<>() {
@Override
@ -294,7 +292,6 @@ public class BondsView extends ActivatableView<GridPane, Void> {
column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.lockupDate"));
column.setMinWidth(140);
column.setComparator(Comparator.comparingLong(v -> v.getBond().getLockupDate()));
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setCellFactory(new Callback<>() {
@Override

View file

@ -170,6 +170,10 @@ public class ProposalsListItem {
}
}
public String getProposalTypeAsString() {
return Res.get("dao.proposal.type." + proposal.getType().name());
}
private String getNext(IconButtonType iconButtonType) {
switch (iconButtonType) {
case ACCEPT:

View file

@ -786,7 +786,7 @@ public class ProposalsView extends ActivatableView<GridPane, Void> implements Bs
public void updateItem(final ProposalsListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
final Proposal proposal = item.getProposal();
Proposal proposal = item.getProposal();
field = new HyperlinkWithIcon(proposal.getLink());
field.setOnAction(event -> GUIUtil.openWebPage(proposal.getLink()));
field.setTooltip(new Tooltip(proposal.getLink()));
@ -800,7 +800,7 @@ public class ProposalsView extends ActivatableView<GridPane, Void> implements Bs
};
}
});
column.setComparator(Comparator.comparing(o -> o.getProposal().getTxId()));
column.setComparator(Comparator.comparing(o -> o.getProposal().getLink()));
tableView.getColumns().add(column);
@ -817,14 +817,14 @@ public class ProposalsView extends ActivatableView<GridPane, Void> implements Bs
public void updateItem(final ProposalsListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null)
setText(Res.get("dao.proposal.type." + item.getProposal().getType().name()));
setText(item.getProposalTypeAsString());
else
setText("");
}
};
}
});
column.setComparator(Comparator.comparing(o2 -> o2.getProposal().getName()));
column.setComparator(Comparator.comparing(ProposalsListItem::getProposalTypeAsString));
tableView.getColumns().add(column);
@ -886,6 +886,7 @@ public class ProposalsView extends ActivatableView<GridPane, Void> implements Bs
};
}
});
column.setComparator(Comparator.comparing(item -> ((ProposalsListItem.IconButtonType) item.getIconButton().getUserData()).getTitle()));
tableView.getColumns().add(column);
lastColumn = column;
}

View file

@ -596,7 +596,7 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements D
};
}
});
column.setComparator(Comparator.comparing(CycleListItem::getNumProposals));
column.setComparator(Comparator.comparing(CycleListItem::getNumVotesAsString));
votesTableView.getColumns().add(column);
column = new AutoTooltipTableColumn<>(Res.get("dao.results.cycles.table.header.voteWeight"));
@ -619,7 +619,7 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements D
};
}
});
column.setComparator(Comparator.comparing(CycleListItem::getNumProposals));
column.setComparator(Comparator.comparing(CycleListItem::getMeritAndStake));
votesTableView.getColumns().add(column);
column = new AutoTooltipTableColumn<>(Res.get("dao.results.cycles.table.header.issuance"));
@ -643,7 +643,7 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements D
};
}
});
column.setComparator(Comparator.comparing(CycleListItem::getNumProposals));
column.setComparator(Comparator.comparing(CycleListItem::getIssuance));
votesTableView.getColumns().add(column);
}
@ -676,7 +676,7 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements D
};
}
});
column.setComparator(Comparator.comparing(o3 -> o3.getProposal().getCreationDateAsDate()));
column.setComparator(Comparator.comparing(item -> item.getProposal().getCreationDateAsDate()));
column.setSortType(TableColumn.SortType.DESCENDING);
votesTableView.getColumns().add(column);
votesTableView.getSortOrder().add(column);
@ -721,7 +721,7 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements D
};
}
});
column.setComparator(Comparator.comparing((evaluatedProposal -> evaluatedProposal.getProposal().getName().toLowerCase())));
column.setComparator(Comparator.comparing((item -> item.getProposalOwnerName() + item.getProposal().getLink())));
votesTableView.getColumns().add(column);
@ -745,7 +745,7 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements D
};
}
});
column.setComparator(Comparator.comparing(o2 -> o2.getProposal().getType().getDisplayName()));
column.setComparator(Comparator.comparing(o2 -> o2.getProposal().getType().getShortDisplayName()));
votesTableView.getColumns().add(column);
@ -770,7 +770,7 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements D
}
});
// We sort by issued amount
column.setComparator(Comparator.comparing(ProposalListItem::getIssuedAmount));
column.setComparator(Comparator.comparing(ProposalListItem::getDetails));
votesTableView.getColumns().add(column);

View file

@ -256,7 +256,6 @@ public class LockedView extends ActivatableView<VBox, Void> {
if (item != null && !empty) {
Optional<Tradable> tradableOptional = getTradable(item);
AddressEntry addressEntry = item.getAddressEntry();
if (tradableOptional.isPresent()) {
field = new HyperlinkWithIcon(Res.get("funds.locked.locked", item.getTrade().getShortId()),
AwesomeIcon.INFO_SIGN);

View file

@ -42,13 +42,7 @@ import bisq.network.p2p.P2PService;
import bisq.common.util.Utilities;
import org.bitcoinj.core.TransactionConfidence;
import org.bitcoinj.core.listeners.TransactionConfidenceEventListener;
import org.bitcoinj.wallet.listeners.KeyChainEventListener;
import org.bitcoinj.wallet.listeners.ScriptsChangeEventListener;
import org.bitcoinj.wallet.listeners.WalletChangeEventListener;
import org.bitcoinj.wallet.listeners.WalletCoinsReceivedEventListener;
import org.bitcoinj.wallet.listeners.WalletCoinsSentEventListener;
import org.bitcoinj.wallet.listeners.WalletReorganizeEventListener;
import com.googlecode.jcsv.writer.CSVEntryConverter;
@ -155,14 +149,17 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
dateColumn.setComparator(Comparator.comparing(TransactionsListItem::getDate));
detailsColumn.setComparator((o1, o2) -> {
String id1 = o1.getTradable() != null ? o1.getTradable().getId() : o1.getDetails();
String id2 = o2.getTradable() != null ? o2.getTradable().getId() : o2.getDetails();
String id1 = !o1.getDetails().isEmpty() ? o1.getDetails() :
o1.getTradable() != null ? o1.getTradable().getId() : o1.getTxId();
String id2 = !o2.getDetails().isEmpty() ? o2.getDetails() :
o2.getTradable() != null ? o2.getTradable().getId() : o2.getTxId();
return id1.compareTo(id2);
});
addressColumn.setComparator(Comparator.comparing(TransactionsListItem::getAddressString));
addressColumn.setComparator(Comparator.comparing(item -> item.getDirection() + item.getAddressString()));
transactionColumn.setComparator(Comparator.comparing(TransactionsListItem::getTxId));
amountColumn.setComparator(Comparator.comparing(TransactionsListItem::getAmountAsCoin));
confidenceColumn.setComparator(Comparator.comparingDouble(item -> item.getTxConfidenceIndicator().getProgress()));
memoColumn.setComparator(Comparator.comparing(TransactionsListItem::getMemo));
dateColumn.setSortType(TableColumn.SortType.DESCENDING);
tableView.getSortOrder().add(dateColumn);
@ -428,7 +425,6 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
private void setMemoColumnCellFactory() {
memoColumn.setCellValueFactory((addressListItem) ->
new ReadOnlyObjectWrapper<>(addressListItem.getValue()));
memoColumn.setCellFactory(
new Callback<>() {

View file

@ -386,42 +386,41 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
seriesSell.getData().clear();
areaChart.getData().clear();
List<Double> leftMnMx, rightMnMx;
boolean isCrypto = CurrencyUtil.isCryptoCurrency(model.getCurrencyCode());
if (isCrypto) { // crypto: left-sell, right-buy,
leftMnMx = minMaxFilterLeft(model.getSellData());
rightMnMx = minMaxFilterRight(model.getBuyData());
} else { // fiat: left-buy, right-sell
leftMnMx = minMaxFilterLeft(model.getBuyData());
rightMnMx = minMaxFilterRight(model.getSellData());
}
double minValue = Double.min(leftMnMx.get(0).doubleValue(), rightMnMx.get(0).doubleValue());
double maxValue = Double.max(leftMnMx.get(1).doubleValue(), rightMnMx.get(1).doubleValue());
if (minValue == Double.MAX_VALUE || maxValue == Double.MIN_VALUE) { // no filtering
seriesBuy.getData().addAll(model.getBuyData());
seriesSell.getData().addAll(model.getSellData());
} else { // apply filtering
if (isCrypto) { // crypto: left-sell, right-buy
seriesBuy.getData().addAll(filterRight(model.getBuyData(), rightMnMx.get(0)));
seriesSell.getData().addAll(filterLeft(model.getSellData(), leftMnMx.get(1)));
} else { // fiat: left-buy, right-sell
seriesBuy.getData().addAll(filterLeft(model.getBuyData(), leftMnMx.get(1)));
seriesSell.getData().addAll(filterRight(model.getSellData(), rightMnMx.get(0)));
}
}
// crypto: left-sell, right-buy. fiat: left-buy, right-sell
seriesBuy.getData().addAll(filterOutliersBuy(model.getBuyData(), isCrypto));
seriesSell.getData().addAll(filterOutliersSell(model.getSellData(), isCrypto));
areaChart.getData().addAll(List.of(seriesBuy, seriesSell));
}
List<XYChart.Data<Number, Number>> filterOutliersBuy(List<XYChart.Data<Number, Number>> buy, boolean isCrypto) {
List<Double> mnmx = isCrypto ? minMaxFilterRight(buy) : minMaxFilterLeft(buy);
if (mnmx.get(0).doubleValue() == Double.MAX_VALUE ||
mnmx.get(1).doubleValue() == Double.MIN_VALUE) { // no filtering
return buy;
}
// apply filtering
return isCrypto ? filterRight(buy, mnmx.get(0)) : filterLeft(buy, mnmx.get(1));
}
List<XYChart.Data<Number, Number>> filterOutliersSell(List<XYChart.Data<Number, Number>> sell, boolean isCrypto) {
List<Double> mnmx = isCrypto ? minMaxFilterLeft(sell) : minMaxFilterRight(sell);
if (mnmx.get(0).doubleValue() == Double.MAX_VALUE ||
mnmx.get(1).doubleValue() == Double.MIN_VALUE) { // no filtering
return sell;
}
// apply filtering
return isCrypto ? filterLeft(sell, mnmx.get(1)) : filterRight(sell, mnmx.get(0));
}
private List<Double> minMaxFilterLeft(List<XYChart.Data<Number, Number>> data) {
double maxValue = data.stream()
.mapToDouble(o -> o.getXValue().doubleValue())
.max()
.orElse(Double.MIN_VALUE);
// Hide sell offers that are less than a div-factor of dataLimitFactor
// lower than the highest sell offer.
// Hide offers less than a div-factor of dataLimitFactor lower than the highest offer.
double minValue = data.stream()
.mapToDouble(o -> o.getXValue().doubleValue())
.filter(o -> o > maxValue / dataLimitFactor)
@ -436,8 +435,7 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
.min()
.orElse(Double.MAX_VALUE);
// Hide sell offers that are more than dataLimitFactor factor higher
// than the lowest sell offer
// Hide offers a dataLimitFactor factor higher than the lowest offer
double maxValue = data.stream()
.mapToDouble(o -> o.getXValue().doubleValue())
.filter(o -> o < minValue * dataLimitFactor)

View file

@ -33,7 +33,6 @@ import bisq.desktop.util.GUIUtil;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
import bisq.core.monetary.Price;
import bisq.core.monetary.Volume;
import bisq.core.trade.statistics.TradeStatistics3;
import bisq.core.util.FormattingUtils;
import bisq.core.util.coin.CoinFormatter;
@ -54,6 +53,7 @@ import com.jfoenix.controls.JFXTabPane;
import javafx.stage.Stage;
import javafx.scene.Node;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.control.ComboBox;
@ -72,7 +72,6 @@ import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.Node;
import javafx.scene.text.Text;
import javafx.geometry.Insets;
@ -741,7 +740,7 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
};
}
});
marketColumn.setComparator(Comparator.comparing(TradeStatistics3ListItem::getDate));
marketColumn.setComparator(Comparator.comparing(TradeStatistics3ListItem::getMarket));
tableView.getColumns().add(marketColumn);
// price
@ -814,11 +813,7 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
};
}
});
volumeColumn.setComparator((o1, o2) -> {
final Volume tradeVolume1 = o1.getTradeVolume();
final Volume tradeVolume2 = o2.getTradeVolume();
return tradeVolume1.compareTo(tradeVolume2);
});
volumeColumn.setComparator(Comparator.comparing(TradeStatistics3ListItem::getTradeVolume));
tableView.getColumns().add(volumeColumn);
// paymentMethod

View file

@ -122,7 +122,6 @@ import static bisq.desktop.util.FormBuilder.*;
import static javafx.beans.binding.Bindings.createStringBinding;
public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> extends ActivatableViewAndModel<AnchorPane, M> {
public static final String BUYER_SECURITY_DEPOSIT_NEWS = "buyerSecurityDepositNews0.9.5";
protected final Navigation navigation;
private final Preferences preferences;
private final OfferDetailsWindow offerDetailsWindow;
@ -136,8 +135,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
private BusyAnimation waitingForFundsSpinner;
private AutoTooltipButton nextButton, cancelButton1, cancelButton2, placeOfferButton;
private Button priceTypeToggleButton;
private InputTextField fixedPriceTextField;
private InputTextField marketBasedPriceTextField;
private InputTextField fixedPriceTextField, marketBasedPriceTextField;
protected InputTextField amountTextField, minAmountTextField, volumeTextField, buyerSecurityDepositInputTextField;
private TextField currencyTextField;
private AddressTextField addressTextField;
@ -155,7 +153,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
currencyTextFieldBox;
private HBox fundingHBox, firstRowHBox, secondRowHBox, placeOfferBox, amountValueCurrencyBox,
priceAsPercentageValueCurrencyBox, volumeValueCurrencyBox, priceValueCurrencyBox,
minAmountValueCurrencyBox, advancedOptionsBox, paymentGroupBox;
minAmountValueCurrencyBox, advancedOptionsBox;
private Subscription isWaitingForFundsSubscription, balanceSubscription;
private ChangeListener<Boolean> amountFocusedListener, minAmountFocusedListener, volumeFocusedListener,
@ -989,7 +987,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
paymentTitledGroupBg = addTitledGroupBg(gridPane, gridRow, 1, Res.get("shared.selectTradingAccount"));
GridPane.setColumnSpan(paymentTitledGroupBg, 2);
paymentGroupBox = new HBox();
HBox paymentGroupBox = new HBox();
paymentGroupBox.setAlignment(Pos.CENTER_LEFT);
paymentGroupBox.setSpacing(12);
paymentGroupBox.setPadding(new Insets(10, 0, 18, 0));
@ -1038,12 +1036,6 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
paymentGroupBox.getChildren().add(currencyTextFieldBox);
}
protected void hidePaymentGroup() {
paymentTitledGroupBg.setVisible(false);
paymentGroupBox.setManaged(false);
paymentGroupBox.setVisible(false);
}
private void addAmountPriceGroup() {
amountTitledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 2,
Res.get("createOffer.setAmountPrice"), Layout.COMPACT_GROUP_DISTANCE);

View file

@ -53,8 +53,6 @@ import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import static bisq.desktop.main.offer.MutableOfferView.BUYER_SECURITY_DEPOSIT_NEWS;
public abstract class OfferView extends ActivatableView<TabPane, Void> {
private OfferBookView offerBookView;
@ -273,8 +271,6 @@ public abstract class OfferView extends ActivatableView<TabPane, Void> {
offerBookView.enableCreateOfferButton();
navigation.navigateTo(MainView.class, this.getClass(), OfferBookView.class);
preferences.dontShowAgain(BUYER_SECURITY_DEPOSIT_NEWS, true);
}
private void onTakeOfferViewRemoved() {

View file

@ -244,14 +244,20 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
priceColumn.setComparator(Comparator.comparing(o -> o.getOffer().getPrice(), Comparator.nullsFirst(Comparator.naturalOrder())));
amountColumn.setComparator(Comparator.comparing(o -> o.getOffer().getMinAmount()));
volumeColumn.setComparator(Comparator.comparing(o -> o.getOffer().getMinVolume(), Comparator.nullsFirst(Comparator.naturalOrder())));
paymentMethodColumn.setComparator(Comparator.comparing(o -> o.getOffer().getPaymentMethod()));
avatarColumn.setComparator(Comparator.comparing(o -> o.getOffer().getOwnerNodeAddress().getFullAddress()));
depositColumn.setComparator(Comparator.comparing(o -> {
var isSellOffer = o.getOffer().getDirection() == OfferPayload.Direction.SELL;
var deposit = isSellOffer ? o.getOffer().getBuyerSecurityDeposit() :
o.getOffer().getSellerSecurityDeposit();
paymentMethodColumn.setComparator(Comparator.comparing(o -> Res.get(o.getOffer().getPaymentMethod().getId())));
avatarColumn.setComparator(Comparator.comparing(o -> model.getNumTrades(o.getOffer())));
depositColumn.setComparator(Comparator.comparing(item -> {
boolean isSellOffer = item.getOffer().getDirection() == OfferPayload.Direction.SELL;
Coin deposit = isSellOffer ?
item.getOffer().getBuyerSecurityDeposit() :
item.getOffer().getSellerSecurityDeposit();
return (deposit == null) ? 0.0 : deposit.getValue() / (double) o.getOffer().getAmount().getValue();
double amountValue = item.getOffer().getAmount().getValue();
if ((deposit == null || amountValue == 0)) {
return 0d;
} else {
return deposit.getValue() / amountValue;
}
}, Comparator.nullsFirst(Comparator.naturalOrder())));

View file

@ -19,6 +19,7 @@ package bisq.desktop.main.overlays.windows;
import bisq.desktop.components.BisqTextArea;
import bisq.desktop.components.TextFieldWithCopyIcon;
import bisq.desktop.components.TxIdTextField;
import bisq.desktop.main.MainView;
import bisq.desktop.main.overlays.Overlay;
import bisq.desktop.util.DisplayUtils;
@ -285,9 +286,17 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
addLabelTxIdTextField(gridPane, ++rowIndex, Res.get("shared.makerFeeTxId"), offer.getOfferFeePaymentTxId());
addLabelTxIdTextField(gridPane, ++rowIndex, Res.get("shared.takerFeeTxId"), trade.getTakerFeeTxId());
String depositTxId = trade.getDepositTxId();
Transaction depositTx = trade.getDepositTx();
String depositTxString = depositTx != null ? depositTx.getTxId().toString() : null;
addLabelTxIdTextField(gridPane, ++rowIndex, Res.get("shared.depositTransactionId"), depositTxString);
String depositTxIdFromTx = depositTx != null ? depositTx.getTxId().toString() : null;
TxIdTextField depositTxIdTextField = addLabelTxIdTextField(gridPane, ++rowIndex,
Res.get("shared.depositTransactionId"), depositTxId).second;
if (depositTxId == null || !depositTxId.equals(depositTxIdFromTx)) {
depositTxIdTextField.getTextField().setId("address-text-field-error");
log.error("trade.getDepositTxId() and trade.getDepositTx().getTxId().toString() are not the same. " +
"trade.getDepositTxId()={}, trade.getDepositTx().getTxId().toString()={}, depositTx={}",
depositTxId, depositTxIdFromTx, depositTx);
}
Transaction delayedPayoutTx = trade.getDelayedPayoutTx(btcWalletService);
String delayedPayoutTxString = delayedPayoutTx != null ? delayedPayoutTx.getTxId().toString() : null;

View file

@ -41,10 +41,10 @@
<TableColumn fx:id="deviationColumn" minWidth="70"/>
<TableColumn fx:id="amountColumn" minWidth="110"/>
<TableColumn fx:id="volumeColumn" minWidth="110"/>
<TableColumn fx:id="txFeeColumn" visible="false"/>
<TableColumn fx:id="tradeFeeColumn" visible="false"/>
<TableColumn fx:id="buyerSecurityDepositColumn" visible="false"/>
<TableColumn fx:id="sellerSecurityDepositColumn" visible="false"/>
<TableColumn fx:id="txFeeColumn" visible="false" minWidth="75"/>
<TableColumn fx:id="tradeFeeColumn" visible="false" minWidth="110"/>
<TableColumn fx:id="buyerSecurityDepositColumn" visible="false" minWidth="75"/>
<TableColumn fx:id="sellerSecurityDepositColumn" visible="false" minWidth="75"/>
<TableColumn fx:id="directionColumn" minWidth="70"/>
<TableColumn fx:id="stateColumn" minWidth="80"/>
<TableColumn fx:id="avatarColumn" minWidth="40" maxWidth="40"/>

View file

@ -100,6 +100,7 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
ColumnNames(String text) {
this.text = text;
}
@Override
public String toString() {
return text;
@ -124,12 +125,13 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
AutoTooltipButton exportButton;
private final OfferDetailsWindow offerDetailsWindow;
private Preferences preferences;
private final Preferences preferences;
private final TradeDetailsWindow tradeDetailsWindow;
private final PrivateNotificationManager privateNotificationManager;
private SortedList<ClosedTradableListItem> sortedList;
private FilteredList<ClosedTradableListItem> filteredList;
private ChangeListener<String> filterTextFieldListener;
private ChangeListener<Number> widthListener;
@Inject
public ClosedTradesView(ClosedTradesViewModel model,
@ -148,6 +150,7 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
@Override
public void initialize() {
widthListener = (observable, oldValue, newValue) -> onWidthChange((double) newValue);
txFeeColumn.setGraphic(new AutoTooltipLabel(ColumnNames.TX_FEE.toString()));
tradeFeeColumn.setGraphic(new AutoTooltipLabel(ColumnNames.TRADE_FEE.toString()));
buyerSecurityDepositColumn.setGraphic(new AutoTooltipLabel(ColumnNames.BUYER_SEC.toString()));
@ -186,24 +189,31 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
dateColumn.setComparator(Comparator.comparing(o -> o.getTradable().getDate()));
directionColumn.setComparator(Comparator.comparing(o -> o.getTradable().getOffer().getDirection()));
marketColumn.setComparator(Comparator.comparing(model::getMarketLabel));
priceColumn.setComparator(nullsFirstComparing(o ->
o instanceof Trade ? ((Trade) o).getTradePrice() : o.getOffer().getPrice()
));
priceColumn.setComparator(Comparator.comparing(model::getPrice, Comparator.nullsFirst(Comparator.naturalOrder())));
deviationColumn.setComparator(Comparator.comparing(o ->
o.getTradable().getOffer().isUseMarketBasedPrice() ? o.getTradable().getOffer().getMarketPriceMargin() : 1,
Comparator.nullsFirst(Comparator.naturalOrder())));
volumeColumn.setComparator(nullsFirstComparingAsTrade(Trade::getTradeVolume));
amountColumn.setComparator(nullsFirstComparingAsTrade(Trade::getTradeAmount));
avatarColumn.setComparator(nullsFirstComparingAsTrade(o ->
o.getTradingPeerNodeAddress() != null ? o.getTradingPeerNodeAddress().getFullAddress() : null
amountColumn.setComparator(Comparator.comparing(model::getAmount, Comparator.nullsFirst(Comparator.naturalOrder())));
avatarColumn.setComparator(Comparator.comparing(
o -> model.getNumPastTrades(o.getTradable()),
Comparator.nullsFirst(Comparator.naturalOrder())
));
txFeeColumn.setComparator(nullsFirstComparing(o ->
o instanceof Trade ? ((Trade) o).getTxFee() : o.getOffer().getTxFee()
));
tradeFeeColumn.setComparator(nullsFirstComparing(o ->
o instanceof Trade ? ((Trade) o).getTakerFee() : o.getOffer().getMakerFee()
));
txFeeColumn.setComparator(Comparator.comparing(model::getTxFee, Comparator.nullsFirst(Comparator.naturalOrder())));
//
tradeFeeColumn.setComparator(Comparator.comparing(item -> {
String tradeFee = model.getTradeFee(item);
// We want to separate BSQ and BTC fees so we use a prefix
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
));
@ -225,20 +235,6 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
HBox.setMargin(exportButton, new Insets(0, 10, 0, 0));
}
private static <T extends Comparable<T>> Comparator<ClosedTradableListItem> nullsFirstComparing(Function<Tradable, T> keyExtractor) {
return Comparator.comparing(
o -> o.getTradable() != null ? keyExtractor.apply(o.getTradable()) : null,
Comparator.nullsFirst(Comparator.naturalOrder())
);
}
private static <T extends Comparable<T>> Comparator<ClosedTradableListItem> nullsFirstComparingAsTrade(Function<Trade, T> keyExtractor) {
return Comparator.comparing(
o -> o.getTradable() instanceof Trade ? keyExtractor.apply((Trade) o.getTradable()) : null,
Comparator.nullsFirst(Comparator.naturalOrder())
);
}
@Override
protected void activate() {
filteredList = new FilteredList<>(model.getList());
@ -267,7 +263,7 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
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.getMakerFee(item);
columns[ColumnNames.TRADE_FEE.ordinal()] = model.getTradeFee(item);
columns[ColumnNames.BUYER_SEC.ordinal()] = model.getBuyerSecurityDeposit(item);
columns[ColumnNames.SELLER_SEC.ordinal()] = model.getSellerSecurityDeposit(item);
columns[ColumnNames.OFFER_TYPE.ordinal()] = model.getDirectionLabel(item);
@ -281,6 +277,8 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
filterTextField.textProperty().addListener(filterTextFieldListener);
applyFilteredListPredicate(filterTextField.getText());
root.widthProperty().addListener(widthListener);
onWidthChange(root.getWidth());
}
@Override
@ -289,6 +287,29 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
exportButton.setOnAction(null);
filterTextField.textProperty().removeListener(filterTextFieldListener);
root.widthProperty().removeListener(widthListener);
}
private static <T extends Comparable<T>> Comparator<ClosedTradableListItem> nullsFirstComparing(Function<Tradable, T> keyExtractor) {
return Comparator.comparing(
o -> o.getTradable() != null ? keyExtractor.apply(o.getTradable()) : null,
Comparator.nullsFirst(Comparator.naturalOrder())
);
}
private static <T extends Comparable<T>> Comparator<ClosedTradableListItem> nullsFirstComparingAsTrade(Function<Trade, T> keyExtractor) {
return Comparator.comparing(
o -> o.getTradable() instanceof Trade ? keyExtractor.apply((Trade) o.getTradable()) : null,
Comparator.nullsFirst(Comparator.naturalOrder())
);
}
private void onWidthChange(double width) {
log.error("onWidthChange " + width);
txFeeColumn.setVisible(width > 1200);
tradeFeeColumn.setVisible(width > 1300);
buyerSecurityDepositColumn.setVisible(width > 1400);
sellerSecurityDepositColumn.setVisible(width > 1500);
}
private void applyFilteredListPredicate(String filterString) {
@ -583,7 +604,7 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
@Override
public void updateItem(final ClosedTradableListItem item, boolean empty) {
super.updateItem(item, empty);
setGraphic(new AutoTooltipLabel(model.getMakerFee(item)));
setGraphic(new AutoTooltipLabel(model.getTradeFee(item)));
}
};
}

View file

@ -22,14 +22,26 @@ import bisq.desktop.common.model.ViewModel;
import bisq.desktop.util.DisplayUtils;
import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
import bisq.core.offer.Offer;
import bisq.core.offer.OpenOffer;
import bisq.core.trade.Tradable;
import bisq.core.trade.Trade;
import bisq.core.util.FormattingUtils;
import bisq.core.util.coin.BsqFormatter;
import bisq.core.util.coin.CoinFormatter;
import bisq.network.p2p.NodeAddress;
import bisq.common.config.Config;
import org.bitcoinj.core.Address;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionOutput;
import com.google.inject.Inject;
import javax.inject.Named;
@ -39,16 +51,25 @@ import javafx.collections.ObservableList;
import java.util.stream.Collectors;
class ClosedTradesViewModel extends ActivatableWithDataModel<ClosedTradesDataModel> implements ViewModel {
private final CoinFormatter formatter;
private final BtcWalletService btcWalletService;
private final BsqWalletService bsqWalletService;
private final BsqFormatter bsqFormatter;
private final CoinFormatter btcFormatter;
final AccountAgeWitnessService accountAgeWitnessService;
@Inject
public ClosedTradesViewModel(ClosedTradesDataModel dataModel,
AccountAgeWitnessService accountAgeWitnessService,
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter) {
BtcWalletService btcWalletService,
BsqWalletService bsqWalletService,
BsqFormatter bsqFormatter,
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter) {
super(dataModel);
this.accountAgeWitnessService = accountAgeWitnessService;
this.formatter = formatter;
this.btcWalletService = btcWalletService;
this.bsqWalletService = bsqWalletService;
this.bsqFormatter = bsqFormatter;
this.btcFormatter = btcFormatter;
}
public ObservableList<ClosedTradableListItem> getList() {
@ -61,7 +82,7 @@ class ClosedTradesViewModel extends ActivatableWithDataModel<ClosedTradesDataMod
String getAmount(ClosedTradableListItem item) {
if (item != null && item.getTradable() instanceof Trade)
return formatter.formatCoin(((Trade) item.getTradable()).getTradeAmount());
return btcFormatter.formatCoin(((Trade) item.getTradable()).getTradeAmount());
else if (item != null && item.getTradable() instanceof OpenOffer)
return "-";
else
@ -103,19 +124,39 @@ class ClosedTradesViewModel extends ActivatableWithDataModel<ClosedTradesDataMod
return "";
Tradable tradable = item.getTradable();
if (!wasMyOffer(tradable) && (tradable instanceof Trade))
return formatter.formatCoin(((Trade) tradable).getTxFee());
return btcFormatter.formatCoin(((Trade) tradable).getTxFee());
else
return formatter.formatCoin(tradable.getOffer().getTxFee());
return btcFormatter.formatCoin(tradable.getOffer().getTxFee());
}
String getMakerFee(ClosedTradableListItem item) {
if (item == null)
String getTradeFee(ClosedTradableListItem item) {
if (item == null) {
return "";
}
Tradable tradable = item.getTradable();
if (!wasMyOffer(tradable) && (tradable instanceof Trade))
return formatter.formatCoin(((Trade) tradable).getTakerFee());
else
return formatter.formatCoin(tradable.getOffer().getMakerFee());
Offer offer = tradable.getOffer();
if (!wasMyOffer(tradable) && (tradable instanceof Trade)) {
Trade trade = (Trade) tradable;
Transaction takerFeeTx = btcWalletService.getTransaction(trade.getTakerFeeTxId());
if (takerFeeTx != null && takerFeeTx.getOutputs().size() > 1) {
// First output is fee receiver address. If its a BSQ (change) address of our own wallet its a BSQ fee
TransactionOutput output = takerFeeTx.getOutput(0);
Address address = output.getScriptPubKey().getToAddress(Config.baseCurrencyNetworkParameters());
if (bsqWalletService.getWallet().findKeyFromAddress(address) != null) {
return bsqFormatter.formatCoinWithCode(trade.getTakerFee());
} else {
return btcFormatter.formatCoinWithCode(trade.getTakerFee());
}
} else {
log.warn("takerFeeTx is null or has invalid structure. takerFeeTx={}", takerFeeTx);
return Res.get("shared.na");
}
} else {
CoinFormatter formatter = offer.isCurrencyForMakerFeeBtc() ? btcFormatter : bsqFormatter;
return formatter.formatCoinWithCode(offer.getMakerFee());
}
}
String getBuyerSecurityDeposit(ClosedTradableListItem item) {
@ -123,7 +164,7 @@ class ClosedTradesViewModel extends ActivatableWithDataModel<ClosedTradesDataMod
return "";
Tradable tradable = item.getTradable();
if (tradable.getOffer() != null)
return formatter.formatCoin(tradable.getOffer().getBuyerSecurityDeposit());
return btcFormatter.formatCoin(tradable.getOffer().getBuyerSecurityDeposit());
else
return "";
}
@ -133,7 +174,7 @@ class ClosedTradesViewModel extends ActivatableWithDataModel<ClosedTradesDataMod
return "";
Tradable tradable = item.getTradable();
if (tradable.getOffer() != null)
return formatter.formatCoin(tradable.getOffer().getSellerSecurityDeposit());
return btcFormatter.formatCoin(tradable.getOffer().getSellerSecurityDeposit());
else
return "";
}
@ -194,15 +235,16 @@ class ClosedTradesViewModel extends ActivatableWithDataModel<ClosedTradesDataMod
}
int getNumPastTrades(Tradable tradable) {
//noinspection ConstantConditions
return dataModel.closedTradableManager.getObservableList().stream()
.filter(e -> e instanceof Trade &&
tradable instanceof Trade &&
((Trade) e).getTradingPeerNodeAddress() != null &&
((Trade) tradable).getTradingPeerNodeAddress() != null &&
((Trade) e).getTradingPeerNodeAddress() != null &&
((Trade) tradable).getTradingPeerNodeAddress() != null &&
((Trade) e).getTradingPeerNodeAddress().getFullAddress().equals(((Trade) tradable).getTradingPeerNodeAddress().getFullAddress()))
.filter(candidate -> {
if (!(candidate instanceof Trade) ||
!(tradable instanceof Trade)) return false;
NodeAddress candidateAddress = ((Trade) candidate).getTradingPeerNodeAddress();
NodeAddress tradableAddress = ((Trade) tradable).getTradingPeerNodeAddress();
return candidateAddress != null &&
tradableAddress != null &&
candidateAddress.getFullAddress().equals(tradableAddress.getFullAddress());
})
.collect(Collectors.toSet())
.size();
}

View file

@ -112,7 +112,6 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
priceColumn.setComparator(Comparator.comparing(o -> o.getTrade().getTradePrice()));
volumeColumn.setComparator(Comparator.comparing(o -> o.getTrade().getTradeVolume(), Comparator.nullsFirst(Comparator.naturalOrder())));
amountColumn.setComparator(Comparator.comparing(o -> o.getTrade().getTradeAmount(), Comparator.nullsFirst(Comparator.naturalOrder())));
stateColumn.setComparator(Comparator.comparing(model::getState));
marketColumn.setComparator(Comparator.comparing(model::getMarketLabel));

View file

@ -125,7 +125,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
Comparator.nullsFirst(Comparator.naturalOrder())));
volumeColumn.setComparator(Comparator.comparing(o -> o.getOffer().getVolume(), Comparator.nullsFirst(Comparator.naturalOrder())));
dateColumn.setComparator(Comparator.comparing(o -> o.getOffer().getDate()));
paymentMethodColumn.setComparator(Comparator.comparing(o -> o.getOffer().getPaymentMethod().getId()));
paymentMethodColumn.setComparator(Comparator.comparing(o -> Res.get(o.getOffer().getPaymentMethod().getId())));
dateColumn.setSortType(TableColumn.SortType.DESCENDING);
tableView.getSortOrder().add(dateColumn);

View file

@ -196,18 +196,19 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
dateColumn.setComparator(Comparator.comparing(o -> o.getTrade().getDate()));
volumeColumn.setComparator(Comparator.comparing(o -> o.getTrade().getTradeVolume(), Comparator.nullsFirst(Comparator.naturalOrder())));
amountColumn.setComparator(Comparator.comparing(o -> o.getTrade().getTradeAmount(), Comparator.nullsFirst(Comparator.naturalOrder())));
priceColumn.setComparator(Comparator.comparing(PendingTradesListItem::getPrice));
priceColumn.setComparator(Comparator.comparing(item -> FormattingUtils.formatPrice(item.getPrice())));
paymentMethodColumn.setComparator(Comparator.comparing(
o -> o.getTrade().getOffer() != null ? o.getTrade().getOffer().getPaymentMethod().getId() : null,
Comparator.nullsFirst(Comparator.naturalOrder())
));
avatarColumn.setComparator(Comparator.comparing(
o -> o.getTrade().getTradingPeerNodeAddress() != null ? o.getTrade().getTradingPeerNodeAddress().getFullAddress() : null,
Comparator.nullsFirst(Comparator.naturalOrder())
));
roleColumn.setComparator(Comparator.comparing(model::getMyRole));
marketColumn.setComparator(Comparator.comparing(model::getMarketLabel));
item -> item.getTrade().getOffer() != null ?
Res.get(item.getTrade().getOffer().getPaymentMethod().getId()) :
null,
Comparator.nullsFirst(Comparator.naturalOrder())));
marketColumn.setComparator(Comparator.comparing(model::getMarketLabel));
roleColumn.setComparator(Comparator.comparing(model::getMyRole));
avatarColumn.setComparator(Comparator.comparing(
o -> model.getNumPastTrades(o.getTrade()),
Comparator.nullsFirst(Comparator.naturalOrder())
));
dateColumn.setSortType(TableColumn.SortType.DESCENDING);
tableView.getSortOrder().add(dateColumn);

View file

@ -118,6 +118,6 @@ public final class MailboxStoragePayload implements ProtectedStoragePayload, Exp
@Override
public long getTTL() {
return TimeUnit.DAYS.toMillis(7);
return TimeUnit.DAYS.toMillis(15);
}
}