Add online state icons to offerbook

This commit is contained in:
Manfred Karrer 2015-03-09 15:32:12 +01:00
parent 9c8ae1bc10
commit 397aedc099
15 changed files with 122 additions and 27 deletions

View file

@ -155,4 +155,17 @@
#image-update-failed { #image-update-failed {
-fx-image: url("../../../images/update/update_failed.png"); -fx-image: url("../../../images/update/update_failed.png");
}
/* offer state */
#image-offer_state_unknown {
-fx-image: url("../../../images/offer/offer_state_unknown.png");
}
#image-offer_state_available {
-fx-image: url("../../../images/offer/offer_state_available.png");
}
#image-offer_state_not_available {
-fx-image: url("../../../images/offer/offer_state_not_available.png");
} }

View file

@ -137,7 +137,7 @@
<!--<TableColumn text="Country" fx:id="countryColumn" minWidth="60"/>--> <!--<TableColumn text="Country" fx:id="countryColumn" minWidth="60"/>-->
<TableColumn text="Bank transfer type" fx:id="bankAccountTypeColumn" minWidth="130"/> <TableColumn text="Bank transfer type" fx:id="bankAccountTypeColumn" minWidth="130"/>
<TableColumn text="" fx:id="directionColumn" minWidth="80" sortable="false"/> <TableColumn text="" fx:id="directionColumn" minWidth="80" sortable="false"/>
<TableColumn text="Online" fx:id="statusColumn" minWidth="20" sortable="false"/>
</columns> </columns>
</TableView> </TableView>

View file

@ -42,7 +42,9 @@ import javax.inject.Inject;
import viewfx.view.FxmlView; import viewfx.view.FxmlView;
import viewfx.view.support.ActivatableViewAndModel; import viewfx.view.support.ActivatableViewAndModel;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.value.ChangeListener;
import javafx.collections.transformation.SortedList; import javafx.collections.transformation.SortedList;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.fxml.FXML; import javafx.fxml.FXML;
@ -67,7 +69,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
@FXML InputTextField volumeTextField, amountTextField, priceTextField; @FXML InputTextField volumeTextField, amountTextField, priceTextField;
@FXML Button createOfferButton, showAdvancedSettingsButton, openCountryFilterButton, openPaymentMethodsFilterButton; @FXML Button createOfferButton, showAdvancedSettingsButton, openCountryFilterButton, openPaymentMethodsFilterButton;
@FXML TableColumn<OfferBookListItem, OfferBookListItem> priceColumn, amountColumn, volumeColumn, directionColumn, @FXML TableColumn<OfferBookListItem, OfferBookListItem> priceColumn, amountColumn, volumeColumn, directionColumn,
/*countryColumn,*/ bankAccountTypeColumn; /*countryColumn,*/ bankAccountTypeColumn, statusColumn;
@FXML Label amountBtcLabel, priceDescriptionLabel, priceFiatLabel, volumeDescriptionLabel, volumeFiatLabel, @FXML Label amountBtcLabel, priceDescriptionLabel, priceFiatLabel, volumeDescriptionLabel, volumeFiatLabel,
extendedButton1Label, extendedButton2Label, extendedCheckBoxLabel; extendedButton1Label, extendedButton2Label, extendedCheckBoxLabel;
@ -107,6 +109,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
/* setCountryColumnCellFactory();*/ /* setCountryColumnCellFactory();*/
setBankAccountTypeColumnCellFactory(); setBankAccountTypeColumnCellFactory();
setDirectionColumnCellFactory(); setDirectionColumnCellFactory();
setStatusColumnCellFactory();
table.getSortOrder().add(priceColumn); table.getSortOrder().add(priceColumn);
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
@ -480,6 +483,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
button.setOnAction(event -> takeOffer(item.getOffer())); button.setOnAction(event -> takeOffer(item.getOffer()));
} }
//TODO remove listener
item.bankAccountCountryProperty().addListener((ov, o, n) -> item.bankAccountCountryProperty().addListener((ov, o, n) ->
verifyIfTradable(item)); verifyIfTradable(item));
verifyIfTradable(item); verifyIfTradable(item);
@ -496,6 +500,66 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
}); });
} }
private void setStatusColumnCellFactory() {
statusColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
statusColumn.setCellFactory(
new Callback<TableColumn<OfferBookListItem, OfferBookListItem>, TableCell<OfferBookListItem,
OfferBookListItem>>() {
@Override
public TableCell<OfferBookListItem, OfferBookListItem> call(
TableColumn<OfferBookListItem, OfferBookListItem> column) {
return new TableCell<OfferBookListItem, OfferBookListItem>() {
final ImageView iconView = new ImageView();
private ChangeListener<Offer.State> stateChangeListener;
private ObjectProperty<Offer.State> stateProperty;
private void updateIcon(final OfferBookListItem item) {
Offer offer = item.getOffer();
if (model.isMyOffer(offer)) {
iconView.setId("image-offer_state_available");
}
else {
switch (offer.getState()) {
case UNKNOWN:
iconView.setId("image-offer_state_unknown");
break;
case OFFER_AVAILABLE:
iconView.setId("image-offer_state_available");
break;
case OFFER_NOT_AVAILABLE:
case OFFER_REMOVED:
iconView.setId("image-offer_state_not_available");
break;
}
}
}
@Override
public void updateItem(final OfferBookListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
stateProperty = item.getOffer().getStateProperty();
this.stateChangeListener = (ov, o, n) -> updateIcon(item);
stateProperty.addListener(stateChangeListener);
updateIcon(item);
setGraphic(iconView);
}
else {
if (stateProperty != null) {
stateProperty.removeListener(stateChangeListener);
stateChangeListener = null;
}
setGraphic(null);
}
}
};
}
});
}
/* private void setCountryColumnCellFactory() { /* private void setCountryColumnCellFactory() {
countryColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); countryColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
countryColumn.setCellFactory( countryColumn.setCellFactory(

View file

@ -82,7 +82,7 @@ class TakeOfferDataModel implements Activatable, DataModel {
final ObjectProperty<Offer.State> offerIsAvailable = new SimpleObjectProperty<>(Offer.State.UNKNOWN); final ObjectProperty<Offer.State> offerIsAvailable = new SimpleObjectProperty<>(Offer.State.UNKNOWN);
@Inject @Inject
public TakeOfferDataModel(TradeManager tradeManager, public TakeOfferDataModel(TradeManager tradeManager,
WalletService walletService, WalletService walletService,
Preferences preferences, Preferences preferences,
Persistence persistence) { Persistence persistence) {
@ -103,6 +103,7 @@ class TakeOfferDataModel implements Activatable, DataModel {
@Override @Override
public void deactivate() { public void deactivate() {
btcCode.unbind(); btcCode.unbind();
tradeManager.stopRequestIsOfferAvailableRequest(offer);
} }
void initWithData(Coin amount, Offer offer) { void initWithData(Coin amount, Offer offer) {

View file

@ -47,6 +47,7 @@ import viewfx.view.FxmlView;
import viewfx.view.support.ActivatableViewAndModel; import viewfx.view.support.ActivatableViewAndModel;
import javafx.beans.property.BooleanProperty; import javafx.beans.property.BooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.geometry.HPos; import javafx.geometry.HPos;
@ -95,6 +96,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
private final Navigation navigation; private final Navigation navigation;
private final OverlayManager overlayManager; private final OverlayManager overlayManager;
private ChangeListener<Offer.State> offerIsAvailableChangeListener;
@Inject @Inject
private TakeOfferView(TakeOfferViewModel model, Navigation navigation, private TakeOfferView(TakeOfferViewModel model, Navigation navigation,
@ -111,6 +113,12 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
setupBindings(); setupBindings();
} }
@Override
protected void doDeactivate() {
if (offerIsAvailableChangeListener != null)
model.offerIsAvailable.removeListener(offerIsAvailableChangeListener);
}
public void initWithData(Direction direction, Coin amount, Offer offer) { public void initWithData(Direction direction, Coin amount, Offer offer) {
model.initWithData(direction, amount, offer); model.initWithData(direction, amount, offer);
@ -140,18 +148,18 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
acceptedLanguagesTextField.setText(model.getAcceptedLanguages()); acceptedLanguagesTextField.setText(model.getAcceptedLanguages());
acceptedArbitratorsTextField.setText(model.getAcceptedArbitrators()); acceptedArbitratorsTextField.setText(model.getAcceptedArbitrators());
model.offerIsAvailable.addListener((ov, oldValue, newValue) -> handleOfferIsAvailableState(newValue)); offerIsAvailableChangeListener = (ov, oldValue, newValue) -> handleOfferIsAvailableState(newValue);
model.offerIsAvailable.addListener(offerIsAvailableChangeListener);
handleOfferIsAvailableState(model.offerIsAvailable.get()); handleOfferIsAvailableState(model.offerIsAvailable.get());
} }
private void handleOfferIsAvailableState(Offer.State state) { private void handleOfferIsAvailableState(Offer.State state) {
isOfferAvailableLabel.setVisible(false); if (state == Offer.State.OFFER_AVAILABLE) {
isOfferAvailableLabel.setManaged(false); isOfferAvailableLabel.setVisible(false);
isOfferAvailableProgressIndicator.setProgress(0); isOfferAvailableLabel.setManaged(false);
isOfferAvailableProgressIndicator.setVisible(false); isOfferAvailableProgressIndicator.setProgress(0);
isOfferAvailableProgressIndicator.setManaged(false); isOfferAvailableProgressIndicator.setVisible(false);
isOfferAvailableProgressIndicator.setManaged(false);
if ((state == Offer.State.OFFER_AVAILABLE)) {
showPaymentInfoScreenButton.setVisible(true); showPaymentInfoScreenButton.setVisible(true);
} }
else if ((state == Offer.State.OFFER_NOT_AVAILABLE)) { else if ((state == Offer.State.OFFER_NOT_AVAILABLE)) {
@ -173,7 +181,6 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
@FXML @FXML
void onTakeOffer() { void onTakeOffer() {
model.takeOffer(); model.takeOffer();
} }
@FXML @FXML
@ -261,7 +268,8 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
// Might fix #315 Offerbook tab gets closed // Might fix #315 Offerbook tab gets closed
//tabPane.getTabs().remove(tabPane.getSelectionModel().getSelectedItem()); //tabPane.getTabs().remove(tabPane.getSelectionModel().getSelectedItem());
tabPane.getTabs().remove(1); if (tabPane != null && tabPane.getTabs() != null && tabPane.getTabs().size() > 1)
tabPane.getTabs().remove(1);
} }
private void setupListeners() { private void setupListeners() {

View file

@ -80,7 +80,7 @@ public class Offer implements Serializable {
private String offerFeePaymentTxID; private String offerFeePaymentTxID;
// Those state properties are transient and only used at runtime! // Those state properties are transient and only used at runtime!
private transient State state = State.UNKNOWN; private transient State state;
// don't access directly as it might be null; use getStateProperty() which creates an object if not instantiated // don't access directly as it might be null; use getStateProperty() which creates an object if not instantiated
private transient ObjectProperty<State> stateProperty; private transient ObjectProperty<State> stateProperty;
@ -120,6 +120,7 @@ public class Offer implements Serializable {
this.acceptedLanguageLocales = acceptedLanguageLocales; this.acceptedLanguageLocales = acceptedLanguageLocales;
creationDate = new Date(); creationDate = new Date();
state = State.UNKNOWN;
getStateProperty().set(state); getStateProperty().set(state);
} }
@ -225,6 +226,9 @@ public class Offer implements Serializable {
} }
public State getState() { public State getState() {
if(state == null)
setState(State.UNKNOWN);
return state; return state;
} }

View file

@ -94,7 +94,7 @@ public class OfferBook {
offer.setState(Offer.State.OFFER_REMOVED); offer.setState(Offer.State.OFFER_REMOVED);
// clean up possible references in tradeManager // clean up possible references in tradeManager
tradeManager.handleRemovedOffer(offer); tradeManager.onOfferRemovedFromRemoteOfferBook(offer);
offerBookListItems.removeIf(item -> item.getOffer().getId().equals(offer.getId())); offerBookListItems.removeIf(item -> item.getOffer().getId().equals(offer.getId()));
} }

View file

@ -436,8 +436,13 @@ public class TradeManager {
log.warn("requestIsOfferAvailable already called for offer with ID:" + offer.getId()); log.warn("requestIsOfferAvailable already called for offer with ID:" + offer.getId());
} }
} }
public void handleRemovedOffer(Offer offer) { // When closing take offer view, we are not interested in the requestIsOfferAvailable result anymore, so remove from the map
public void stopRequestIsOfferAvailableRequest(Offer offer) {
requestIsOfferAvailableProtocolMap.remove(offer.getId());
}
public void onOfferRemovedFromRemoteOfferBook(Offer offer) {
requestIsOfferAvailableProtocolMap.remove(offer.getId()); requestIsOfferAvailableProtocolMap.remove(offer.getId());
} }

View file

@ -70,31 +70,31 @@ public class RequestIsOfferAvailableProtocol {
// 1. GetPeerAddress // 1. GetPeerAddress
// Async // Async
// In case of an error: Repeat once, then give up. // In case of an error: Don't repeat call for now, maybe in production repeat once.
private void getPeerAddress() { private void getPeerAddress() {
log.debug("getPeerAddress called"); log.debug("getPeerAddress called");
GetPeerAddress.run(this::onResultGetPeerAddress, this::onGetPeerAddressFault, tradeMessageService, offererMessagePublicKey);
}
private void onGetPeerAddressFault(String errorMessage) {
GetPeerAddress.run(this::onResultGetPeerAddress, this::handleErrorMessage, tradeMessageService, offererMessagePublicKey); GetPeerAddress.run(this::onResultGetPeerAddress, this::handleErrorMessage, tradeMessageService, offererMessagePublicKey);
} }
/* private void onGetPeerAddressFault(String errorMessage) {
GetPeerAddress.run(this::onResultGetPeerAddress, this::handleErrorMessage, tradeMessageService, offererMessagePublicKey);
}*/
// 2. RequestTakeOffer // 2. RequestTakeOffer
// Async // Async
// In case of an error: Repeat once, then give up. // In case of an error: Don't repeat call for now, maybe in production repeat once.
public void onResultGetPeerAddress(Peer peer) { public void onResultGetPeerAddress(Peer peer) {
log.debug("onResultGetPeerAddress called"); log.debug("onResultGetPeerAddress called");
this.peer = peer; this.peer = peer;
RequestIsOfferAvailable.run(this::onRequestIsOfferAvailableFault, peer, tradeMessageService, offerId);
}
private void onRequestIsOfferAvailableFault(String errorMessage) {
RequestIsOfferAvailable.run(this::handleErrorMessage, peer, tradeMessageService, offerId); RequestIsOfferAvailable.run(this::handleErrorMessage, peer, tradeMessageService, offerId);
} }
/* private void onRequestIsOfferAvailableFault(String errorMessage) {
RequestIsOfferAvailable.run(this::handleErrorMessage, peer, tradeMessageService, offerId);
}*/
// generic // generic
private void handleErrorMessage(String errorMessage) { private void handleErrorMessage(String errorMessage) {
offer.setState(Offer.State.OFFER_NOT_AVAILABLE); offer.setState(Offer.State.OFFER_NOT_AVAILABLE);

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB