Fix pending trades view update bugs

This commit is contained in:
Manfred Karrer 2015-03-19 16:32:12 +01:00
parent 0ac6b39270
commit b416408f89
4 changed files with 89 additions and 52 deletions

View file

@ -21,13 +21,13 @@ import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.WalletService;
import io.bitsquare.btc.listeners.TxConfidenceListener;
import io.bitsquare.common.viewfx.model.Activatable;
import io.bitsquare.common.viewfx.model.DataModel;
import io.bitsquare.offer.Direction;
import io.bitsquare.offer.Offer;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.TradeManager;
import io.bitsquare.user.User;
import io.bitsquare.common.viewfx.model.Activatable;
import io.bitsquare.common.viewfx.model.DataModel;
import org.bitcoinj.core.AddressFormatException;
import org.bitcoinj.core.Coin;
@ -39,9 +39,9 @@ import com.google.common.util.concurrent.FutureCallback;
import com.google.inject.Inject;
import java.util.Optional;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
@ -67,14 +67,14 @@ class PendingTradesDataModel implements Activatable, DataModel {
private PendingTradesListItem selectedItem;
private boolean isOfferer;
private Trade closedTrade;
private TxConfidenceListener txConfidenceListener;
private final ChangeListener<Trade.State> stateChangeListener;
private TxConfidenceListener txConfidenceListener;
private final ChangeListener<Trade.State> tradeStateChangeListener;
private final MapChangeListener<String, Trade> mapChangeListener;
final StringProperty txId = new SimpleStringProperty();
final ObjectProperty<Trade.State> tradeState = new SimpleObjectProperty<>();
final IntegerProperty selectedIndex = new SimpleIntegerProperty(-1);
@Inject
public PendingTradesDataModel(TradeManager tradeManager, WalletService walletService, User user) {
@ -82,13 +82,23 @@ class PendingTradesDataModel implements Activatable, DataModel {
this.walletService = walletService;
this.user = user;
this.stateChangeListener = (ov, oldValue, newValue) -> tradeState.set(newValue);
tradeStateChangeListener = (ov, oldValue, newValue) -> tradeState.set(newValue);
this.mapChangeListener = change -> {
if (change.wasAdded())
mapChangeListener = change -> {
if (change.wasAdded()) {
list.add(new PendingTradesListItem(change.getValueAdded()));
else if (change.wasRemoved())
if (list.size() == 1) {
selectTrade(list.get(0));
selectedIndex.set(0);
}
}
else if (change.wasRemoved()) {
closedTrade = change.getValueRemoved();
if (list.size() == 0) {
selectTrade(null);
selectedIndex.set(-1);
}
}
sortList();
};
@ -98,27 +108,33 @@ class PendingTradesDataModel implements Activatable, DataModel {
public void activate() {
list.clear();
// transform trades to list of PendingTradesListItems and keep it updated
tradeManager.getPendingTrades().values().stream()
.forEach(e -> list.add(new PendingTradesListItem(e)));
tradeManager.getPendingTrades().values().stream().forEach(e -> list.add(new PendingTradesListItem(e)));
tradeManager.getPendingTrades().addListener(mapChangeListener);
// we sort by date, earliest first
sortList();
// 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())
selectTrade(currentTradeItemOptional.get());
else if (list.size() > 0)
if (tradeManager.getCurrentPendingTrade() != null) {
for (int i = 0; i < list.size(); i++) {
PendingTradesListItem item = list.get(i);
if (tradeManager.getCurrentPendingTrade().getId().equals(item.getTrade().getId())) {
selectedIndex.set(i);
selectTrade(item);
break;
}
}
}
else if (list.size() > 0) {
selectTrade(list.get(0));
selectedIndex.set(0);
}
}
@Override
public void deactivate() {
tradeManager.getPendingTrades().removeListener(mapChangeListener);
cleanUpSelectedTrade();
}
@ -133,7 +149,7 @@ class PendingTradesDataModel implements Activatable, DataModel {
isOfferer = getTrade().getOffer().getMessagePublicKey().equals(user.getMessagePubKey());
Trade trade = getTrade();
trade.stateProperty().addListener(stateChangeListener);
trade.stateProperty().addListener(tradeStateChangeListener);
tradeState.set(trade.stateProperty().get());
log.trace("selectTrade trade.stateProperty().get() " + trade.stateProperty().get());
@ -287,8 +303,7 @@ class PendingTradesDataModel implements Activatable, DataModel {
private void cleanUpSelectedTrade() {
if (selectedItem != null) {
Trade trade = getTrade();
trade.stateProperty().removeListener(stateChangeListener);
selectedItem.getTrade().stateProperty().removeListener(tradeStateChangeListener);
}
if (txConfidenceListener != null)

View file

@ -82,13 +82,15 @@ public class PendingTradesView extends ActivatableViewAndModel<AnchorPane, Pendi
@FXML TableColumn<PendingTradesListItem, Date> dateColumn;
@FXML TableColumn<PendingTradesListItem, Coin> tradeAmountColumn;
private ChangeListener<PendingTradesListItem> selectedItemChangeListener;
private ChangeListener<Number> selectedIndexChangeListener;
private ListChangeListener<PendingTradesListItem> listChangeListener;
private ChangeListener<String> txIdChangeListener;
private ChangeListener<PendingTradesViewModel.State> offererStateChangeListener;
private ChangeListener<PendingTradesViewModel.State> takerStateChangeListener;
private final Navigation navigation;
private ChangeListener<Boolean> focusedPropertyListener;
private ChangeListener<PendingTradesListItem> selectedItemChangeListener;
@Inject
public PendingTradesView(PendingTradesViewModel model, Navigation navigation) {
@ -112,60 +114,68 @@ public class PendingTradesView extends ActivatableViewAndModel<AnchorPane, Pendi
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
table.setPlaceholder(new Label("No pending trades available"));
txIdChangeListener = (ov, oldValue, newValue) ->
txIdTextField.setup(model.getWalletService(), newValue);
txIdChangeListener = (ov, oldValue, newValue) -> txIdTextField.setup(model.getWalletService(), newValue);
selectedItemChangeListener = (obsValue, oldValue, newValue) -> {
if (oldValue != null && newValue != null) {
model.selectTrade(newValue);
updateScreen();
}
selectedIndexChangeListener = (ov, oldValue, newValue) -> {
if ((Integer) newValue > -1)
table.getSelectionModel().select((Integer) newValue);
updateScreen();
};
listChangeListener = change -> {
change.next();
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);
focusedPropertyListener = (ov, oldValue, newValue) -> {
if (oldValue && !newValue)
model.withdrawAddressFocusOut(withdrawAddressTextField.getText());
};
selectedItemChangeListener = (ov, oldValue, newValue) -> {
model.selectTrade(newValue);
updateScreen();
};
withdrawAddressTextField.setValidator(model.getBtcAddressValidator());
withdrawButton.disableProperty().bind(model.withdrawalButtonDisable);
}
@Override
public void doActivate() {
table.setItems(model.getList());
table.getSelectionModel().selectedItemProperty().addListener(selectedItemChangeListener);
model.getList().addListener(listChangeListener);
model.txId.addListener(txIdChangeListener);
model.selectedIndex.addListener(selectedIndexChangeListener);
withdrawAddressTextField.focusedProperty().addListener(focusedPropertyListener);
txIdTextField.setup(model.getWalletService(), model.txId.get());
table.getSelectionModel().select(model.getSelectedItem());
table.getSelectionModel().selectedItemProperty().addListener(selectedItemChangeListener);
// TODO Set focus to row does not work yet...
/* table.requestFocus();
table.getFocusModel().focus( table.getSelectionModel().getSelectedIndex());*/
Platform.runLater(() -> table.requestFocus());
table.getFocusModel().focus(model.selectedIndex.get());
txIdTextField.setup(model.getWalletService(), model.txId.get());
selectedIndexChangeListener.changed(null, null, model.selectedIndex.get());
withdrawAddressTextField.focusedProperty().addListener((ov, oldValue, newValue) -> {
if (oldValue && !newValue)
model.withdrawAddressFocusOut(withdrawAddressTextField.getText());
});
withdrawButton.disableProperty().bind(model.withdrawalButtonDisable);
updateScreen();
}
@Override
public void doDeactivate() {
table.getSelectionModel().selectedItemProperty().removeListener(selectedItemChangeListener);
model.getList().removeListener(listChangeListener);
model.txId.removeListener(txIdChangeListener);
model.state.removeListener(offererStateChangeListener);
model.state.removeListener(takerStateChangeListener);
model.selectedIndex.removeListener(selectedIndexChangeListener);
table.getSelectionModel().selectedItemProperty().removeListener(selectedItemChangeListener);
withdrawButton.disableProperty().unbind();
}
@FXML
@ -450,7 +460,8 @@ public class PendingTradesView extends ActivatableViewAndModel<AnchorPane, Pendi
fiatAmountTextField.setManaged(visible);
holderNameTextField.setManaged(visible);
Platform.runLater(() -> scrollPane.setVvalue(visible ? scrollPane.getVmax() : 0));
if (visible)
Platform.runLater(() -> scrollPane.setVvalue(scrollPane.getVmax()));
}
private void setSummaryControlsVisible(boolean visible) {
@ -491,11 +502,14 @@ public class PendingTradesView extends ActivatableViewAndModel<AnchorPane, Pendi
withdrawButton.setManaged(visible);
if (visible)
withdrawAddressTextField.requestFocus();
Platform.runLater(() -> scrollPane.setVvalue(visible ? scrollPane.getVmax() : 0));
Platform.runLater(() -> {
withdrawAddressTextField.requestFocus();
scrollPane.setVvalue(scrollPane.getVmax());
});
}
// CellFactories
private void setTradeIdColumnCellFactory() {
idColumn.setCellFactory(
new Callback<TableColumn<PendingTradesListItem, String>, TableCell<PendingTradesListItem, String>>() {

View file

@ -34,8 +34,10 @@ import java.util.Date;
import javafx.beans.InvalidationListener;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
@ -66,6 +68,7 @@ class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataM
final StringProperty txId = new SimpleStringProperty();
final ObjectProperty<State> state = new SimpleObjectProperty<>();
final BooleanProperty withdrawalButtonDisable = new SimpleBooleanProperty(true);
final IntegerProperty selectedIndex = new SimpleIntegerProperty(-1);
@Inject
@ -81,6 +84,7 @@ class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataM
@Override
public void doActivate() {
txId.bind(dataModel.txId);
selectedIndex.bind(dataModel.selectedIndex);
dataModel.tradeState.addListener(stateChangeListener);
updateState();
@ -89,6 +93,7 @@ class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataM
@Override
public void doDeactivate() {
txId.unbind();
selectedIndex.unbind();
dataModel.tradeState.removeListener(stateChangeListener);
}

View file

@ -48,6 +48,8 @@ import io.bitsquare.user.User;
import org.bitcoinj.core.Coin;
import org.bitcoinj.utils.Fiat;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
@ -102,17 +104,17 @@ public class TradeManager {
this.signatureService = signatureService;
this.offerBookService = offerBookService;
Object openOffersObject = persistence.read(this, "openOffers");
Serializable openOffersObject = persistence.read(this, "openOffers");
if (openOffersObject instanceof Map<?, ?>) {
openOffers.putAll((Map<String, Offer>) openOffersObject);
}
Object pendingTradesObject = persistence.read(this, "pendingTrades");
Serializable pendingTradesObject = persistence.read(this, "pendingTrades");
if (pendingTradesObject instanceof Map<?, ?>) {
pendingTrades.putAll((Map<String, Trade>) pendingTradesObject);
}
Object closedTradesObject = persistence.read(this, "closedTrades");
Serializable closedTradesObject = persistence.read(this, "closedTrades");
if (closedTradesObject instanceof Map<?, ?>) {
closedTrades.putAll((Map<String, Trade>) closedTradesObject);
}
@ -120,7 +122,8 @@ public class TradeManager {
tradeMessageService.addMessageHandler(this::handleMessage);
}
// When all services are initialized we create the protocols for our open offers (which will listen for take offer requests)
// When all services are initialized we create the protocols for our open offers and persisted not completed pendingTrades
// BuyerAcceptsOfferProtocol listens for take offer requests, so we need to instantiate it early.
public void onAllServicesInitialized() {
for (Map.Entry<String, Offer> entry : openOffers.entrySet()) {
createBuyerAcceptsOfferProtocol(entry.getValue());