Add listeners if pricefeed is not available

This commit is contained in:
Manfred Karrer 2016-04-16 15:46:45 +02:00
parent 3b94eda701
commit b97506cf51
11 changed files with 150 additions and 42 deletions

View file

@ -107,6 +107,7 @@ public class PriceFeed {
return null; return null;
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Setter // Setter
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////

View file

@ -277,6 +277,7 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
resultHandler.handleResult(); resultHandler.handleResult();
}, },
(errorMessage) -> { (errorMessage) -> {
if (availabilityProtocol != null)
availabilityProtocol.cancel(); availabilityProtocol.cancel();
log.error(errorMessage); log.error(errorMessage);
}); });
@ -370,8 +371,8 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
return null; return null;
} }
} else { } else {
log.warn("We don't have a market price./n" + log.warn("We don't have a market price.\n" +
"That case could only happen if you don't get a price feed."); "That case could only happen if you don't have a price feed.");
return null; return null;
} }
} else { } else {

View file

@ -35,6 +35,8 @@ import io.bitsquare.trade.offer.Offer;
import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty; import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ListChangeListener; import javafx.collections.ListChangeListener;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.geometry.Pos; import javafx.geometry.Pos;
@ -47,7 +49,6 @@ import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.util.Callback; import javafx.util.Callback;
import javafx.util.StringConverter; import javafx.util.StringConverter;
import org.bitcoinj.utils.Fiat;
import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.EasyBind;
import org.fxmisc.easybind.Subscription; import org.fxmisc.easybind.Subscription;
@ -182,18 +183,35 @@ public class MarketsChartsView extends ActivatableViewAndModel<VBox, MarketsChar
@Override @Override
public TableCell<Offer, Offer> call(TableColumn<Offer, Offer> column) { public TableCell<Offer, Offer> call(TableColumn<Offer, Offer> column) {
return new TableCell<Offer, Offer>() { return new TableCell<Offer, Offer>() {
private Offer offer;
ChangeListener<Number> listener = new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
if (offer != null && offer.getPrice() != null) {
setText(formatter.formatFiat(offer.getPrice()));
model.priceFeed.currenciesUpdateFlagProperty().removeListener(listener);
}
}
};
@Override @Override
public void updateItem(final Offer offer, boolean empty) { public void updateItem(final Offer offer, boolean empty) {
super.updateItem(offer, empty); super.updateItem(offer, empty);
if (offer != null && !empty) { if (offer != null && !empty) {
Fiat offerPrice = offer.getPrice(); if (offer.getPrice() == null) {
if (offerPrice != null) this.offer = offer;
setText(formatter.formatFiat(offerPrice)); model.priceFeed.currenciesUpdateFlagProperty().addListener(listener);
else setText("N/A");
setText(""); } else {
} else setText(formatter.formatFiat(offer.getPrice()));
}
} else {
if (listener != null)
model.priceFeed.currenciesUpdateFlagProperty().removeListener(listener);
this.offer = null;
setText(""); setText("");
} }
}
}; };
} }
}); });
@ -236,14 +254,35 @@ public class MarketsChartsView extends ActivatableViewAndModel<VBox, MarketsChar
@Override @Override
public TableCell<Offer, Offer> call(TableColumn<Offer, Offer> column) { public TableCell<Offer, Offer> call(TableColumn<Offer, Offer> column) {
return new TableCell<Offer, Offer>() { return new TableCell<Offer, Offer>() {
private Offer offer;
ChangeListener<Number> listener = new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
if (offer != null && offer.getPrice() != null) {
setText(formatter.formatFiat(offer.getOfferVolume()));
model.priceFeed.currenciesUpdateFlagProperty().removeListener(listener);
}
}
};
@Override @Override
public void updateItem(final Offer offer, boolean empty) { public void updateItem(final Offer offer, boolean empty) {
super.updateItem(offer, empty); super.updateItem(offer, empty);
if (offer != null && !empty) if (offer != null && !empty) {
if (offer.getPrice() == null) {
this.offer = offer;
model.priceFeed.currenciesUpdateFlagProperty().addListener(listener);
setText("N/A");
} else {
setText(formatter.formatFiat(offer.getOfferVolume())); setText(formatter.formatFiat(offer.getOfferVolume()));
else }
} else {
if (listener != null)
model.priceFeed.currenciesUpdateFlagProperty().removeListener(listener);
this.offer = null;
setText(""); setText("");
} }
}
}; };
} }
}); });

View file

@ -29,6 +29,8 @@ import io.bitsquare.trade.offer.Offer;
import io.bitsquare.user.Preferences; import io.bitsquare.user.Preferences;
import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener; import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
@ -44,15 +46,16 @@ class MarketsChartsViewModel extends ActivatableViewModel {
private final OfferBook offerBook; private final OfferBook offerBook;
private final Preferences preferences; private final Preferences preferences;
private final PriceFeed priceFeed; final PriceFeed priceFeed;
final ObjectProperty<TradeCurrency> tradeCurrency = new SimpleObjectProperty<>(CurrencyUtil.getDefaultTradeCurrency()); final ObjectProperty<TradeCurrency> tradeCurrency = new SimpleObjectProperty<>(CurrencyUtil.getDefaultTradeCurrency());
private final List<XYChart.Data> buyData = new ArrayList(); private final List<XYChart.Data> buyData = new ArrayList<>();
private final List<XYChart.Data> sellData = new ArrayList(); private final List<XYChart.Data> sellData = new ArrayList<>();
private final ObservableList<OfferBookListItem> offerBookListItems; private final ObservableList<OfferBookListItem> offerBookListItems;
private final ListChangeListener<OfferBookListItem> listChangeListener; private final ListChangeListener<OfferBookListItem> listChangeListener;
private final ObservableList<Offer> top3BuyOfferList = FXCollections.observableArrayList(); private final ObservableList<Offer> top3BuyOfferList = FXCollections.observableArrayList();
private final ObservableList<Offer> top3SellOfferList = FXCollections.observableArrayList(); private final ObservableList<Offer> top3SellOfferList = FXCollections.observableArrayList();
private final ChangeListener<Number> cacheFilledListener;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -67,15 +70,30 @@ class MarketsChartsViewModel extends ActivatableViewModel {
offerBookListItems = offerBook.getOfferBookListItems(); offerBookListItems = offerBook.getOfferBookListItems();
listChangeListener = c -> updateChartData(offerBookListItems); listChangeListener = c -> updateChartData(offerBookListItems);
cacheFilledListener = new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
if (!offerBookListItems.stream().filter(item -> item.getOffer().getPrice() == null).findAny().isPresent()) {
offerBook.fillOfferBookListItems();
updateChartData(offerBookListItems);
priceFeed.currenciesUpdateFlagProperty().removeListener(cacheFilledListener);
}
}
};
} }
@Override @Override
protected void activate() { protected void activate() {
priceFeed.setType(PriceFeed.Type.LAST); priceFeed.setType(PriceFeed.Type.LAST);
offerBookListItems.addListener(listChangeListener); offerBookListItems.addListener(listChangeListener);
offerBook.fillOfferBookListItems(); offerBook.fillOfferBookListItems();
updateChartData(offerBookListItems); updateChartData(offerBookListItems);
if (offerBookListItems.stream().filter(item -> item.getOffer().getPrice() == null).findAny().isPresent())
priceFeed.currenciesUpdateFlagProperty().addListener(cacheFilledListener);
if (!preferences.getUseStickyMarketPrice()) if (!preferences.getUseStickyMarketPrice())
priceFeed.setCurrencyCode(tradeCurrency.get().getCode()); priceFeed.setCurrencyCode(tradeCurrency.get().getCode());
} }

View file

@ -751,7 +751,9 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
isBtcInputValid(minAmount.get()).isValid && isBtcInputValid(minAmount.get()).isValid &&
isFiatInputValid(price.get()).isValid && isFiatInputValid(price.get()).isValid &&
isFiatInputValid(volume.get()).isValid && isFiatInputValid(volume.get()).isValid &&
dataModel.isMinAmountLessOrEqualAmount(); dataModel.isMinAmountLessOrEqualAmount() &&
!dataModel.useMarketBasedPrice.get() || dataModel.getMarketPriceMargin() != 0 &&
dataModel.useMarketBasedPrice.get() || dataModel.priceAsFiat.get().getValue() != 0;
isNextButtonDisabled.set(!inputDataValid); isNextButtonDisabled.set(!inputDataValid);
// boolean notSufficientFees = dataModel.isWalletFunded.get() && dataModel.isMainNet.get() && !dataModel.isFeeFromFundingTxSufficient.get(); // boolean notSufficientFees = dataModel.isWalletFunded.get() && dataModel.isMainNet.get() && !dataModel.isFeeFromFundingTxSufficient.get();
//isPlaceOfferButtonDisabled.set(createOfferRequested || !inputDataValid || notSufficientFees); //isPlaceOfferButtonDisabled.set(createOfferRequested || !inputDataValid || notSufficientFees);

View file

@ -41,6 +41,8 @@ import io.bitsquare.locale.TradeCurrency;
import io.bitsquare.payment.PaymentMethod; import io.bitsquare.payment.PaymentMethod;
import io.bitsquare.trade.offer.Offer; import io.bitsquare.trade.offer.Offer;
import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.HPos; import javafx.geometry.HPos;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.geometry.VPos; import javafx.geometry.VPos;
@ -420,14 +422,36 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
public TableCell<OfferBookListItem, OfferBookListItem> call( public TableCell<OfferBookListItem, OfferBookListItem> call(
TableColumn<OfferBookListItem, OfferBookListItem> column) { TableColumn<OfferBookListItem, OfferBookListItem> column) {
return new TableCell<OfferBookListItem, OfferBookListItem>() { return new TableCell<OfferBookListItem, OfferBookListItem>() {
private OfferBookListItem offerBookListItem;
ChangeListener<Number> listener = new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
if (offerBookListItem != null && offerBookListItem.getOffer().getPrice() != null) {
setText(model.getPrice(offerBookListItem));
model.priceFeed.currenciesUpdateFlagProperty().removeListener(listener);
}
}
};
@Override @Override
public void updateItem(final OfferBookListItem item, boolean empty) { public void updateItem(final OfferBookListItem item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
if (item != null && !empty)
if (item != null && !empty) {
if (item.getOffer().getPrice() == null) {
this.offerBookListItem = item;
model.priceFeed.currenciesUpdateFlagProperty().addListener(listener);
setText("N/A");
} else {
setText(model.getPrice(item)); setText(model.getPrice(item));
else }
} else {
if (listener != null)
model.priceFeed.currenciesUpdateFlagProperty().removeListener(listener);
this.offerBookListItem = null;
setText(""); setText("");
} }
}
}; };
} }
}); });
@ -448,14 +472,35 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
public TableCell<OfferBookListItem, OfferBookListItem> call( public TableCell<OfferBookListItem, OfferBookListItem> call(
TableColumn<OfferBookListItem, OfferBookListItem> column) { TableColumn<OfferBookListItem, OfferBookListItem> column) {
return new TableCell<OfferBookListItem, OfferBookListItem>() { return new TableCell<OfferBookListItem, OfferBookListItem>() {
private OfferBookListItem offerBookListItem;
ChangeListener<Number> listener = new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
if (offerBookListItem != null && offerBookListItem.getOffer().getOfferVolume() != null) {
setText(model.getVolume(offerBookListItem));
model.priceFeed.currenciesUpdateFlagProperty().removeListener(listener);
}
}
};
@Override @Override
public void updateItem(final OfferBookListItem item, boolean empty) { public void updateItem(final OfferBookListItem item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
if (item != null && !empty) if (item != null && !empty) {
if (item.getOffer().getPrice() == null) {
this.offerBookListItem = item;
model.priceFeed.currenciesUpdateFlagProperty().addListener(listener);
setText("N/A");
} else {
setText(model.getVolume(item)); setText(model.getVolume(item));
else }
} else {
if (listener != null)
model.priceFeed.currenciesUpdateFlagProperty().removeListener(listener);
this.offerBookListItem = null;
setText(""); setText("");
} }
}
}; };
} }
}); });

View file

@ -70,7 +70,7 @@ class OfferBookViewModel extends ActivatableViewModel {
private final OfferBook offerBook; private final OfferBook offerBook;
private final Preferences preferences; private final Preferences preferences;
private final P2PService p2PService; private final P2PService p2PService;
private final PriceFeed priceFeed; final PriceFeed priceFeed;
private ClosedTradableManager closedTradableManager; private ClosedTradableManager closedTradableManager;
private Navigation navigation; private Navigation navigation;
final BSFormatter formatter; final BSFormatter formatter;
@ -272,19 +272,21 @@ class OfferBookViewModel extends ActivatableViewModel {
else else
return formatter.formatFiat(price) + postFix; return formatter.formatFiat(price) + postFix;
} else { } else {
return ""; return "N/A";
} }
} }
String getVolume(OfferBookListItem item) { String getVolume(OfferBookListItem item) {
Fiat offerVolume = item.getOffer().getOfferVolume(); Fiat offerVolume = item.getOffer().getOfferVolume();
Fiat minOfferVolume = item.getOffer().getMinOfferVolume(); Fiat minOfferVolume = item.getOffer().getMinOfferVolume();
if (offerVolume != null && minOfferVolume != null) {
if (showAllTradeCurrenciesProperty.get()) if (showAllTradeCurrenciesProperty.get())
return (item != null) ? formatter.formatFiatWithCode(offerVolume) + return formatter.formatFiatWithCode(offerVolume) + " (" + formatter.formatFiatWithCode(minOfferVolume) + ")";
" (" + formatter.formatFiatWithCode(minOfferVolume) + ")" : "";
else else
return (item != null) ? formatter.formatFiat(offerVolume) + return formatter.formatFiat(offerVolume) + " (" + formatter.formatFiat(minOfferVolume) + ")";
" (" + formatter.formatFiat(minOfferVolume) + ")" : ""; } else {
return "N/A";
}
} }
String getPaymentMethod(OfferBookListItem item) { String getPaymentMethod(OfferBookListItem item) {

View file

@ -148,6 +148,7 @@ class TakeOfferDataModel extends ActivatableDataModel {
protected void deactivate() { protected void deactivate() {
removeBindings(); removeBindings();
removeListeners(); removeListeners();
if (offer != null)
tradeManager.onCancelAvailabilityRequest(offer); tradeManager.onCancelAvailabilityRequest(offer);
} }
@ -160,8 +161,6 @@ class TakeOfferDataModel extends ActivatableDataModel {
void initWithData(Offer offer) { void initWithData(Offer offer) {
this.offer = offer; this.offer = offer;
tradePrice = offer.getPrice(); tradePrice = offer.getPrice();
// we check at the view class and close in case we dont get a price
checkNotNull(tradePrice, "tradePrice must not be null");
addressEntry = walletService.getOrCreateAddressEntry(offer.getId(), AddressEntry.Context.OFFER_FUNDING); addressEntry = walletService.getOrCreateAddressEntry(offer.getId(), AddressEntry.Context.OFFER_FUNDING);
checkNotNull(addressEntry, "addressEntry must not be null"); checkNotNull(addressEntry, "addressEntry must not be null");
@ -309,7 +308,7 @@ class TakeOfferDataModel extends ActivatableDataModel {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
void calculateVolume() { void calculateVolume() {
if (offer != null && if (tradePrice != null && offer != null &&
amountAsCoin.get() != null && amountAsCoin.get() != null &&
!amountAsCoin.get().isZero()) { !amountAsCoin.get().isZero()) {
volumeAsFiat.set(new ExchangeRate(tradePrice).coinToFiat(amountAsCoin.get())); volumeAsFiat.set(new ExchangeRate(tradePrice).coinToFiat(amountAsCoin.get()));

View file

@ -59,6 +59,7 @@ import javafx.stage.Window;
import javafx.util.StringConverter; import javafx.util.StringConverter;
import net.glxn.qrgen.QRCode; import net.glxn.qrgen.QRCode;
import net.glxn.qrgen.image.ImageType; import net.glxn.qrgen.image.ImageType;
import org.bitcoinj.core.Coin;
import org.bitcoinj.uri.BitcoinURI; import org.bitcoinj.uri.BitcoinURI;
import org.controlsfx.control.PopOver; import org.controlsfx.control.PopOver;
import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.EasyBind;
@ -194,7 +195,6 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void initWithData(Offer offer) { public void initWithData(Offer offer) {
if (offer.getPrice() != null) {
model.initWithData(offer); model.initWithData(offer);
priceAsPercentageInputBox.setVisible(offer.getUseMarketBasedPrice()); priceAsPercentageInputBox.setVisible(offer.getUseMarketBasedPrice());
@ -233,13 +233,13 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
priceAsPercentageTextField.setText(model.marketPriceMargin); priceAsPercentageTextField.setText(model.marketPriceMargin);
addressTextField.setPaymentLabel(model.getPaymentLabel()); addressTextField.setPaymentLabel(model.getPaymentLabel());
addressTextField.setAddress(model.dataModel.getAddressEntry().getAddressString()); addressTextField.setAddress(model.dataModel.getAddressEntry().getAddressString());
} else {
if (offer.getPrice() == null)
new Popup().warning("You cannot take that offer as it uses a percentage price based on the " + new Popup().warning("You cannot take that offer as it uses a percentage price based on the " +
"market price but there is no price feed available.") "market price but there is no price feed available.")
.onClose(this::close) .onClose(this::close)
.show(); .show();
} }
}
public void setCloseHandler(OfferView.CloseHandler closeHandler) { public void setCloseHandler(OfferView.CloseHandler closeHandler) {
this.closeHandler = closeHandler; this.closeHandler = closeHandler;
@ -247,7 +247,8 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
// called form parent as the view does not get notified when the tab is closed // called form parent as the view does not get notified when the tab is closed
public void onClose() { public void onClose() {
if (model.dataModel.balance.get().isPositive() && !model.takeOfferCompleted.get()) { Coin balance = model.dataModel.balance.get();
if (balance != null && balance.isPositive() && !model.takeOfferCompleted.get()) {
model.dataModel.swapTradeToSavings(); model.dataModel.swapTradeToSavings();
new Popup().information("You have already funds paid in.\n" + new Popup().information("You have already funds paid in.\n" +
"In the \"Funds/Available for withdrawal\" section you can withdraw those funds.") "In the \"Funds/Available for withdrawal\" section you can withdraw those funds.")

View file

@ -32,7 +32,7 @@
<TableColumn text="Trade ID" fx:id="idColumn" minWidth="100"/> <TableColumn text="Trade ID" fx:id="idColumn" minWidth="100"/>
<TableColumn text="Date/Time" fx:id="dateColumn" minWidth="130"/> <TableColumn text="Date/Time" fx:id="dateColumn" minWidth="130"/>
<TableColumn text="Trade amount in BTC" fx:id="tradeAmountColumn" minWidth="130"/> <TableColumn text="Trade amount in BTC" fx:id="tradeAmountColumn" minWidth="130"/>
<TableColumn text="Price" fx:id="priceColumn" minWidth="100"/> <TableColumn text="Price" fx:id="priceColumn" minWidth="110"/>
<TableColumn text="Trade amount" fx:id="tradeVolumeColumn" minWidth="130"/> <TableColumn text="Trade amount" fx:id="tradeVolumeColumn" minWidth="130"/>
<TableColumn text="Payment method" fx:id="paymentMethodColumn" minWidth="120"/> <TableColumn text="Payment method" fx:id="paymentMethodColumn" minWidth="120"/>
<TableColumn text="My role" fx:id="roleColumn" minWidth="120" maxWidth="120"/> <TableColumn text="My role" fx:id="roleColumn" minWidth="120" maxWidth="120"/>

View file

@ -27,8 +27,8 @@ import java.util.function.Consumer;
public class LocalhostNetworkNode extends NetworkNode { public class LocalhostNetworkNode extends NetworkNode {
private static final Logger log = LoggerFactory.getLogger(LocalhostNetworkNode.class); private static final Logger log = LoggerFactory.getLogger(LocalhostNetworkNode.class);
private static volatile int simulateTorDelayTorNode = 200; private static volatile int simulateTorDelayTorNode = 500;
private static volatile int simulateTorDelayHiddenService = 300; private static volatile int simulateTorDelayHiddenService = 500;
public static void setSimulateTorDelayTorNode(int simulateTorDelayTorNode) { public static void setSimulateTorDelayTorNode(int simulateTorDelayTorNode) {
LocalhostNetworkNode.simulateTorDelayTorNode = simulateTorDelayTorNode; LocalhostNetworkNode.simulateTorDelayTorNode = simulateTorDelayTorNode;