Clean up pending trades

This commit is contained in:
Manfred Karrer 2014-09-25 14:29:48 +02:00
parent 1a6fb9f5b5
commit 2840311853
12 changed files with 434 additions and 449 deletions

View file

@ -40,8 +40,7 @@ public class OfferListItem {
this.amount.set(BSFormatter.formatCoin( this.amount.set(BSFormatter.formatCoin(
offer.getAmount()) + " (" + BSFormatter.formatCoin(offer.getMinAmount()) + ")"); offer.getAmount()) + " (" + BSFormatter.formatCoin(offer.getMinAmount()) + ")");
this.volume.set(BSFormatter.formatVolumeWithMinVolume( this.volume.set(BSFormatter.formatVolumeWithMinVolume(offer));
offer.getOfferVolume(), offer.getMinOfferVolume()));
this.offerId = offer.getId(); this.offerId = offer.getId();
} }

View file

@ -17,22 +17,17 @@
package io.bitsquare.gui.main.orders.pending; package io.bitsquare.gui.main.orders.pending;
import io.bitsquare.locale.Country;
import io.bitsquare.trade.Offer;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
// TODO don't use inheritance /**
public class PendingTradesListItem { * We could remove that wrapper if it is not needed for additional UI only fields.
*/
class PendingTradesListItem {
private static final Logger log = LoggerFactory.getLogger(PendingTradesListItem.class); private static final Logger log = LoggerFactory.getLogger(PendingTradesListItem.class);
private final Offer offer;
private final ObjectProperty<Country> bankAccountCountry = new SimpleObjectProperty<>();
private final Trade trade; private final Trade trade;
@ -40,20 +35,8 @@ public class PendingTradesListItem {
// Constructor // Constructor
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public PendingTradesListItem(Trade trade) { PendingTradesListItem(Trade trade) {
this.trade = trade; this.trade = trade;
this.offer = trade.getOffer();
setBankAccountCountry(offer.getBankAccountCountry());
}
///////////////////////////////////////////////////////////////////////////////////////////
// Setters
///////////////////////////////////////////////////////////////////////////////////////////
void setBankAccountCountry(Country bankAccountCountry) {
this.bankAccountCountry.set(bankAccountCountry);
} }
@ -61,20 +44,7 @@ public class PendingTradesListItem {
// Getters // Getters
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public Trade getTrade() { Trade getTrade() {
return trade; return trade;
} }
Offer getOffer() {
return offer;
}
Country getBankAccountCountry() {
return bankAccountCountry.get();
}
ObjectProperty<Country> bankAccountCountryProperty() {
return bankAccountCountry;
}
} }

View file

@ -23,6 +23,7 @@ import io.bitsquare.btc.listeners.TxConfidenceListener;
import io.bitsquare.gui.UIModel; import io.bitsquare.gui.UIModel;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
import io.bitsquare.trade.TradeManager; import io.bitsquare.trade.TradeManager;
import io.bitsquare.user.User;
import com.google.bitcoin.core.Coin; import com.google.bitcoin.core.Coin;
import com.google.bitcoin.core.TransactionConfidence; import com.google.bitcoin.core.TransactionConfidence;
@ -31,12 +32,11 @@ import com.google.inject.Inject;
import java.util.Optional; import java.util.Optional;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
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.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.MapChangeListener; import javafx.collections.MapChangeListener;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
@ -44,20 +44,26 @@ import javafx.collections.ObservableList;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class PendingTradesModel extends UIModel { class PendingTradesModel extends UIModel {
private static final Logger log = LoggerFactory.getLogger(PendingTradesModel.class); private static final Logger log = LoggerFactory.getLogger(PendingTradesModel.class);
private final TradeManager tradeManager; private final TradeManager tradeManager;
private WalletFacade walletFacade; private final WalletFacade walletFacade;
private final ObservableList<PendingTradesListItem> pendingTrades = FXCollections.observableArrayList(); private final User user;
private PendingTradesListItem currentItem; private final ObservableList<PendingTradesListItem> list = FXCollections.observableArrayList();
private PendingTradesListItem selectedItem;
private boolean isOfferer; private boolean isOfferer;
final IntegerProperty selectedIndex = new SimpleIntegerProperty(-1);
private TxConfidenceListener txConfidenceListener;
private ChangeListener<Trade.State> stateChangeListener;
private ChangeListener<Throwable> faultChangeListener;
private MapChangeListener<String, Trade> mapChangeListener;
final StringProperty txId = new SimpleStringProperty();
final ObjectProperty<Trade.State> tradeState = new SimpleObjectProperty<>(); final ObjectProperty<Trade.State> tradeState = new SimpleObjectProperty<>();
final ObjectProperty<Throwable> fault = new SimpleObjectProperty<>(); final ObjectProperty<Throwable> fault = new SimpleObjectProperty<>();
final StringProperty txId = new SimpleStringProperty();
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -65,9 +71,10 @@ public class PendingTradesModel extends UIModel {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Inject @Inject
public PendingTradesModel(TradeManager tradeManager, WalletFacade walletFacade) { PendingTradesModel(TradeManager tradeManager, WalletFacade walletFacade, User user) {
this.tradeManager = tradeManager; this.tradeManager = tradeManager;
this.walletFacade = walletFacade; this.walletFacade = walletFacade;
this.user = user;
} }
@ -77,35 +84,51 @@ public class PendingTradesModel extends UIModel {
@Override @Override
public void initialize() { public void initialize() {
super.initialize(); stateChangeListener = (ov, oldValue, newValue) -> tradeState.set(newValue);
// transform trades to list of PendingTradesListItems and keep it updated faultChangeListener = (ov, oldValue, newValue) -> fault.set(newValue);
tradeManager.getTrades().values().stream().forEach(e -> pendingTrades.add(new PendingTradesListItem(e)));
tradeManager.getTrades().addListener((MapChangeListener<String, Trade>) change -> { mapChangeListener = change -> {
if (change.wasAdded()) if (change.wasAdded())
pendingTrades.add(new PendingTradesListItem(change.getValueAdded())); list.add(new PendingTradesListItem(change.getValueAdded()));
else if (change.wasAdded()) else if (change.wasRemoved())
pendingTrades.remove(new PendingTradesListItem(change.getValueRemoved())); list.remove(new PendingTradesListItem(change.getValueRemoved()));
}); };
super.initialize();
} }
@Override @Override
public void activate() { public void activate() {
super.activate(); super.activate();
// TODO Check if we can really use tradeManager.getPendingTrade() list.clear();
Optional<PendingTradesListItem> currentTradeItemOptional = pendingTrades.stream().filter((e) -> // transform trades to list of PendingTradesListItems and keep it updated
tradeManager.getCurrentPendingTrade() != null && tradeManager.getTrades().values().stream()
e.getTrade().getId().equals(tradeManager.getCurrentPendingTrade().getId())).findFirst(); .filter(e -> e.getState() != Trade.State.CLOSED)
.forEach(e -> list.add(new PendingTradesListItem(e)));
tradeManager.getTrades().addListener(mapChangeListener);
// we sort by date
list.sort((o1, o2) -> o2.getTrade().getDate().compareTo(o1.getTrade().getDate()));
// select either currentPendingTrade or first in the list
Optional<PendingTradesListItem> currentTradeItemOptional = list.stream()
.filter((e) -> tradeManager.getCurrentPendingTrade() != null &&
tradeManager.getCurrentPendingTrade().getId().equals(e.getTrade().getId()))
.findFirst();
if (currentTradeItemOptional.isPresent()) if (currentTradeItemOptional.isPresent())
selectPendingTrade(currentTradeItemOptional.get()); selectPendingTrade(currentTradeItemOptional.get());
else if (pendingTrades.size() > 0) else if (list.size() > 0)
selectPendingTrade(pendingTrades.get(0)); selectPendingTrade(list.get(0));
} }
@SuppressWarnings("EmptyMethod") @SuppressWarnings("EmptyMethod")
@Override @Override
public void deactivate() { public void deactivate() {
super.deactivate(); super.deactivate();
tradeManager.getTrades().removeListener(mapChangeListener);
selectPendingTrade(null);
} }
@SuppressWarnings("EmptyMethod") @SuppressWarnings("EmptyMethod")
@ -119,79 +142,87 @@ public class PendingTradesModel extends UIModel {
// Methods // Methods
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void selectPendingTrade(PendingTradesListItem item) { void selectPendingTrade(PendingTradesListItem item) {
if (item != null) { // clean up previous selectedItem
currentItem = item; if (selectedItem != null) {
isOfferer = tradeManager.isTradeMyOffer(currentItem.getTrade()); Trade trade = getTrade();
trade.stateProperty().removeListener(stateChangeListener);
trade.faultProperty().removeListener(faultChangeListener);
if (txConfidenceListener != null)
walletFacade.removeTxConfidenceListener(txConfidenceListener);
}
selectedItem = item;
if (selectedItem != null) {
isOfferer = getTrade().getOffer().getMessagePublicKey().equals(user.getMessagePublicKey());
// we want to re-trigger a change if the state is the same but different trades // we want to re-trigger a change if the state is the same but different trades
tradeState.set(null); tradeState.set(null);
selectedIndex.set(pendingTrades.indexOf(item)); Trade trade = getTrade();
Trade currentTrade = currentItem.getTrade(); txId.set(trade.getDepositTx().getHashAsString());
if (currentTrade.getDepositTx() != null) {
walletFacade.addTxConfidenceListener(new TxConfidenceListener(currentItem.getTrade() txConfidenceListener = new TxConfidenceListener(txId.get()) {
.getDepositTx().getHashAsString()) {
@Override @Override
public void onTransactionConfidenceChanged(TransactionConfidence confidence) { public void onTransactionConfidenceChanged(TransactionConfidence confidence) {
updateConfidence(confidence); updateConfidence(confidence);
} }
}); };
updateConfidence(walletFacade.getConfidenceForTxId(currentItem.getTrade().getDepositTx() walletFacade.addTxConfidenceListener(txConfidenceListener);
.getHashAsString())); updateConfidence(walletFacade.getConfidenceForTxId(txId.get()));
trade.stateProperty().addListener(stateChangeListener);
tradeState.set(trade.stateProperty().get());
trade.faultProperty().addListener(faultChangeListener);
fault.set(trade.faultProperty().get());
} }
else {
if (currentItem.getTrade().getDepositTx() != null) txId.set(null);
txId.set(currentItem.getTrade().getDepositTx().getHashAsString()); tradeState.set(null);
else
txId.set("");
currentTrade.stateProperty().addListener((ov, oldValue, newValue) -> tradeState.set(newValue));
tradeState.set(currentTrade.stateProperty().get());
currentTrade.faultProperty().addListener((ov, oldValue, newValue) -> fault.set(newValue));
fault.set(currentTrade.faultProperty().get());
} }
} }
public void paymentStarted() { void fiatPaymentStarted() {
tradeManager.bankTransferInited(currentItem.getTrade().getId()); tradeManager.fiatPaymentStarted(getTrade().getId());
} }
public void paymentReceived() { void fiatPaymentReceived() {
tradeManager.onFiatReceived(currentItem.getTrade().getId()); tradeManager.fiatPaymentReceived(getTrade().getId());
} }
///////////////////////////////////////////////////////////////////////////////////////////
// Setters
///////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Getters // Getters
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
ObservableList<PendingTradesListItem> getPendingTrades() { ObservableList<PendingTradesListItem> getList() {
return pendingTrades; return list;
} }
public boolean isOfferer() { boolean isOfferer() {
return isOfferer; return isOfferer;
} }
public Trade getTrade() { Trade getTrade() {
return currentItem.getTrade(); return selectedItem.getTrade();
} }
public Coin getTotalFees() { Coin getTotalFees() {
Coin tradeFee = isOfferer() ? FeePolicy.CREATE_OFFER_FEE : FeePolicy.TAKE_OFFER_FEE; return FeePolicy.TX_FEE.add(isOfferer() ? FeePolicy.CREATE_OFFER_FEE : FeePolicy.TAKE_OFFER_FEE);
return tradeFee.add(FeePolicy.TX_FEE);
} }
public WalletFacade getWalletFacade() { WalletFacade getWalletFacade() {
return walletFacade; return walletFacade;
} }
PendingTradesListItem getSelectedItem() {
return selectedItem;
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Private // Private
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -199,8 +230,12 @@ public class PendingTradesModel extends UIModel {
private void updateConfidence(TransactionConfidence confidence) { private void updateConfidence(TransactionConfidence confidence) {
if (confidence != null && if (confidence != null &&
confidence.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING confidence.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING
&& currentItem.getTrade().getState() == Trade.State.DEPOSIT_PUBLISHED) && getTrade().getState() == Trade.State.DEPOSIT_PUBLISHED) {
currentItem.getTrade().setState(Trade.State.DEPOSIT_CONFIRMED); // only set it once when actual state is DEPOSIT_PUBLISHED, and remove listener afterwards
getTrade().setState(Trade.State.DEPOSIT_CONFIRMED);
walletFacade.removeTxConfidenceListener(txConfidenceListener);
txConfidenceListener = null;
}
} }
} }

View file

@ -21,27 +21,24 @@ import io.bitsquare.btc.WalletFacade;
import io.bitsquare.gui.PresentationModel; import io.bitsquare.gui.PresentationModel;
import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.locale.BSResources; import io.bitsquare.locale.BSResources;
import io.bitsquare.trade.Direction;
import io.bitsquare.trade.Trade;
import com.google.inject.Inject; import com.google.inject.Inject;
import javafx.beans.property.IntegerProperty; import javafx.beans.InvalidationListener;
import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty; import javafx.beans.property.StringProperty;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.collections.transformation.SortedList;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class PendingTradesPM extends PresentationModel<PendingTradesModel> { public class PendingTradesPM extends PresentationModel<PendingTradesModel> {
private static final Logger log = LoggerFactory.getLogger(PendingTradesPM.class); private static final Logger log = LoggerFactory.getLogger(PendingTradesPM.class);
private BSFormatter formatter; private final BSFormatter formatter;
private BSResources resources; private InvalidationListener stateChangeListener;
enum State { enum State {
TAKER_SELLER_WAIT_TX_CONF, TAKER_SELLER_WAIT_TX_CONF,
@ -55,25 +52,20 @@ public class PendingTradesPM extends PresentationModel<PendingTradesModel> {
OFFERER_BUYER_COMPLETED, OFFERER_BUYER_COMPLETED,
} }
final StringProperty amount = new SimpleStringProperty();
final StringProperty price = new SimpleStringProperty();
final StringProperty volume = new SimpleStringProperty();
final IntegerProperty selectedIndex = new SimpleIntegerProperty(-1);
final ObjectProperty<State> state = new SimpleObjectProperty<>();
final ObjectProperty<Trade.State> tradeState = new SimpleObjectProperty<>();
final ObjectProperty<Throwable> fault = new SimpleObjectProperty<>();
final StringProperty txId = new SimpleStringProperty(); final StringProperty txId = new SimpleStringProperty();
final ObjectProperty<State> state = new SimpleObjectProperty<>();
final ObjectProperty<Throwable> fault = new SimpleObjectProperty<>();
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor // Constructor
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Inject @Inject
public PendingTradesPM(PendingTradesModel model, BSFormatter formatter, BSResources resources) { PendingTradesPM(PendingTradesModel model, BSFormatter formatter) {
super(model); super(model);
this.formatter = formatter; this.formatter = formatter;
this.resources = resources;
} }
@ -83,12 +75,7 @@ public class PendingTradesPM extends PresentationModel<PendingTradesModel> {
@Override @Override
public void initialize() { public void initialize() {
selectedIndex.bind(model.selectedIndex); stateChangeListener = (ov) -> updateState();
txId.bind(model.txId);
model.tradeState.addListener((ov, oldValue, newValue) -> {
updateState();
});
fault.bind(model.fault);
super.initialize(); super.initialize();
} }
@ -97,6 +84,10 @@ public class PendingTradesPM extends PresentationModel<PendingTradesModel> {
public void activate() { public void activate() {
super.activate(); super.activate();
txId.bind(model.txId);
fault.bind(model.fault);
model.tradeState.addListener(stateChangeListener);
updateState(); updateState();
} }
@ -104,6 +95,11 @@ public class PendingTradesPM extends PresentationModel<PendingTradesModel> {
@Override @Override
public void deactivate() { public void deactivate() {
super.deactivate(); super.deactivate();
txId.unbind();
fault.unbind();
model.tradeState.removeListener(stateChangeListener);
} }
@SuppressWarnings("EmptyMethod") @SuppressWarnings("EmptyMethod")
@ -117,17 +113,16 @@ public class PendingTradesPM extends PresentationModel<PendingTradesModel> {
// Methods // Methods
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
void selectPendingTrade(PendingTradesListItem item) {
public void selectPendingTrade(PendingTradesListItem item) {
model.selectPendingTrade(item); model.selectPendingTrade(item);
} }
public void paymentStarted() { void fiatPaymentStarted() {
model.paymentStarted(); model.fiatPaymentStarted();
} }
public void paymentReceived() { void fiatPaymentReceived() {
model.paymentReceived(); model.fiatPaymentReceived();
} }
@ -135,46 +130,36 @@ public class PendingTradesPM extends PresentationModel<PendingTradesModel> {
// Getters // Getters
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
ObservableList<PendingTradesListItem> getPendingTrades() { ObservableList<PendingTradesListItem> getList() {
return model.getPendingTrades(); return new SortedList<>(model.getList());
} }
boolean isOfferer() {
public boolean isOfferer() {
return model.isOfferer(); return model.isOfferer();
} }
public WalletFacade getWalletFacade() { WalletFacade getWalletFacade() {
return model.getWalletFacade(); return model.getWalletFacade();
} }
PendingTradesListItem getSelectedItem() {
return model.getSelectedItem();
}
String getAmount(PendingTradesListItem item) { String getAmount(PendingTradesListItem item) {
return (item != null) ? BSFormatter.formatCoin(item.getOffer().getAmount()) + return (item != null) ? BSFormatter.formatAmountWithMinAmount(item.getTrade().getOffer()) : "";
" (" + BSFormatter.formatCoin(item.getOffer().getMinAmount()) + ")" : "";
} }
String getPrice(PendingTradesListItem item) { String getPrice(PendingTradesListItem item) {
return (item != null) ? BSFormatter.formatFiat(item.getOffer().getPrice()) : ""; return (item != null) ? BSFormatter.formatFiat(item.getTrade().getOffer().getPrice()) : "";
} }
String getVolume(PendingTradesListItem item) { String getVolume(PendingTradesListItem item) {
return (item != null) ? BSFormatter.formatFiat(item.getOffer().getOfferVolume()) + return (item != null) ? BSFormatter.formatVolumeWithMinVolume(item.getTrade().getOffer()) : "";
" (" + BSFormatter.formatFiat(item.getOffer().getMinOfferVolume()) + ")" : "";
}
String getBankAccountType(PendingTradesListItem item) {
return (item != null) ? BSResources.get(item.getOffer().getBankAccountType().toString()) : "";
} }
String getDirectionLabel(PendingTradesListItem item) { String getDirectionLabel(PendingTradesListItem item) {
// mirror direction! return (item != null) ? BSFormatter.formatDirection(item.getTrade().getOffer().getMirroredDirection()) : "";
if (item != null) {
Direction direction = item.getOffer().getDirection() == Direction.BUY ? Direction.SELL : Direction.BUY;
return BSFormatter.formatDirection(direction, true);
}
else {
return "";
}
} }
String getPaymentMethod() { String getPaymentMethod() {
@ -193,6 +178,13 @@ public class PendingTradesPM extends PresentationModel<PendingTradesModel> {
return model.getTrade().getContract().getTakerBankAccount().getAccountSecondaryID(); return model.getTrade().getContract().getTakerBankAccount().getAccountSecondaryID();
} }
String getDate(PendingTradesListItem item) {
return formatter.formatDateTime(item.getTrade().getDate());
}
String getTradeId(PendingTradesListItem item) {
return item.getTrade().getId();
}
String getTradeVolume() { String getTradeVolume() {
return formatter.formatCoinWithCode(model.getTrade().getTradeAmount()); return formatter.formatCoinWithCode(model.getTrade().getTradeAmount());
@ -216,19 +208,18 @@ public class PendingTradesPM extends PresentationModel<PendingTradesModel> {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private void updateState() { private void updateState() {
log.debug("updateState " + model.tradeState.get());
if (model.tradeState.get() != null) { if (model.tradeState.get() != null) {
switch (model.tradeState.get()) { switch (model.tradeState.get()) {
case DEPOSIT_PUBLISHED: case DEPOSIT_PUBLISHED:
state.set(model.isOfferer() ? State.OFFERER_BUYER_WAIT_TX_CONF : State.TAKER_SELLER_WAIT_TX_CONF); state.set(model.isOfferer() ? State.OFFERER_BUYER_WAIT_TX_CONF : State.TAKER_SELLER_WAIT_TX_CONF);
break; break;
case DEPOSIT_CONFIRMED: case DEPOSIT_CONFIRMED:
state.set(model.isOfferer() ? State.OFFERER_BUYER_START_PAYMENT : State state.set(model.isOfferer() ? State.OFFERER_BUYER_START_PAYMENT :
.TAKER_SELLER_WAIT_PAYMENT_STARTED); State.TAKER_SELLER_WAIT_PAYMENT_STARTED);
break; break;
case PAYMENT_STARTED: case PAYMENT_STARTED:
state.set(model.isOfferer() ? State.OFFERER_BUYER_WAIT_CONFIRM_PAYMENT_RECEIVED : State state.set(model.isOfferer() ? State.OFFERER_BUYER_WAIT_CONFIRM_PAYMENT_RECEIVED :
.TAKER_SELLER_CONFIRM_RECEIVE_PAYMENT); State.TAKER_SELLER_CONFIRM_RECEIVE_PAYMENT);
break; break;
case PAYMENT_RECEIVED: case PAYMENT_RECEIVED:
case PAYOUT_PUBLISHED: case PAYOUT_PUBLISHED:

View file

@ -42,12 +42,12 @@
<Insets top="10.0" left="-10" right="-10" bottom="-15"/> <Insets top="10.0" left="-10" right="-10" bottom="-15"/>
</GridPane.margin> </GridPane.margin>
<columns> <columns>
<TableColumn text="Amount in BTC (Min.)" fx:id="amountColumn" minWidth="130"/> <TableColumn text="Trade ID" fx:id="tradeIdColumn" minWidth="100" sortable="false"/>
<TableColumn text="Price" fx:id="priceColumn" minWidth="130"/> <TableColumn text="Date" fx:id="dateColumn" minWidth="130"/>
<TableColumn text="Amount in EUR (Min.)" fx:id="volumeColumn" minWidth="130"/> <TableColumn text="Amount in BTC (Min.)" fx:id="amountColumn" minWidth="130" sortable="false"/>
<TableColumn text="Country" fx:id="countryColumn" minWidth="60"/> <TableColumn text="Price" fx:id="priceColumn" minWidth="100" sortable="false"/>
<TableColumn text="Bank transfer type" fx:id="bankAccountTypeColumn" minWidth="130"/> <TableColumn text="Amount in EUR (Min.)" fx:id="volumeColumn" minWidth="130" sortable="false"/>
<TableColumn text="Trade tye" fx:id="directionColumn" minWidth="80" sortable="false"/> <TableColumn text="Trade type" fx:id="directionColumn" minWidth="80" sortable="false"/>
<TableColumn fx:id="selectColumn" minWidth="60" sortable="false" text=""/> <TableColumn fx:id="selectColumn" minWidth="60" sortable="false" text=""/>
</columns> </columns>
</TableView> </TableView>

View file

@ -26,8 +26,6 @@ import io.bitsquare.gui.components.processbar.ProcessStepBar;
import io.bitsquare.gui.components.processbar.ProcessStepItem; import io.bitsquare.gui.components.processbar.ProcessStepItem;
import io.bitsquare.gui.main.help.Help; import io.bitsquare.gui.main.help.Help;
import io.bitsquare.gui.main.help.HelpId; import io.bitsquare.gui.main.help.HelpId;
import io.bitsquare.gui.util.ImageUtil;
import io.bitsquare.locale.Country;
import java.net.URL; import java.net.URL;
@ -37,12 +35,11 @@ import java.util.ResourceBundle;
import javax.inject.Inject; import javax.inject.Inject;
import javafx.application.Platform;
import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.value.ChangeListener;
import javafx.collections.ListChangeListener;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.geometry.Pos;
import javafx.scene.control.*; import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.util.Callback; import javafx.util.Callback;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -50,29 +47,26 @@ import org.slf4j.LoggerFactory;
public class PendingTradesViewCB extends CachedViewCB<PendingTradesPM> { public class PendingTradesViewCB extends CachedViewCB<PendingTradesPM> {
private static final Logger log = LoggerFactory.getLogger(PendingTradesViewCB.class); private static final Logger log = LoggerFactory.getLogger(PendingTradesViewCB.class);
public TitledGroupBg summaryGroupBg;
public Label btcLabel;
public TextField btcTextField;
public Label fiatLabel;
public TextField fiatTextField;
public Label feesLabel;
public TextField feesTextField;
public Label collateralLabel; @FXML TitledGroupBg titledGroupBg, paymentsGroupBg, summaryGroupBg;
public TextField collateralTextField;
public InfoDisplay summaryInfoDisplay;
@FXML TitledGroupBg titledGroupBg, paymentsGroupBg;
@FXML ProcessStepBar processBar; @FXML ProcessStepBar processBar;
@FXML Label statusLabel, txIdLabel, paymentMethodLabel, holderNameLabel, primaryIdLabel, secondaryIdLabel; @FXML Label statusLabel, txIdLabel, paymentMethodLabel, holderNameLabel, primaryIdLabel, secondaryIdLabel,
@FXML TextField statusTextField, paymentMethodTextField; btcLabel, fiatLabel, feesLabel, collateralLabel;
@FXML TextField statusTextField, paymentMethodTextField, btcTextField, fiatTextField, feesTextField,
collateralTextField;
@FXML TxIdTextField txIdTextField; @FXML TxIdTextField txIdTextField;
@FXML InfoDisplay infoDisplay, paymentsInfoDisplay; @FXML InfoDisplay infoDisplay, paymentsInfoDisplay, summaryInfoDisplay;
@FXML Button confirmPaymentReceiptButton, paymentsButton; @FXML Button confirmPaymentReceiptButton, paymentsButton;
@FXML TextFieldWithCopyIcon holderNameTextField, secondaryIdTextField, primaryIdTextField; @FXML TextFieldWithCopyIcon holderNameTextField, secondaryIdTextField, primaryIdTextField;
@FXML TableView<PendingTradesListItem> table; @FXML TableView<PendingTradesListItem> table;
@FXML TableColumn<PendingTradesListItem, PendingTradesListItem> priceColumn, amountColumn, volumeColumn, @FXML TableColumn<PendingTradesListItem, PendingTradesListItem> priceColumn, amountColumn, volumeColumn,
directionColumn, countryColumn, bankAccountTypeColumn, selectColumn; directionColumn, dateColumn, tradeIdColumn, selectColumn;
private ChangeListener<PendingTradesListItem> selectedItemChangeListener;
private ListChangeListener<PendingTradesListItem> listChangeListener;
private ChangeListener<String> txIdChangeListener;
private ChangeListener<PendingTradesPM.State> offererStateChangeListener;
private ChangeListener<PendingTradesPM.State> takerStateChangeListener;
private ChangeListener<Throwable> faultChangeListener;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -80,7 +74,7 @@ public class PendingTradesViewCB extends CachedViewCB<PendingTradesPM> {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Inject @Inject
public PendingTradesViewCB(PendingTradesPM presentationModel) { PendingTradesViewCB(PendingTradesPM presentationModel) {
super(presentationModel); super(presentationModel);
} }
@ -91,19 +85,20 @@ public class PendingTradesViewCB extends CachedViewCB<PendingTradesPM> {
@Override @Override
public void initialize(URL url, ResourceBundle rb) { public void initialize(URL url, ResourceBundle rb) {
setTradeIdColumnCellFactory();
setDirectionColumnCellFactory();
setAmountColumnCellFactory(); setAmountColumnCellFactory();
setPriceColumnCellFactory(); setPriceColumnCellFactory();
setVolumeColumnCellFactory(); setVolumeColumnCellFactory();
setCountryColumnCellFactory(); setDateColumnCellFactory();
setBankAccountTypeColumnCellFactory();
setDirectionColumnCellFactory();
setSelectColumnCellFactory(); setSelectColumnCellFactory();
table.setItems(presentationModel.getPendingTrades());
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
table.getSelectionModel().selectedItemProperty(). txIdChangeListener = (ov, oldValue, newValue) ->
addListener((obsValue, oldValue, newValue) -> { txIdTextField.setup(presentationModel.getWalletFacade(), newValue);
selectedItemChangeListener = (obsValue, oldValue, newValue) -> {
if (oldValue != newValue) { if (oldValue != newValue) {
if (oldValue != null && newValue != null) if (oldValue != null && newValue != null)
presentationModel.selectPendingTrade(newValue); presentationModel.selectPendingTrade(newValue);
@ -111,13 +106,20 @@ public class PendingTradesViewCB extends CachedViewCB<PendingTradesPM> {
table.getSelectionModel().clearSelection(); table.getSelectionModel().clearSelection();
} }
else { else {
log.error("####### should not happen!"); log.warn("should never happen!");
} }
}); };
// need runLater to avoid conflict with user initiated selection listChangeListener = change -> {
presentationModel.selectedIndex.addListener((ov, oldValue, newValue) -> change.next();
Platform.runLater(() -> table.getSelectionModel().select((int) newValue))); if ((change.wasAdded() && change.getList().size() == 1) ||
(change.wasRemoved() && change.getList().size() == 0))
updateScreen();
};
offererStateChangeListener = (ov, oldValue, newValue) -> applyOffererState(newValue);
takerStateChangeListener = (ov, oldValue, newValue) -> applyTakerState(newValue);
faultChangeListener = (ov, oldValue, newValue) -> onFault(newValue);
super.initialize(url, rb); super.initialize(url, rb);
} }
@ -126,39 +128,33 @@ public class PendingTradesViewCB extends CachedViewCB<PendingTradesPM> {
public void activate() { public void activate() {
super.activate(); super.activate();
if (!presentationModel.getPendingTrades().isEmpty()) { table.setItems(presentationModel.getList());
titledGroupBg.setVisible(true);
processBar.setVisible(true);
statusLabel.setVisible(true);
statusTextField.setVisible(true);
txIdLabel.setVisible(true);
txIdTextField.setVisible(true);
infoDisplay.setVisible(true);
if (presentationModel.isOfferer()) presentationModel.getList().addListener(listChangeListener);
setupScreenForOfferer(); presentationModel.txId.addListener(txIdChangeListener);
else presentationModel.fault.addListener(faultChangeListener);
setupScreenForTaker();
presentationModel.txId.addListener((ov, oldValue, newValue) ->
txIdTextField.setup(presentationModel.getWalletFacade(), newValue));
txIdTextField.setup(presentationModel.getWalletFacade(), presentationModel.txId.get()); txIdTextField.setup(presentationModel.getWalletFacade(), presentationModel.txId.get());
} table.getSelectionModel().select(presentationModel.getSelectedItem());
else {
titledGroupBg.setVisible(false); // TODO Set focus does not work yet...
processBar.setVisible(false); /* table.requestFocus();
statusLabel.setVisible(false); table.getFocusModel().focus( table.getSelectionModel().getSelectedIndex());*/
statusTextField.setVisible(false);
txIdLabel.setVisible(false); updateScreen();
txIdTextField.setVisible(false);
infoDisplay.setVisible(false);
}
} }
@SuppressWarnings("EmptyMethod")
@Override @Override
public void deactivate() { public void deactivate() {
super.deactivate(); super.deactivate();
table.getSelectionModel().selectedItemProperty().removeListener(selectedItemChangeListener);
presentationModel.getList().removeListener(listChangeListener);
presentationModel.txId.removeListener(txIdChangeListener);
presentationModel.fault.removeListener(faultChangeListener);
presentationModel.state.removeListener(offererStateChangeListener);
presentationModel.state.removeListener(takerStateChangeListener);
} }
@SuppressWarnings("EmptyMethod") @SuppressWarnings("EmptyMethod")
@ -174,12 +170,12 @@ public class PendingTradesViewCB extends CachedViewCB<PendingTradesPM> {
@FXML @FXML
void onPaymentStarted() { void onPaymentStarted() {
presentationModel.paymentStarted(); presentationModel.fiatPaymentStarted();
} }
@FXML @FXML
void onConfirmPaymentReceipt() { void onConfirmPaymentReceipt() {
presentationModel.paymentReceived(); presentationModel.fiatPaymentReceived();
} }
@FXML @FXML
@ -202,10 +198,25 @@ public class PendingTradesViewCB extends CachedViewCB<PendingTradesPM> {
// Private methods // Private methods
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private void updateScreen() {
boolean dataAvailable = !presentationModel.getList().isEmpty();
titledGroupBg.setVisible(dataAvailable);
processBar.setVisible(dataAvailable);
statusLabel.setVisible(dataAvailable);
statusTextField.setVisible(dataAvailable);
txIdLabel.setVisible(dataAvailable);
txIdTextField.setVisible(dataAvailable);
infoDisplay.setVisible(dataAvailable);
if (dataAvailable) {
if (presentationModel.isOfferer())
setupScreenForOfferer();
else
setupScreenForTaker();
}
}
private void setupScreenForOfferer() { private void setupScreenForOfferer() {
log.debug("setupScreenForOfferer");
if (processBar.getProcessStepItems() == null) { if (processBar.getProcessStepItems() == null) {
List<ProcessStepItem> items = new ArrayList<>(); List<ProcessStepItem> items = new ArrayList<>();
items.add(new ProcessStepItem("Wait for block chain confirmation")); items.add(new ProcessStepItem("Wait for block chain confirmation"));
@ -215,115 +226,10 @@ public class PendingTradesViewCB extends CachedViewCB<PendingTradesPM> {
processBar.setProcessStepItems(items); processBar.setProcessStepItems(items);
} }
presentationModel.state.addListener((ov, oldValue, newValue) -> applyOffererState(newValue)); presentationModel.state.addListener(offererStateChangeListener);
applyOffererState(presentationModel.state.get()); applyOffererState(presentationModel.state.get());
} }
private void applyOffererState(PendingTradesPM.State state) {
paymentsGroupBg.setVisible(false);
paymentMethodLabel.setVisible(false);
holderNameLabel.setVisible(false);
primaryIdLabel.setVisible(false);
secondaryIdLabel.setVisible(false);
paymentMethodTextField.setVisible(false);
paymentsInfoDisplay.setVisible(false);
paymentsButton.setVisible(false);
holderNameTextField.setVisible(false);
primaryIdTextField.setVisible(false);
secondaryIdTextField.setVisible(false);
summaryGroupBg.setVisible(false);
btcLabel.setVisible(false);
btcTextField.setVisible(false);
fiatLabel.setVisible(false);
fiatTextField.setVisible(false);
feesLabel.setVisible(false);
feesTextField.setVisible(false);
collateralLabel.setVisible(false);
collateralTextField.setVisible(false);
summaryInfoDisplay.setVisible(false);
if (state != null) {
switch (state) {
case OFFERER_BUYER_WAIT_TX_CONF:
processBar.setSelectedIndex(0);
statusTextField.setText("Deposit transaction is published. Waiting " +
"for at least 1 confirmation");
infoDisplay.setText("Deposit transaction has bee published. You need to wait for at least one " +
"block " +
"chain confirmation. After that you need to make the payments transfer.");
break;
case OFFERER_BUYER_START_PAYMENT:
processBar.setSelectedIndex(1);
statusTextField.setText("Deposit transaction has at least 1 confirmation. Start payment.");
infoDisplay.setText("Deposit transaction has at least one blockchain confirmation. You need to " +
"start " +
"the payment.");
paymentsGroupBg.setVisible(true);
paymentMethodLabel.setVisible(true);
holderNameLabel.setVisible(true);
primaryIdLabel.setVisible(true);
secondaryIdLabel.setVisible(true);
paymentMethodTextField.setVisible(true);
paymentsInfoDisplay.setVisible(true);
holderNameTextField.setVisible(true);
primaryIdTextField.setVisible(true);
secondaryIdTextField.setVisible(true);
paymentsButton.setVisible(true);
paymentMethodTextField.setText(presentationModel.getPaymentMethod());
holderNameTextField.setText(presentationModel.getHolderName());
primaryIdTextField.setText(presentationModel.getPrimaryId());
secondaryIdTextField.setText(presentationModel.getSecondaryId());
paymentsInfoDisplay.setText("Copy and paste the payments accounts data to your payments " +
"accounts web page and transfer the payment to the other trader. When the transfer is " +
"done confirm it with the 'Payment started' button.");
break;
case OFFERER_BUYER_WAIT_CONFIRM_PAYMENT_RECEIVED:
processBar.setSelectedIndex(2);
statusTextField.setText("Waiting until the other trader has received your payment.");
infoDisplay.setText("Waiting until the other trader has confirmed that he has received your " +
"payment.");
break;
case OFFERER_BUYER_COMPLETED:
processBar.setSelectedIndex(3);
statusTextField.setText("Trade has successfully completed.");
infoDisplay.setText("Trade has successfully completed. You can find the details to that trade" +
" in the closed trades section.");
summaryGroupBg.setVisible(true);
btcLabel.setVisible(true);
btcTextField.setVisible(true);
fiatLabel.setVisible(true);
fiatTextField.setVisible(true);
feesLabel.setVisible(true);
feesTextField.setVisible(true);
collateralLabel.setVisible(true);
collateralTextField.setVisible(true);
summaryInfoDisplay.setVisible(true);
btcLabel.setText("You have bought:");
fiatLabel.setText("You have paid:");
btcTextField.setText(presentationModel.getTradeVolume());
fiatTextField.setText(presentationModel.getFiatVolume());
feesTextField.setText(presentationModel.getTotalFees());
collateralTextField.setText(presentationModel.getCollateral());
summaryInfoDisplay.setText("You can open that summary any time in the closed orders section.");
break;
}
}
else {
processBar.reset();
}
}
private void setupScreenForTaker() { private void setupScreenForTaker() {
log.debug("setupScreenForTaker"); log.debug("setupScreenForTaker");
if (processBar.getProcessStepItems() == null) { if (processBar.getProcessStepItems() == null) {
@ -335,37 +241,90 @@ public class PendingTradesViewCB extends CachedViewCB<PendingTradesPM> {
processBar.setProcessStepItems(items); processBar.setProcessStepItems(items);
} }
presentationModel.state.addListener((ov, oldValue, newValue) -> applyTakerState(newValue)); presentationModel.state.addListener(takerStateChangeListener);
applyTakerState(presentationModel.state.get()); applyTakerState(presentationModel.state.get());
} }
private void applyTakerState(PendingTradesPM.State state) { private void applyOffererState(PendingTradesPM.State state) {
log.debug("#### state " + state); setPaymentsControlsVisible(false);
setSummaryControlsVisible(false);
processBar.reset();
if (state != null) {
switch (state) {
case OFFERER_BUYER_WAIT_TX_CONF:
processBar.setSelectedIndex(0);
statusTextField.setText("Deposit transaction is published. Waiting " +
"for at least 1 confirmation");
infoDisplay.setText("Deposit transaction has bee published. You need to wait for at least one " +
"block chain confirmation. After that you need to make the payments transfer.");
break;
case OFFERER_BUYER_START_PAYMENT:
processBar.setSelectedIndex(1);
setPaymentsControlsVisible(true);
statusTextField.setText("Deposit transaction has at least 1 confirmation. Start payment.");
infoDisplay.setText("Deposit transaction has at least one blockchain confirmation. You need to " +
"start the payment.");
paymentMethodTextField.setText(presentationModel.getPaymentMethod());
holderNameTextField.setText(presentationModel.getHolderName());
primaryIdTextField.setText(presentationModel.getPrimaryId());
secondaryIdTextField.setText(presentationModel.getSecondaryId());
paymentsInfoDisplay.setText("Copy and paste the payments accounts data to your payments " +
"accounts web page and transfer the payment to the other trader. When the transfer is " +
"done confirm it with the 'Payment started' button.");
break;
case OFFERER_BUYER_WAIT_CONFIRM_PAYMENT_RECEIVED:
processBar.setSelectedIndex(2);
statusTextField.setText("Waiting until the other trader has received your payment.");
infoDisplay.setText("Waiting until the other trader has confirmed that he has received your " +
"payment.");
break;
case OFFERER_BUYER_COMPLETED:
processBar.setSelectedIndex(3);
setSummaryControlsVisible(true);
statusTextField.setText("Trade has successfully completed.");
infoDisplay.setText("Trade has successfully completed. You can find the details to that trade" +
" in the closed trades section.");
btcLabel.setText("You have bought:");
fiatLabel.setText("You have paid:");
btcTextField.setText(presentationModel.getTradeVolume());
fiatTextField.setText(presentationModel.getFiatVolume());
feesTextField.setText(presentationModel.getTotalFees());
collateralTextField.setText(presentationModel.getCollateral());
summaryInfoDisplay.setText("You can open that summary any time in the closed orders section.");
break;
}
}
}
private void applyTakerState(PendingTradesPM.State state) {
confirmPaymentReceiptButton.setVisible(false); confirmPaymentReceiptButton.setVisible(false);
summaryGroupBg.setVisible(false); setSummaryControlsVisible(false);
btcLabel.setVisible(false);
btcTextField.setVisible(false); processBar.reset();
fiatLabel.setVisible(false);
fiatTextField.setVisible(false);
feesLabel.setVisible(false);
feesTextField.setVisible(false);
collateralLabel.setVisible(false);
collateralTextField.setVisible(false);
summaryInfoDisplay.setVisible(false);
if (state != null) { if (state != null) {
switch (state) { switch (state) {
case TAKER_SELLER_WAIT_TX_CONF: case TAKER_SELLER_WAIT_TX_CONF:
processBar.setSelectedIndex(0); processBar.setSelectedIndex(0);
statusTextField.setText("Deposit transaction is published. Waiting for at least 1 confirmation"); statusTextField.setText("Deposit transaction is published. Waiting for at least 1 confirmation");
infoDisplay.setText("Deposit transaction has bee published. He needs to wait for at least one " + infoDisplay.setText("Deposit transaction has bee published. He needs to wait for at least one " +
"blockchain " + "blockchain confirmation.");
"confirmation.");
break; break;
case TAKER_SELLER_WAIT_PAYMENT_STARTED: case TAKER_SELLER_WAIT_PAYMENT_STARTED:
processBar.setSelectedIndex(1); processBar.setSelectedIndex(1);
statusTextField.setText("Deposit transaction has at least 1 confirmation. Waiting that other " + statusTextField.setText("Deposit transaction has at least 1 confirmation. Waiting that other " +
"trader starts payment."); "trader starts payment.");
infoDisplay.setText("Deposit transaction has at least one blockchain " + infoDisplay.setText("Deposit transaction has at least one blockchain " +
@ -374,30 +333,24 @@ public class PendingTradesViewCB extends CachedViewCB<PendingTradesPM> {
break; break;
case TAKER_SELLER_CONFIRM_RECEIVE_PAYMENT: case TAKER_SELLER_CONFIRM_RECEIVE_PAYMENT:
processBar.setSelectedIndex(2); processBar.setSelectedIndex(2);
confirmPaymentReceiptButton.setVisible(true);
statusTextField.setText("Payment is on the way. Check your payments account and confirm when you " + statusTextField.setText("Payment is on the way. Check your payments account and confirm when you " +
"have received the payment."); "have received the payment.");
infoDisplay.setText("The other trader has started the payment. You need to check your payments " + infoDisplay.setText("The other trader has started the payment. You need to check your payments " +
"account and confirm the payment when the money has arrived there."); "account and confirm the payment when the money has arrived there.");
confirmPaymentReceiptButton.setVisible(true);
break; break;
case TAKER_SELLER_COMPLETED: case TAKER_SELLER_COMPLETED:
processBar.setSelectedIndex(3); processBar.setSelectedIndex(3);
setSummaryControlsVisible(true);
statusTextField.setText("Trade has successfully completed."); statusTextField.setText("Trade has successfully completed.");
infoDisplay.setText("Trade has successfully completed. You can find the details to that trade" + infoDisplay.setText("Trade has successfully completed. You can find the details to that trade" +
" in the closed trades section."); " in the closed trades section.");
summaryGroupBg.setVisible(true);
btcLabel.setVisible(true);
btcTextField.setVisible(true);
fiatLabel.setVisible(true);
fiatTextField.setVisible(true);
feesLabel.setVisible(true);
feesTextField.setVisible(true);
collateralLabel.setVisible(true);
collateralTextField.setVisible(true);
summaryInfoDisplay.setVisible(true);
btcLabel.setText("You have sold:"); btcLabel.setText("You have sold:");
fiatLabel.setText("You have received:"); fiatLabel.setText("You have received:");
btcTextField.setText(presentationModel.getTradeVolume()); btcTextField.setText(presentationModel.getTradeVolume());
@ -408,9 +361,38 @@ public class PendingTradesViewCB extends CachedViewCB<PendingTradesPM> {
break; break;
} }
} }
else {
processBar.reset();
} }
private void onFault(Throwable fault) {
// TODO
log.error(fault.toString());
}
private void setPaymentsControlsVisible(boolean visible) {
paymentsGroupBg.setVisible(visible);
paymentMethodLabel.setVisible(visible);
holderNameLabel.setVisible(visible);
primaryIdLabel.setVisible(visible);
secondaryIdLabel.setVisible(visible);
paymentMethodTextField.setVisible(visible);
paymentsInfoDisplay.setVisible(visible);
paymentsButton.setVisible(visible);
holderNameTextField.setVisible(visible);
primaryIdTextField.setVisible(visible);
secondaryIdTextField.setVisible(visible);
}
private void setSummaryControlsVisible(boolean visible) {
summaryGroupBg.setVisible(visible);
btcLabel.setVisible(visible);
btcTextField.setVisible(visible);
fiatLabel.setVisible(visible);
fiatTextField.setVisible(visible);
feesLabel.setVisible(visible);
feesTextField.setVisible(visible);
collateralLabel.setVisible(visible);
collateralTextField.setVisible(visible);
summaryInfoDisplay.setVisible(visible);
} }
@ -418,6 +400,54 @@ public class PendingTradesViewCB extends CachedViewCB<PendingTradesPM> {
// CellFactories // CellFactories
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private void setDateColumnCellFactory() {
dateColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
dateColumn.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 item, boolean empty) {
super.updateItem(item, empty);
if (item != null)
setText(presentationModel.getDate(item));
else
setText("");
}
};
}
});
}
private void setTradeIdColumnCellFactory() {
tradeIdColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
tradeIdColumn.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 item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
setText(presentationModel.getTradeId(item));
Tooltip.install(this, new Tooltip(presentationModel.getTradeId(item)));
}
else {
setText("");
}
}
};
}
});
}
private void setAmountColumnCellFactory() { private void setAmountColumnCellFactory() {
amountColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); amountColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
amountColumn.setCellFactory( amountColumn.setCellFactory(
@ -497,62 +527,8 @@ public class PendingTradesViewCB extends CachedViewCB<PendingTradesPM> {
}); });
} }
private void setCountryColumnCellFactory() {
countryColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
countryColumn.setCellFactory(
new Callback<TableColumn<PendingTradesListItem, PendingTradesListItem>, TableCell<PendingTradesListItem,
PendingTradesListItem>>() {
@Override
public TableCell<PendingTradesListItem, PendingTradesListItem> call(
TableColumn<PendingTradesListItem, PendingTradesListItem> column) {
return new TableCell<PendingTradesListItem, PendingTradesListItem>() {
final HBox hBox = new HBox();
{
hBox.setSpacing(3);
hBox.setAlignment(Pos.CENTER);
setGraphic(hBox);
}
@Override
public void updateItem(final PendingTradesListItem item, boolean empty) {
super.updateItem(item, empty);
hBox.getChildren().clear();
if (item != null) {
Country country = item.getOffer().getBankAccountCountry();
hBox.getChildren().add(ImageUtil.getCountryIconImageView(item
.getOffer().getBankAccountCountry()));
Tooltip.install(this, new Tooltip(country.getName()));
}
}
};
}
});
}
private void setBankAccountTypeColumnCellFactory() {
bankAccountTypeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
bankAccountTypeColumn.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 item, boolean empty) {
super.updateItem(item, empty);
setText(presentationModel.getBankAccountType(item));
}
};
}
});
}
private void setSelectColumnCellFactory() { private void setSelectColumnCellFactory() {
selectColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper(offer.getValue())); selectColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
selectColumn.setCellFactory(new Callback<TableColumn<PendingTradesListItem, PendingTradesListItem>, selectColumn.setCellFactory(new Callback<TableColumn<PendingTradesListItem, PendingTradesListItem>,
TableCell<PendingTradesListItem, PendingTradesListItem>>() { TableCell<PendingTradesListItem, PendingTradesListItem>>() {
@Override @Override
@ -581,7 +557,5 @@ public class PendingTradesViewCB extends CachedViewCB<PendingTradesPM> {
} }
}); });
} }
} }

View file

@ -201,9 +201,7 @@ class OrderBookPM extends PresentationModel<OrderBookModel> {
} }
String getDirectionLabel(Offer offer) { String getDirectionLabel(Offer offer) {
// mirror direction! return BSFormatter.formatDirection(offer.getMirroredDirection());
Direction direction = offer.getDirection() == Direction.BUY ? Direction.SELL : Direction.BUY;
return BSFormatter.formatDirection(direction, true);
} }
Direction getDirection() { Direction getDirection() {

View file

@ -141,8 +141,6 @@ public class OrderBookViewCB extends CachedViewCB<OrderBookPM> {
SortedList<OrderBookListItem> offerList = presentationModel.getOfferList(); SortedList<OrderBookListItem> offerList = presentationModel.getOfferList();
orderBookTable.setItems(offerList); orderBookTable.setItems(offerList);
offerList.comparatorProperty().bind(orderBookTable.comparatorProperty()); offerList.comparatorProperty().bind(orderBookTable.comparatorProperty());
priceColumn.setSortType((presentationModel.getDirection() == Direction.BUY) ? priceColumn.setSortType((presentationModel.getDirection() == Direction.BUY) ?
TableColumn.SortType.ASCENDING : TableColumn.SortType.DESCENDING); TableColumn.SortType.ASCENDING : TableColumn.SortType.DESCENDING);
orderBookTable.sort(); orderBookTable.sort();

View file

@ -21,6 +21,7 @@ import io.bitsquare.arbitrator.Arbitrator;
import io.bitsquare.locale.BSResources; import io.bitsquare.locale.BSResources;
import io.bitsquare.locale.Country; import io.bitsquare.locale.Country;
import io.bitsquare.trade.Direction; import io.bitsquare.trade.Direction;
import io.bitsquare.trade.Offer;
import io.bitsquare.user.User; import io.bitsquare.user.User;
import com.google.bitcoin.core.Coin; import com.google.bitcoin.core.Coin;
@ -261,6 +262,10 @@ public class BSFormatter {
} }
} }
public static String formatDirection(Direction direction) {
return formatDirection(direction, true);
}
public static String formatDirection(Direction direction, boolean allUpperCase) { public static String formatDirection(Direction direction, boolean allUpperCase) {
String result = (direction == Direction.BUY) ? "Buy" : "Sell"; String result = (direction == Direction.BUY) ? "Buy" : "Sell";
if (allUpperCase) { if (allUpperCase) {
@ -269,6 +274,14 @@ public class BSFormatter {
return result; return result;
} }
public static String formatAmountWithMinAmount(Offer offer) {
return formatCoin(offer.getAmount()) + " (" + BSFormatter.formatCoin(offer.getMinAmount()) + ")";
}
public static String formatVolumeWithMinVolume(Offer offer) {
return BSFormatter.formatFiat(offer.getOfferVolume()) +
" (" + BSFormatter.formatFiat(offer.getMinOfferVolume()) + ")";
}
public static String countryLocalesToString(List<Country> countries) { public static String countryLocalesToString(List<Country> countries) {
return countries.stream().map(e -> e.getName()).collect(Collectors.joining(", ")); return countries.stream().map(e -> e.getName()).collect(Collectors.joining(", "));
@ -317,10 +330,6 @@ public class BSFormatter {
return decimalFormat.format(value / 100) + " %"; return decimalFormat.format(value / 100) + " %";
} }
public static String formatVolumeWithMinVolume(Fiat volume, Fiat minVolume) {
return formatFiat(volume) + " (" + formatFiat(minVolume) + ")";
}
private static String cleanInput(String input) { private static String cleanInput(String input) {
input = input.replace(",", "."); input = input.replace(",", ".");
// don't use String.valueOf(Double.parseDouble(input)) as return value as it gives scientific // don't use String.valueOf(Double.parseDouble(input)) as return value as it gives scientific

View file

@ -135,6 +135,10 @@ public class Offer implements Serializable {
return direction; return direction;
} }
public Direction getMirroredDirection() {
return direction == Direction.BUY ? Direction.SELL : Direction.BUY;
}
public BankAccountType getBankAccountType() { public BankAccountType getBankAccountType() {
return bankAccountType; return bankAccountType;
} }

View file

@ -23,6 +23,8 @@ import com.google.bitcoin.utils.Fiat;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date;
import javafx.beans.property.BooleanProperty; import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleBooleanProperty;
@ -46,11 +48,13 @@ public class Trade implements Serializable {
PAYMENT_STARTED, PAYMENT_STARTED,
PAYMENT_RECEIVED, /* For taker only*/ PAYMENT_RECEIVED, /* For taker only*/
PAYOUT_PUBLISHED, PAYOUT_PUBLISHED,
FAULT FAULT,
CLOSED
} }
private final Offer offer; private final Offer offer;
private final Date date;
private String takeOfferFeeTxID; private String takeOfferFeeTxID;
private Coin tradeAmount; private Coin tradeAmount;
private Contract contract; private Contract contract;
@ -76,6 +80,7 @@ public class Trade implements Serializable {
public Trade(Offer offer) { public Trade(Offer offer) {
this.offer = offer; this.offer = offer;
date = new Date();
state = State.OPEN; state = State.OPEN;
} }
@ -133,6 +138,7 @@ public class Trade implements Serializable {
faultProperty().set(fault); faultProperty().set(fault);
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Getters // Getters
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -181,6 +187,10 @@ public class Trade implements Serializable {
return contractAsJson; return contractAsJson;
} }
public Date getDate() {
return date;
}
// When serialized those transient properties are not instantiated, so we need to instantiate them at first access // When serialized those transient properties are not instantiated, so we need to instantiate them at first access
public ObjectProperty<Transaction> depositTxProperty() { public ObjectProperty<Transaction> depositTxProperty() {
if (_depositTx == null) if (_depositTx == null)

View file

@ -86,7 +86,7 @@ public class TradeManager {
private final ObservableMap<String, Offer> offers = FXCollections.observableHashMap(); private final ObservableMap<String, Offer> offers = FXCollections.observableHashMap();
private final ObservableMap<String, Trade> trades = FXCollections.observableHashMap(); private final ObservableMap<String, Trade> trades = FXCollections.observableHashMap();
// TODO There might be multiple pending trades // the latest pending trade
private Trade currentPendingTrade; private Trade currentPendingTrade;
@ -385,7 +385,7 @@ public class TradeManager {
//TODO we don't support interruptions yet. //TODO we don't support interruptions yet.
// If the user has shut down the app we lose the offererAsBuyerProtocolMap // If the user has shut down the app we lose the offererAsBuyerProtocolMap
// Also we don't support yet offline messaging (mail box) // Also we don't support yet offline messaging (mail box)
public void bankTransferInited(String tradeId) { public void fiatPaymentStarted(String tradeId) {
if (offererAsBuyerProtocolMap.get(tradeId) != null) { if (offererAsBuyerProtocolMap.get(tradeId) != null) {
offererAsBuyerProtocolMap.get(tradeId).onUIEventBankTransferInited(); offererAsBuyerProtocolMap.get(tradeId).onUIEventBankTransferInited();
trades.get(tradeId).setState(Trade.State.PAYMENT_STARTED); trades.get(tradeId).setState(Trade.State.PAYMENT_STARTED);
@ -398,7 +398,7 @@ public class TradeManager {
} }
} }
public void onFiatReceived(String tradeId) { public void fiatPaymentReceived(String tradeId) {
takerAsSellerProtocolMap.get(tradeId).onUIEventFiatReceived(); takerAsSellerProtocolMap.get(tradeId).onUIEventFiatReceived();
trades.get(tradeId).setState(Trade.State.PAYMENT_RECEIVED); trades.get(tradeId).setState(Trade.State.PAYMENT_RECEIVED);
persistTrades(); persistTrades();
@ -454,9 +454,6 @@ public class TradeManager {
return trades.containsKey(offer.getId()); return trades.containsKey(offer.getId());
} }
public boolean isTradeMyOffer(Trade trade) {
return trade.getOffer().getMessagePublicKey().equals(user.getMessagePublicKey());
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Getters // Getters