Show Identicon for offerers or trading peers onion address and indicate repeated trades, Display additional info for Altcoins at buy/sell buttons
@ -34,7 +34,6 @@
|
||||
-fx-image: url("../../../images/buy_white.png");
|
||||
}
|
||||
|
||||
|
||||
#image-sell {
|
||||
-fx-image: url("../../../images/sell.png");
|
||||
}
|
||||
@ -213,3 +212,64 @@
|
||||
-fx-image: url("../../../images/link.png");
|
||||
}
|
||||
|
||||
#avatar_1 {
|
||||
-fx-image: url("../../../images/avatars/avatar_1.png");
|
||||
}
|
||||
|
||||
#avatar_2 {
|
||||
-fx-image: url("../../../images/avatars/avatar_2.png");
|
||||
}
|
||||
|
||||
#avatar_3 {
|
||||
-fx-image: url("../../../images/avatars/avatar_3.png");
|
||||
}
|
||||
|
||||
#avatar_4 {
|
||||
-fx-image: url("../../../images/avatars/avatar_4.png");
|
||||
}
|
||||
|
||||
#avatar_5 {
|
||||
-fx-image: url("../../../images/avatars/avatar_5.png");
|
||||
}
|
||||
|
||||
#avatar_6 {
|
||||
-fx-image: url("../../../images/avatars/avatar_6.png");
|
||||
}
|
||||
|
||||
#avatar_7 {
|
||||
-fx-image: url("../../../images/avatars/avatar_7.png");
|
||||
}
|
||||
|
||||
#avatar_8 {
|
||||
-fx-image: url("../../../images/avatars/avatar_8.png");
|
||||
}
|
||||
|
||||
#avatar_9 {
|
||||
-fx-image: url("../../../images/avatars/avatar_9.png");
|
||||
}
|
||||
|
||||
#avatar_10 {
|
||||
-fx-image: url("../../../images/avatars/avatar_10.png");
|
||||
}
|
||||
|
||||
#avatar_11 {
|
||||
-fx-image: url("../../../images/avatars/avatar_11.png");
|
||||
}
|
||||
|
||||
#avatar_12 {
|
||||
-fx-image: url("../../../images/avatars/avatar_12.png");
|
||||
}
|
||||
|
||||
#avatar_13 {
|
||||
-fx-image: url("../../../images/avatars/avatar_13.png");
|
||||
}
|
||||
|
||||
#avatar_14 {
|
||||
-fx-image: url("../../../images/avatars/avatar_14.png");
|
||||
}
|
||||
|
||||
#avatar_15 {
|
||||
-fx-image: url("../../../images/avatars/avatar_15.png");
|
||||
}
|
||||
|
||||
|
||||
|
@ -32,6 +32,7 @@ import io.bitsquare.gui.main.funds.withdrawal.WithdrawalView;
|
||||
import io.bitsquare.gui.main.offer.OfferView;
|
||||
import io.bitsquare.gui.main.overlays.popups.Popup;
|
||||
import io.bitsquare.gui.main.overlays.windows.OfferDetailsWindow;
|
||||
import io.bitsquare.gui.util.ImageUtil;
|
||||
import io.bitsquare.gui.util.Layout;
|
||||
import io.bitsquare.locale.BSResources;
|
||||
import io.bitsquare.locale.CryptoCurrency;
|
||||
@ -43,6 +44,7 @@ import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
import javafx.geometry.HPos;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.VPos;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.GridPane;
|
||||
@ -153,6 +155,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
||||
paymentMethodColumn = getPaymentMethodColumn();
|
||||
tableView.getColumns().add(paymentMethodColumn);
|
||||
tableView.getColumns().add(getActionColumn());
|
||||
tableView.getColumns().add(getAvatarColumn());
|
||||
|
||||
tableView.getSortOrder().add(priceColumn);
|
||||
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||
@ -192,17 +195,18 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
||||
paymentMethodComboBox.setOnAction(e -> model.onSetPaymentMethod(paymentMethodComboBox.getSelectionModel().getSelectedItem()));
|
||||
createOfferButton.setOnAction(e -> onCreateOffer());
|
||||
|
||||
priceColumn.textProperty().bind(createStringBinding(
|
||||
() -> !model.showAllTradeCurrenciesProperty.get() ?
|
||||
"Price in " + model.tradeCurrencyCode.get() + "/BTC" :
|
||||
"Price",
|
||||
model.tradeCurrencyCode,
|
||||
model.showAllTradeCurrenciesProperty));
|
||||
|
||||
volumeColumn.textProperty().bind(createStringBinding(
|
||||
() -> !model.showAllTradeCurrenciesProperty.get() ?
|
||||
"Amount in " + model.tradeCurrencyCode.get() + " (Min.)" :
|
||||
"Amount (Min.)",
|
||||
() -> {
|
||||
setDirectionTitles();
|
||||
String tradeCurrencyCode = model.tradeCurrencyCode.get();
|
||||
boolean showAllTradeCurrencies = model.showAllTradeCurrenciesProperty.get();
|
||||
priceColumn.setText(!showAllTradeCurrencies ?
|
||||
"Price in " + tradeCurrencyCode + "/BTC" :
|
||||
"Price");
|
||||
return !showAllTradeCurrencies ?
|
||||
"Amount in " + tradeCurrencyCode + " (Min.)" :
|
||||
"Amount (Min.)";
|
||||
},
|
||||
model.tradeCurrencyCode,
|
||||
model.showAllTradeCurrenciesProperty));
|
||||
|
||||
@ -212,6 +216,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
||||
tableView.setItems(model.getOfferList());
|
||||
priceColumn.setSortType((model.getDirection() == Offer.Direction.BUY) ? TableColumn.SortType.ASCENDING : TableColumn.SortType.DESCENDING);
|
||||
tableView.sort();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -237,17 +242,22 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
||||
ImageView iconView = new ImageView();
|
||||
|
||||
createOfferButton.setGraphic(iconView);
|
||||
if (direction == Offer.Direction.SELL) {
|
||||
offerBookTitle.setText("Offers for buying bitcoin ");
|
||||
createOfferButton.setId("sell-button-big");
|
||||
createOfferButton.setText("Create new offer for selling bitcoin");
|
||||
iconView.setId("image-sell-white");
|
||||
} else {
|
||||
offerBookTitle.setText("Offers for selling bitcoin ");
|
||||
createOfferButton.setId("buy-button-big");
|
||||
createOfferButton.setText("Create new offer for buying bitcoin");
|
||||
iconView.setId("image-buy-white");
|
||||
}
|
||||
iconView.setId(direction == Offer.Direction.SELL ? "image-sell-white" : "image-buy-white");
|
||||
createOfferButton.setId(direction == Offer.Direction.SELL ? "sell-button-big" : "buy-button-big");
|
||||
|
||||
setDirectionTitles();
|
||||
}
|
||||
|
||||
private void setDirectionTitles() {
|
||||
Offer.Direction direction = model.getDirection();
|
||||
String directionText = direction == Offer.Direction.BUY ? "buying" : "selling";
|
||||
String mirroredDirectionText = direction == Offer.Direction.SELL ? "buying" : "selling";
|
||||
TradeCurrency selectedTradeCurrency = model.getSelectedTradeCurrency();
|
||||
String postFix = selectedTradeCurrency instanceof FiatCurrency || model.showAllTradeCurrenciesProperty.get() ? "" :
|
||||
" (" + mirroredDirectionText + " " + selectedTradeCurrency.getName() + ")";
|
||||
|
||||
offerBookTitle.setText("Offers for " + directionText + " bitcoin" + postFix);
|
||||
createOfferButton.setText("Create new offer for " + directionText + " bitcoin" + postFix);
|
||||
}
|
||||
|
||||
public void setOfferActionHandler(OfferView.OfferActionHandler offerActionHandler) {
|
||||
@ -568,5 +578,44 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
||||
});
|
||||
return column;
|
||||
}
|
||||
|
||||
private TableColumn<OfferBookListItem, OfferBookListItem> getAvatarColumn() {
|
||||
TableColumn<OfferBookListItem, OfferBookListItem> column = new TableColumn<OfferBookListItem, OfferBookListItem>("") {
|
||||
{
|
||||
setMinWidth(32);
|
||||
setMaxWidth(32);
|
||||
setSortable(true);
|
||||
}
|
||||
};
|
||||
column.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
column.setCellFactory(
|
||||
new Callback<TableColumn<OfferBookListItem, OfferBookListItem>, TableCell<OfferBookListItem,
|
||||
OfferBookListItem>>() {
|
||||
|
||||
@Override
|
||||
public TableCell<OfferBookListItem, OfferBookListItem> call(TableColumn<OfferBookListItem, OfferBookListItem> column) {
|
||||
return new TableCell<OfferBookListItem, OfferBookListItem>() {
|
||||
@Override
|
||||
public void updateItem(final OfferBookListItem newItem, boolean empty) {
|
||||
super.updateItem(newItem, empty);
|
||||
|
||||
if (newItem != null && !empty) {
|
||||
String hostName = newItem.getOffer().getOwnerNodeAddress().hostName;
|
||||
int numPastTrades = model.getNumPastTrades(newItem.getOffer());
|
||||
boolean hasTraded = numPastTrades > 0;
|
||||
String tooltipText = hasTraded ? "Offerers onion address: " + hostName + "\n" +
|
||||
"You have already traded " + numPastTrades + " times with that offerer." : "Offerers onion address: " + hostName;
|
||||
Node identIcon = ImageUtil.getIdentIcon(hostName, tooltipText, hasTraded);
|
||||
if (identIcon != null)
|
||||
setGraphic(identIcon);
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
return column;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,8 @@ import io.bitsquare.locale.*;
|
||||
import io.bitsquare.p2p.NodeAddress;
|
||||
import io.bitsquare.p2p.P2PService;
|
||||
import io.bitsquare.payment.*;
|
||||
import io.bitsquare.trade.Trade;
|
||||
import io.bitsquare.trade.closed.ClosedTradableManager;
|
||||
import io.bitsquare.trade.offer.Offer;
|
||||
import io.bitsquare.trade.offer.OpenOfferManager;
|
||||
import io.bitsquare.user.Preferences;
|
||||
@ -69,6 +71,7 @@ class OfferBookViewModel extends ActivatableViewModel {
|
||||
private final Preferences preferences;
|
||||
private final P2PService p2PService;
|
||||
private final PriceFeed priceFeed;
|
||||
private ClosedTradableManager closedTradableManager;
|
||||
private Navigation navigation;
|
||||
final BSFormatter formatter;
|
||||
|
||||
@ -101,6 +104,7 @@ class OfferBookViewModel extends ActivatableViewModel {
|
||||
@Inject
|
||||
public OfferBookViewModel(User user, OpenOfferManager openOfferManager, OfferBook offerBook,
|
||||
Preferences preferences, P2PService p2PService, PriceFeed priceFeed,
|
||||
ClosedTradableManager closedTradableManager,
|
||||
Navigation navigation, BSFormatter formatter) {
|
||||
super();
|
||||
|
||||
@ -110,6 +114,7 @@ class OfferBookViewModel extends ActivatableViewModel {
|
||||
this.preferences = preferences;
|
||||
this.p2PService = p2PService;
|
||||
this.priceFeed = priceFeed;
|
||||
this.closedTradableManager = closedTradableManager;
|
||||
this.navigation = navigation;
|
||||
this.formatter = formatter;
|
||||
|
||||
@ -435,4 +440,12 @@ class OfferBookViewModel extends ActivatableViewModel {
|
||||
private boolean isEditEntry(String id) {
|
||||
return id.equals(EDIT_FLAG);
|
||||
}
|
||||
|
||||
public int getNumPastTrades(Offer offer) {
|
||||
return closedTradableManager.getClosedTrades().stream()
|
||||
.filter(e -> e instanceof Trade && ((Trade) e).getTradingPeerNodeAddress() != null &&
|
||||
((Trade) e).getTradingPeerNodeAddress().hostName.equals(offer.getOffererNodeAddress().hostName))
|
||||
.collect(Collectors.toSet())
|
||||
.size();
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,7 @@
|
||||
<TableColumn text="Trade amount" fx:id="volumeColumn" minWidth="130"/>
|
||||
<TableColumn text="Trade type" fx:id="directionColumn" minWidth="80"/>
|
||||
<TableColumn text="State" fx:id="stateColumn" minWidth="80" sortable="false"/>
|
||||
<TableColumn text="" fx:id="avatarColumn" minWidth="32" maxWidth="32"/>
|
||||
</columns>
|
||||
</TableView>
|
||||
|
||||
|
@ -23,11 +23,13 @@ import io.bitsquare.gui.components.HyperlinkWithIcon;
|
||||
import io.bitsquare.gui.main.overlays.windows.OfferDetailsWindow;
|
||||
import io.bitsquare.gui.main.overlays.windows.TradeDetailsWindow;
|
||||
import io.bitsquare.gui.util.BSFormatter;
|
||||
import io.bitsquare.gui.util.ImageUtil;
|
||||
import io.bitsquare.trade.Tradable;
|
||||
import io.bitsquare.trade.Trade;
|
||||
import io.bitsquare.trade.offer.OpenOffer;
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.util.Callback;
|
||||
@ -41,7 +43,7 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
||||
TableView<ClosedTradableListItem> table;
|
||||
@FXML
|
||||
TableColumn<ClosedTradableListItem, ClosedTradableListItem> priceColumn, amountColumn, volumeColumn,
|
||||
directionColumn, dateColumn, tradeIdColumn, stateColumn;
|
||||
directionColumn, dateColumn, tradeIdColumn, stateColumn, avatarColumn;
|
||||
private final BSFormatter formatter;
|
||||
private final OfferDetailsWindow offerDetailsWindow;
|
||||
private final TradeDetailsWindow tradeDetailsWindow;
|
||||
@ -63,6 +65,7 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
||||
setVolumeColumnCellFactory();
|
||||
setDateColumnCellFactory();
|
||||
setStateColumnCellFactory();
|
||||
setAvatarColumnCellFactory();
|
||||
|
||||
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||
table.setPlaceholder(new Label("No closed trades available"));
|
||||
@ -155,6 +158,34 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
||||
});
|
||||
}
|
||||
|
||||
private TableColumn<ClosedTradableListItem, ClosedTradableListItem> setAvatarColumnCellFactory() {
|
||||
avatarColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
avatarColumn.setCellFactory(
|
||||
new Callback<TableColumn<ClosedTradableListItem, ClosedTradableListItem>, TableCell<ClosedTradableListItem,
|
||||
ClosedTradableListItem>>() {
|
||||
|
||||
@Override
|
||||
public TableCell<ClosedTradableListItem, ClosedTradableListItem> call(TableColumn<ClosedTradableListItem, ClosedTradableListItem> column) {
|
||||
return new TableCell<ClosedTradableListItem, ClosedTradableListItem>() {
|
||||
@Override
|
||||
public void updateItem(final ClosedTradableListItem newItem, boolean empty) {
|
||||
super.updateItem(newItem, empty);
|
||||
|
||||
if (newItem != null && !empty && newItem.getTradable() instanceof Trade) {
|
||||
|
||||
String hostName = ((Trade) newItem.getTradable()).getTradingPeerNodeAddress().hostName;
|
||||
Node identIcon = ImageUtil.getIdentIcon(hostName, "Trading peers onion address: " + hostName, true);
|
||||
if (identIcon != null)
|
||||
setGraphic(identIcon);
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
return avatarColumn;
|
||||
}
|
||||
|
||||
private void setAmountColumnCellFactory() {
|
||||
amountColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
|
@ -52,6 +52,7 @@
|
||||
</TableColumn>
|
||||
<TableColumn text="Payment method" fx:id="paymentMethodColumn" minWidth="120"/>
|
||||
<TableColumn text="My role" fx:id="roleColumn" minWidth="120" maxWidth="120"/>
|
||||
<TableColumn text="" fx:id="avatarColumn" minWidth="32" maxWidth="32"/>
|
||||
</columns>
|
||||
</TableView>
|
||||
</VBox>
|
||||
|
@ -25,9 +25,11 @@ import io.bitsquare.gui.components.HyperlinkWithIcon;
|
||||
import io.bitsquare.gui.main.overlays.popups.Popup;
|
||||
import io.bitsquare.gui.main.overlays.windows.TradeDetailsWindow;
|
||||
import io.bitsquare.gui.util.BSFormatter;
|
||||
import io.bitsquare.gui.util.ImageUtil;
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.control.cell.TextFieldTableCell;
|
||||
@ -56,7 +58,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
||||
@FXML
|
||||
TableColumn<PendingTradesListItem, Fiat> priceColumn, tradeVolumeColumn;
|
||||
@FXML
|
||||
TableColumn<PendingTradesListItem, PendingTradesListItem> roleColumn, paymentMethodColumn, idColumn, dateColumn;
|
||||
TableColumn<PendingTradesListItem, PendingTradesListItem> avatarColumn, roleColumn, paymentMethodColumn, idColumn, dateColumn;
|
||||
@FXML
|
||||
TableColumn<PendingTradesListItem, Coin> tradeAmountColumn;
|
||||
|
||||
@ -88,6 +90,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
||||
setVolumeColumnCellFactory();
|
||||
setPaymentMethodColumnCellFactory();
|
||||
setRoleColumnCellFactory();
|
||||
setAvatarColumnCellFactory();
|
||||
|
||||
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||
table.setPlaceholder(new Label("No pending trades available"));
|
||||
@ -365,5 +368,37 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private TableColumn<PendingTradesListItem, PendingTradesListItem> setAvatarColumnCellFactory() {
|
||||
avatarColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||
avatarColumn.setCellFactory(
|
||||
new Callback<TableColumn<PendingTradesListItem, PendingTradesListItem>, TableCell<PendingTradesListItem,
|
||||
PendingTradesListItem>>() {
|
||||
|
||||
@Override
|
||||
public TableCell<PendingTradesListItem, PendingTradesListItem> call(TableColumn<PendingTradesListItem, PendingTradesListItem> column) {
|
||||
return new TableCell<PendingTradesListItem, PendingTradesListItem>() {
|
||||
@Override
|
||||
public void updateItem(final PendingTradesListItem newItem, boolean empty) {
|
||||
super.updateItem(newItem, empty);
|
||||
|
||||
if (newItem != null && !empty && newItem.getTrade().getTradingPeerNodeAddress() != null) {
|
||||
String hostName = newItem.getTrade().getTradingPeerNodeAddress().hostName;
|
||||
int numPastTrades = model.getNumPastTrades(newItem.getTrade());
|
||||
boolean hasTraded = numPastTrades > 0;
|
||||
String tooltipText = hasTraded ? "Trading peers onion address: " + hostName + "\n" +
|
||||
"You have already traded " + numPastTrades + " times with that peer." : "Trading peers onion address: " + hostName;
|
||||
Node identIcon = ImageUtil.getIdentIcon(hostName, tooltipText, hasTraded);
|
||||
if (identIcon != null)
|
||||
setGraphic(identIcon);
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
return avatarColumn;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@ import io.bitsquare.p2p.P2PService;
|
||||
import io.bitsquare.payment.PaymentMethod;
|
||||
import io.bitsquare.trade.Contract;
|
||||
import io.bitsquare.trade.Trade;
|
||||
import io.bitsquare.trade.closed.ClosedTradableManager;
|
||||
import io.bitsquare.trade.offer.Offer;
|
||||
import io.bitsquare.user.User;
|
||||
import javafx.beans.property.*;
|
||||
@ -38,6 +39,8 @@ import org.bitcoinj.core.BlockChainListener;
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
import org.fxmisc.easybind.Subscription;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel.SellerState.*;
|
||||
|
||||
public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataModel> implements ViewModel {
|
||||
@ -70,6 +73,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
||||
|
||||
public final P2PService p2PService;
|
||||
public final User user;
|
||||
private ClosedTradableManager closedTradableManager;
|
||||
public final Clock clock;
|
||||
|
||||
private final ObjectProperty<BuyerState> buyerState = new SimpleObjectProperty<>();
|
||||
@ -88,6 +92,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
||||
BtcAddressValidator btcAddressValidator,
|
||||
P2PService p2PService,
|
||||
User user,
|
||||
ClosedTradableManager closedTradableManager,
|
||||
Clock clock) {
|
||||
super(dataModel);
|
||||
|
||||
@ -95,6 +100,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
||||
this.btcAddressValidator = btcAddressValidator;
|
||||
this.p2PService = p2PService;
|
||||
this.user = user;
|
||||
this.closedTradableManager = closedTradableManager;
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
@ -256,6 +262,13 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
||||
return dataModel.getOffer() != null && dataModel.getOffer().getPaymentMethod().equals(PaymentMethod.BLOCK_CHAINS);
|
||||
}
|
||||
|
||||
public int getNumPastTrades(Trade trade) {
|
||||
return closedTradableManager.getClosedTrades().stream()
|
||||
.filter(e -> e instanceof Trade && ((Trade) e).getTradingPeerNodeAddress() != null &&
|
||||
((Trade) e).getTradingPeerNodeAddress().hostName.equals(trade.getTradingPeerNodeAddress().hostName))
|
||||
.collect(Collectors.toSet())
|
||||
.size();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// States
|
||||
|
@ -19,11 +19,21 @@ package io.bitsquare.gui.util;
|
||||
|
||||
import com.sun.javafx.tk.quantum.QuantumToolkit;
|
||||
import io.bitsquare.locale.Country;
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.canvas.Canvas;
|
||||
import javafx.scene.canvas.GraphicsContext;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.paint.Color;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.UUID;
|
||||
|
||||
|
||||
public class ImageUtil {
|
||||
private static final Logger log = LoggerFactory.getLogger(ImageUtil.class);
|
||||
@ -55,6 +65,71 @@ public class ImageUtil {
|
||||
}
|
||||
|
||||
public static boolean isRetina() {
|
||||
return ((QuantumToolkit) QuantumToolkit.getToolkit()).getMaxRenderScale() > 1.9f;
|
||||
float maxRenderScale = ((QuantumToolkit) QuantumToolkit.getToolkit()).getMaxRenderScale();
|
||||
boolean isRetina = maxRenderScale > 1.9f;
|
||||
log.info("isRetina=" + isRetina + " / maxRenderScale=" + maxRenderScale);
|
||||
return isRetina;
|
||||
}
|
||||
|
||||
public static Node getIdentIcon(String hostName, String tooltipText, boolean hasTraded) {
|
||||
if (!hostName.isEmpty()) {
|
||||
// for testing locally we use a random hostname to get dif. colors
|
||||
if (hostName.startsWith("localhost"))
|
||||
hostName = UUID.randomUUID().toString().replace("-", "").substring(0, 16);
|
||||
|
||||
int maxIndices = 15;
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA1");
|
||||
byte[] bytes = md.digest(hostName.getBytes());
|
||||
int intValue = Math.abs(((bytes[0] & 0xFF) << 24) | ((bytes[1] & 0xFF) << 16)
|
||||
| ((bytes[2] & 0xFF) << 8) | (bytes[3] & 0xFF));
|
||||
|
||||
int index = (intValue % maxIndices) + 1;
|
||||
|
||||
int red = intValue % 256;
|
||||
int green = (intValue >> 8) % 64; // we use green for marking repeated trades, so avoid it in main bg color
|
||||
int blue = (intValue >> 16) % 256;
|
||||
|
||||
ImageView iconView = new ImageView();
|
||||
iconView.setId("avatar_" + index);
|
||||
iconView.setScaleX(intValue % 2 == 0 ? 1d : -1d);
|
||||
double size = 26;
|
||||
Group iconGroup = new Group();
|
||||
|
||||
Color color = Color.rgb(red, green, blue);
|
||||
color = color.deriveColor(1, 0.6, 1, 1); // reduce saturation
|
||||
|
||||
if (hasTraded) {
|
||||
Canvas outerBg = new Canvas(size, size);
|
||||
GraphicsContext gc = outerBg.getGraphicsContext2D();
|
||||
gc.setFill(Color.rgb(0, 170, 51)); // green
|
||||
gc.fillOval(0, 0, size, size);
|
||||
outerBg.setLayoutY(1);
|
||||
|
||||
Canvas innerBg = new Canvas(size, size);
|
||||
GraphicsContext gc2 = innerBg.getGraphicsContext2D();
|
||||
gc2.setFill(color);
|
||||
gc2.fillOval(2, 2, size - 4, size - 4);
|
||||
innerBg.setLayoutY(1);
|
||||
iconGroup.getChildren().addAll(outerBg, innerBg, iconView);
|
||||
} else {
|
||||
Canvas bg = new Canvas(size, size);
|
||||
GraphicsContext gc = bg.getGraphicsContext2D();
|
||||
gc.setFill(color);
|
||||
gc.fillOval(0, 0, size, size);
|
||||
bg.setLayoutY(1);
|
||||
iconGroup.getChildren().addAll(bg, iconView);
|
||||
}
|
||||
|
||||
Tooltip.install(iconGroup, new Tooltip(tooltipText));
|
||||
return iconGroup;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
log.error(e.toString());
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
BIN
gui/src/main/resources/images/avatars/avatar_1.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_10.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_10@2x.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_11.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_11@2x.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_12.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_12@2x.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_13.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_13@2x.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_14.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_14@2x.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_15.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_15@2x.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_1@2x.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_2.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_2@2x.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_3.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_3@2x.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_4.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_4@2x.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_5.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_5@2x.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_6.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_6@2x.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_7.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_7@2x.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_8.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_8@2x.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_9.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
gui/src/main/resources/images/avatars/avatar_9@2x.png
Normal file
After Width: | Height: | Size: 2.4 KiB |