mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-24 23:18:17 +01:00
Fixed state handling in views
This commit is contained in:
parent
9936dca851
commit
ccd2e6b676
10 changed files with 235 additions and 168 deletions
|
@ -78,7 +78,7 @@ class ClosedTradesViewModel extends ActivatableWithDataModel<ClosedTradesDataMod
|
|||
case FAILED:
|
||||
return "Failed";
|
||||
case PENDING:
|
||||
throw new RuntimeException("Wrong state: " + lifeCycleState);
|
||||
throw new RuntimeException("That must not happen. We got a pending state but we are in the closed trades list.");
|
||||
}
|
||||
}
|
||||
else if (lifeCycleState instanceof OffererTrade.OffererLifeCycleState) {
|
||||
|
@ -91,11 +91,10 @@ class ClosedTradesViewModel extends ActivatableWithDataModel<ClosedTradesDataMod
|
|||
return "Failed";
|
||||
case OPEN_OFFER:
|
||||
case PENDING:
|
||||
throw new RuntimeException("Wrong state: " + lifeCycleState);
|
||||
throw new RuntimeException("That must not happen. We got a pending state but we are in the closed trades list.");
|
||||
}
|
||||
}
|
||||
|
||||
return "Undefined";
|
||||
throw new RuntimeException("That must not happen. We got no defined state.");
|
||||
}
|
||||
else {
|
||||
return "";
|
||||
|
|
|
@ -17,22 +17,19 @@
|
|||
|
||||
package io.bitsquare.gui.main.portfolio.pending;
|
||||
|
||||
import io.bitsquare.btc.AddressEntry;
|
||||
import io.bitsquare.btc.FeePolicy;
|
||||
import io.bitsquare.btc.WalletService;
|
||||
import io.bitsquare.common.viewfx.model.Activatable;
|
||||
import io.bitsquare.common.viewfx.model.DataModel;
|
||||
import io.bitsquare.gui.components.Popups;
|
||||
import io.bitsquare.offer.Offer;
|
||||
import io.bitsquare.trade.OffererTrade;
|
||||
import io.bitsquare.trade.TakerTrade;
|
||||
import io.bitsquare.trade.Trade;
|
||||
import io.bitsquare.trade.TradeManager;
|
||||
import io.bitsquare.user.User;
|
||||
|
||||
import org.bitcoinj.core.AddressFormatException;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.InsufficientMoneyException;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
|
@ -44,13 +41,10 @@ import javafx.beans.property.SimpleIntegerProperty;
|
|||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -65,28 +59,27 @@ class PendingTradesDataModel implements Activatable, DataModel {
|
|||
|
||||
private PendingTradesListItem selectedItem;
|
||||
private boolean isOfferer;
|
||||
private Trade closedTrade;
|
||||
|
||||
private final ChangeListener<Trade.ProcessState> tradeStateChangeListener;
|
||||
private final ListChangeListener<Trade> tradesListChangeListener;
|
||||
|
||||
final StringProperty txId = new SimpleStringProperty();
|
||||
final ObjectProperty<Trade.ProcessState> tradeState = new SimpleObjectProperty<>();
|
||||
final IntegerProperty selectedIndex = new SimpleIntegerProperty(-1);
|
||||
|
||||
final ObjectProperty<TakerTrade.TakerProcessState> takerProcessState = new SimpleObjectProperty<>();
|
||||
final ObjectProperty<OffererTrade.OffererProcessState> offererProcessState = new SimpleObjectProperty<>();
|
||||
|
||||
@Inject
|
||||
public PendingTradesDataModel(TradeManager tradeManager, WalletService walletService, User user) {
|
||||
this.tradeManager = tradeManager;
|
||||
this.walletService = walletService;
|
||||
this.user = user;
|
||||
|
||||
tradeStateChangeListener = (ov, oldValue, newValue) -> tradeState.set(newValue);
|
||||
tradesListChangeListener = change -> applyList();
|
||||
tradesListChangeListener = change -> onListChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activate() {
|
||||
applyList();
|
||||
onListChanged();
|
||||
tradeManager.getPendingTrades().addListener(tradesListChangeListener);
|
||||
|
||||
if (list.size() > 0) {
|
||||
|
@ -98,10 +91,10 @@ class PendingTradesDataModel implements Activatable, DataModel {
|
|||
@Override
|
||||
public void deactivate() {
|
||||
tradeManager.getPendingTrades().removeListener(tradesListChangeListener);
|
||||
cleanUpSelectedTrade();
|
||||
removeListenerFromSelectedTrade();
|
||||
}
|
||||
|
||||
private void applyList() {
|
||||
private void onListChanged() {
|
||||
list.clear();
|
||||
list.addAll(tradeManager.getPendingTrades().stream().map(PendingTradesListItem::new).collect(Collectors.toList()));
|
||||
|
||||
|
@ -116,7 +109,7 @@ class PendingTradesDataModel implements Activatable, DataModel {
|
|||
|
||||
void selectTrade(PendingTradesListItem item) {
|
||||
// clean up previous selectedItem
|
||||
cleanUpSelectedTrade();
|
||||
removeListenerFromSelectedTrade();
|
||||
|
||||
selectedItem = item;
|
||||
|
||||
|
@ -124,8 +117,11 @@ class PendingTradesDataModel implements Activatable, DataModel {
|
|||
isOfferer = getTrade().getOffer().getP2PSigPubKey().equals(user.getP2PSigPubKey());
|
||||
|
||||
Trade trade = getTrade();
|
||||
trade.processStateProperty().addListener(tradeStateChangeListener);
|
||||
tradeState.set(trade.processStateProperty().get());
|
||||
if (trade instanceof TakerTrade)
|
||||
takerProcessState.bind(((TakerTrade) trade).processStateProperty());
|
||||
else
|
||||
offererProcessState.bind(((OffererTrade) trade).processStateProperty());
|
||||
|
||||
log.trace("selectTrade trade.stateProperty().get() " + trade.processStateProperty().get());
|
||||
|
||||
if (trade.getDepositTx() != null)
|
||||
|
@ -133,7 +129,6 @@ class PendingTradesDataModel implements Activatable, DataModel {
|
|||
}
|
||||
else {
|
||||
txId.set(null);
|
||||
tradeState.set(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,34 +141,14 @@ class PendingTradesDataModel implements Activatable, DataModel {
|
|||
}
|
||||
|
||||
void withdraw(String toAddress) {
|
||||
FutureCallback<Transaction> callback = new FutureCallback<Transaction>() {
|
||||
@Override
|
||||
public void onSuccess(@javax.annotation.Nullable Transaction transaction) {
|
||||
if (transaction != null) {
|
||||
log.info("onWithdraw onSuccess tx ID:" + transaction.getHashAsString());
|
||||
tradeManager.requestWithdraw(toAddress,
|
||||
getTrade(),
|
||||
() -> log.debug("requestWithdraw was successful"),
|
||||
(errorMessage, throwable) -> {
|
||||
log.error(errorMessage);
|
||||
Popups.openExceptionPopup(throwable);
|
||||
});
|
||||
|
||||
if (closedTrade != null) {
|
||||
list.removeIf(e -> e.getTrade().getId().equals(closedTrade.getId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NotNull Throwable t) {
|
||||
log.debug("onWithdraw onFailure");
|
||||
}
|
||||
};
|
||||
|
||||
AddressEntry addressEntry = walletService.getAddressEntry(getTrade().getId());
|
||||
String fromAddress = addressEntry.getAddressString();
|
||||
try {
|
||||
walletService.sendFunds(fromAddress, toAddress, getAmountToWithdraw(), callback);
|
||||
} catch (AddressFormatException | InsufficientMoneyException e) {
|
||||
e.printStackTrace();
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
|
||||
tradeManager.onWithdrawAtTradeCompleted(getTrade());
|
||||
|
||||
/*
|
||||
Action response = Popups.openConfirmPopup(
|
||||
|
@ -203,7 +178,6 @@ class PendingTradesDataModel implements Activatable, DataModel {
|
|||
}*/
|
||||
}
|
||||
|
||||
|
||||
ObservableList<PendingTradesListItem> getList() {
|
||||
return list;
|
||||
}
|
||||
|
@ -232,32 +206,36 @@ class PendingTradesDataModel implements Activatable, DataModel {
|
|||
return selectedItem.getTrade().getOffer().getCurrencyCode();
|
||||
}
|
||||
|
||||
Throwable getTradeException() {
|
||||
return getTrade().getThrowable();
|
||||
}
|
||||
|
||||
String getErrorMessage() {
|
||||
return getTrade().getErrorMessage();
|
||||
}
|
||||
|
||||
public Offer.Direction getDirection(Offer offer) {
|
||||
return offer.getP2PSigPubKey().equals(user.getP2PSigPubKey()) ?
|
||||
offer.getDirection() : offer.getMirroredDirection();
|
||||
}
|
||||
|
||||
Coin getAmountToWithdraw() {
|
||||
AddressEntry addressEntry = walletService.getAddressEntry(getTrade().getId());
|
||||
log.debug("trade id " + getTrade().getId());
|
||||
log.debug("getAddressString " + addressEntry.getAddressString());
|
||||
log.debug("funds " + walletService.getBalanceForAddress(addressEntry.getAddress()).subtract(FeePolicy
|
||||
.TX_FEE).toString());
|
||||
// return walletService.getBalanceForAddress(addressEntry.getAddress()).subtract(FeePolicy.TX_FEE);
|
||||
|
||||
// TODO handle overpaid securityDeposit
|
||||
if (isOfferer())
|
||||
return getTrade().getTradeAmount().add(getTrade().getOffer().getSecurityDeposit());
|
||||
else
|
||||
return getTrade().getSecurityDeposit();
|
||||
}
|
||||
|
||||
|
||||
private void cleanUpSelectedTrade() {
|
||||
private void removeListenerFromSelectedTrade() {
|
||||
if (selectedItem != null) {
|
||||
selectedItem.getTrade().processStateProperty().removeListener(tradeStateChangeListener);
|
||||
Trade trade = selectedItem.getTrade();
|
||||
if (trade instanceof TakerTrade)
|
||||
takerProcessState.unbind();
|
||||
else
|
||||
offererProcessState.unbind();
|
||||
}
|
||||
}
|
||||
|
||||
public Coin getAmountToWithdraw() {
|
||||
Trade trade = selectedItem.getTrade();
|
||||
Coin amountToWithdraw = trade.getSecurityDeposit();
|
||||
if (trade instanceof OffererTrade)
|
||||
amountToWithdraw = amountToWithdraw.add(trade.getTradeAmount());
|
||||
return amountToWithdraw;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -85,8 +85,8 @@ public class PendingTradesView extends ActivatableViewAndModel<AnchorPane, Pendi
|
|||
private ChangeListener<Number> selectedIndexChangeListener;
|
||||
private ListChangeListener<PendingTradesListItem> listChangeListener;
|
||||
private ChangeListener<String> txIdChangeListener;
|
||||
private ChangeListener<PendingTradesViewModel.State> offererStateChangeListener;
|
||||
private ChangeListener<PendingTradesViewModel.State> takerStateChangeListener;
|
||||
private ChangeListener<PendingTradesViewModel.ViewState> offererStateChangeListener;
|
||||
private ChangeListener<PendingTradesViewModel.ViewState> takerStateChangeListener;
|
||||
|
||||
private final Navigation navigation;
|
||||
private ChangeListener<Boolean> focusedPropertyListener;
|
||||
|
@ -170,8 +170,8 @@ public class PendingTradesView extends ActivatableViewAndModel<AnchorPane, Pendi
|
|||
public void doDeactivate() {
|
||||
model.getList().removeListener(listChangeListener);
|
||||
model.txId.removeListener(txIdChangeListener);
|
||||
model.state.removeListener(offererStateChangeListener);
|
||||
model.state.removeListener(takerStateChangeListener);
|
||||
model.viewState.removeListener(offererStateChangeListener);
|
||||
model.viewState.removeListener(takerStateChangeListener);
|
||||
model.selectedIndex.removeListener(selectedIndexChangeListener);
|
||||
table.getSelectionModel().selectedItemProperty().removeListener(selectedItemChangeListener);
|
||||
|
||||
|
@ -258,8 +258,8 @@ public class PendingTradesView extends ActivatableViewAndModel<AnchorPane, Pendi
|
|||
processBar.setProcessStepItems(items);
|
||||
}
|
||||
|
||||
model.state.addListener(offererStateChangeListener);
|
||||
applyOffererState(model.state.get());
|
||||
model.viewState.addListener(offererStateChangeListener);
|
||||
applyOffererState(model.viewState.get());
|
||||
}
|
||||
|
||||
private void setupScreenForTaker() {
|
||||
|
@ -273,18 +273,18 @@ public class PendingTradesView extends ActivatableViewAndModel<AnchorPane, Pendi
|
|||
processBar.setProcessStepItems(items);
|
||||
}
|
||||
|
||||
model.state.addListener(takerStateChangeListener);
|
||||
applyTakerState(model.state.get());
|
||||
model.viewState.addListener(takerStateChangeListener);
|
||||
applyTakerState(model.viewState.get());
|
||||
}
|
||||
|
||||
private void applyOffererState(PendingTradesViewModel.State state) {
|
||||
private void applyOffererState(PendingTradesViewModel.ViewState viewState) {
|
||||
setPaymentsControlsVisible(false);
|
||||
setSummaryControlsVisible(false);
|
||||
log.debug("applyOffererState " + state);
|
||||
log.debug("applyOffererState " + viewState);
|
||||
processBar.reset();
|
||||
|
||||
if (state != null) {
|
||||
switch (state) {
|
||||
if (viewState != null) {
|
||||
switch (viewState) {
|
||||
case OFFERER_BUYER_WAIT_TX_CONF:
|
||||
processBar.setSelectedIndex(0);
|
||||
|
||||
|
@ -347,21 +347,27 @@ public class PendingTradesView extends ActivatableViewAndModel<AnchorPane, Pendi
|
|||
|
||||
withdrawAmountTextField.setText(model.getAmountToWithdraw());
|
||||
break;
|
||||
case MESSAGE_SENDING_FAILED:
|
||||
Popups.openWarningPopup("Sending message to trading peer failed.", model.getErrorMessage());
|
||||
break;
|
||||
case EXCEPTION:
|
||||
Popups.openExceptionPopup(model.getTradeException());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void applyTakerState(PendingTradesViewModel.State state) {
|
||||
private void applyTakerState(PendingTradesViewModel.ViewState viewState) {
|
||||
confirmPaymentReceiptButton.setVisible(false);
|
||||
confirmPaymentReceiptButton.setManaged(false);
|
||||
|
||||
setSummaryControlsVisible(false);
|
||||
|
||||
processBar.reset();
|
||||
log.debug("applyTakerState " + state);
|
||||
log.debug("applyTakerState " + viewState);
|
||||
|
||||
if (state != null) {
|
||||
switch (state) {
|
||||
if (viewState != null) {
|
||||
switch (viewState) {
|
||||
case TAKER_SELLER_WAIT_TX_CONF:
|
||||
processBar.setSelectedIndex(0);
|
||||
|
||||
|
@ -422,6 +428,12 @@ public class PendingTradesView extends ActivatableViewAndModel<AnchorPane, Pendi
|
|||
|
||||
withdrawAmountTextField.setText(model.getAmountToWithdraw());
|
||||
break;
|
||||
case MESSAGE_SENDING_FAILED:
|
||||
Popups.openWarningPopup("Sending message to trading peer failed.", model.getErrorMessage());
|
||||
break;
|
||||
case EXCEPTION:
|
||||
Popups.openExceptionPopup(model.getTradeException());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@ import io.bitsquare.gui.util.validation.BtcAddressValidator;
|
|||
import io.bitsquare.locale.BSResources;
|
||||
import io.bitsquare.trade.OffererTrade;
|
||||
import io.bitsquare.trade.TakerTrade;
|
||||
import io.bitsquare.trade.Trade;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.utils.Fiat;
|
||||
|
@ -51,7 +50,7 @@ import org.slf4j.LoggerFactory;
|
|||
class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataModel> implements ViewModel {
|
||||
private static final Logger log = LoggerFactory.getLogger(PendingTradesViewModel.class);
|
||||
|
||||
enum State {
|
||||
enum ViewState {
|
||||
TAKER_SELLER_WAIT_TX_CONF,
|
||||
TAKER_SELLER_WAIT_PAYMENT_STARTED,
|
||||
TAKER_SELLER_CONFIRM_RECEIVE_PAYMENT,
|
||||
|
@ -61,16 +60,20 @@ class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataM
|
|||
OFFERER_BUYER_START_PAYMENT,
|
||||
OFFERER_BUYER_WAIT_CONFIRM_PAYMENT_RECEIVED,
|
||||
OFFERER_BUYER_COMPLETED,
|
||||
|
||||
MESSAGE_SENDING_FAILED,
|
||||
EXCEPTION
|
||||
}
|
||||
|
||||
private final BSFormatter formatter;
|
||||
private final InvalidationListener stateChangeListener;
|
||||
private final InvalidationListener takerStateListener;
|
||||
private final InvalidationListener offererStateListener;
|
||||
private final BtcAddressValidator btcAddressValidator;
|
||||
|
||||
final StringProperty txId = new SimpleStringProperty();
|
||||
final ObjectProperty<State> state = new SimpleObjectProperty<>();
|
||||
final BooleanProperty withdrawalButtonDisable = new SimpleBooleanProperty(true);
|
||||
final IntegerProperty selectedIndex = new SimpleIntegerProperty(-1);
|
||||
final ObjectProperty<ViewState> viewState = new SimpleObjectProperty<>();
|
||||
|
||||
|
||||
@Inject
|
||||
|
@ -80,7 +83,8 @@ class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataM
|
|||
|
||||
this.formatter = formatter;
|
||||
this.btcAddressValidator = btcAddressValidator;
|
||||
this.stateChangeListener = (ov) -> updateState();
|
||||
this.takerStateListener = (ov) -> updateTakerState();
|
||||
this.offererStateListener = (ov) -> updateOffererState();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -88,8 +92,11 @@ class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataM
|
|||
txId.bind(dataModel.txId);
|
||||
selectedIndex.bind(dataModel.selectedIndex);
|
||||
|
||||
dataModel.tradeState.addListener(stateChangeListener);
|
||||
updateState();
|
||||
dataModel.takerProcessState.addListener(takerStateListener);
|
||||
dataModel.offererProcessState.addListener(offererStateListener);
|
||||
|
||||
updateTakerState();
|
||||
updateOffererState();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -97,13 +104,15 @@ class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataM
|
|||
txId.unbind();
|
||||
selectedIndex.unbind();
|
||||
|
||||
dataModel.tradeState.removeListener(stateChangeListener);
|
||||
dataModel.takerProcessState.removeListener(takerStateListener);
|
||||
dataModel.offererProcessState.removeListener(offererStateListener);
|
||||
}
|
||||
|
||||
|
||||
void selectTrade(PendingTradesListItem item) {
|
||||
dataModel.selectTrade(item);
|
||||
updateState();
|
||||
/* updateTakerState();
|
||||
updateOffererState();*/
|
||||
}
|
||||
|
||||
void fiatPaymentStarted() {
|
||||
|
@ -123,7 +132,7 @@ class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataM
|
|||
}
|
||||
|
||||
String getAmountToWithdraw() {
|
||||
return formatter.formatCoinWithCode(dataModel.getAmountToWithdraw()); //.subtract(FeePolicy.TX_FEE));
|
||||
return formatter.formatCoinWithCode(dataModel.getAmountToWithdraw());
|
||||
}
|
||||
|
||||
ObservableList<PendingTradesListItem> getList() {
|
||||
|
@ -218,63 +227,88 @@ class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataM
|
|||
return btcAddressValidator;
|
||||
}
|
||||
|
||||
Throwable getTradeException() {
|
||||
return dataModel.getTradeException();
|
||||
}
|
||||
|
||||
private void updateState() {
|
||||
Trade.ProcessState processState = dataModel.tradeState.get();
|
||||
log.trace("tradeState " + processState);
|
||||
String getErrorMessage() {
|
||||
return dataModel.getErrorMessage();
|
||||
}
|
||||
|
||||
private void updateTakerState() {
|
||||
TakerTrade.TakerProcessState processState = dataModel.takerProcessState.get();
|
||||
log.debug("updateTakerState " + processState);
|
||||
if (processState != null) {
|
||||
if (processState instanceof TakerTrade.TakerProcessState) {
|
||||
switch ((TakerTrade.TakerProcessState) processState) {
|
||||
switch (processState) {
|
||||
case TAKE_OFFER_FEE_TX_CREATED:
|
||||
break;
|
||||
case TAKE_OFFER_FEE_PUBLISHED:
|
||||
break;
|
||||
case TAKE_OFFER_FEE_PUBLISH_FAILED:
|
||||
break;
|
||||
|
||||
case DEPOSIT_PUBLISHED:
|
||||
state.set(dataModel.isOfferer() ? State.OFFERER_BUYER_WAIT_TX_CONF : State.TAKER_SELLER_WAIT_TX_CONF);
|
||||
viewState.set(ViewState.TAKER_SELLER_WAIT_TX_CONF);
|
||||
break;
|
||||
case DEPOSIT_CONFIRMED:
|
||||
state.set(dataModel.isOfferer() ? State.OFFERER_BUYER_START_PAYMENT :
|
||||
State.TAKER_SELLER_WAIT_PAYMENT_STARTED);
|
||||
viewState.set(ViewState.TAKER_SELLER_WAIT_PAYMENT_STARTED);
|
||||
break;
|
||||
|
||||
case FIAT_PAYMENT_STARTED:
|
||||
state.set(dataModel.isOfferer() ? State.OFFERER_BUYER_WAIT_CONFIRM_PAYMENT_RECEIVED :
|
||||
State.TAKER_SELLER_CONFIRM_RECEIVE_PAYMENT);
|
||||
viewState.set(ViewState.TAKER_SELLER_CONFIRM_RECEIVE_PAYMENT);
|
||||
break;
|
||||
|
||||
case FIAT_PAYMENT_RECEIVED:
|
||||
viewState.set(ViewState.TAKER_SELLER_COMPLETED);
|
||||
break;
|
||||
case PAYOUT_PUBLISHED:
|
||||
state.set(dataModel.isOfferer() ? State.OFFERER_BUYER_COMPLETED : State.TAKER_SELLER_COMPLETED);
|
||||
break;
|
||||
|
||||
case MESSAGE_SENDING_FAILED:
|
||||
// TODO error states not implemented yet
|
||||
viewState.set(ViewState.MESSAGE_SENDING_FAILED);
|
||||
break;
|
||||
case EXCEPTION:
|
||||
viewState.set(ViewState.EXCEPTION);
|
||||
break;
|
||||
|
||||
default:
|
||||
log.warn("unhandled state " + processState);
|
||||
log.warn("unhandled processState " + processState);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (processState instanceof OffererTrade.OffererProcessState) {
|
||||
switch ((OffererTrade.OffererProcessState) processState) {
|
||||
case DEPOSIT_PUBLISHED:
|
||||
state.set(dataModel.isOfferer() ? State.OFFERER_BUYER_WAIT_TX_CONF : State.TAKER_SELLER_WAIT_TX_CONF);
|
||||
break;
|
||||
case DEPOSIT_CONFIRMED:
|
||||
state.set(dataModel.isOfferer() ? State.OFFERER_BUYER_START_PAYMENT :
|
||||
State.TAKER_SELLER_WAIT_PAYMENT_STARTED);
|
||||
break;
|
||||
case FIAT_PAYMENT_STARTED:
|
||||
state.set(dataModel.isOfferer() ? State.OFFERER_BUYER_WAIT_CONFIRM_PAYMENT_RECEIVED :
|
||||
State.TAKER_SELLER_CONFIRM_RECEIVE_PAYMENT);
|
||||
break;
|
||||
case PAYOUT_PUBLISHED:
|
||||
state.set(dataModel.isOfferer() ? State.OFFERER_BUYER_COMPLETED : State.TAKER_SELLER_COMPLETED);
|
||||
break;
|
||||
case MESSAGE_SENDING_FAILED:
|
||||
// TODO error states not implemented yet
|
||||
break;
|
||||
default:
|
||||
log.warn("unhandled state " + processState);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
state.set(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateOffererState() {
|
||||
OffererTrade.OffererProcessState processState = dataModel.offererProcessState.get();
|
||||
log.debug("updateOffererState " + processState);
|
||||
if (processState != null) {
|
||||
switch (processState) {
|
||||
case DEPOSIT_PUBLISHED:
|
||||
viewState.set(ViewState.OFFERER_BUYER_WAIT_TX_CONF);
|
||||
break;
|
||||
case DEPOSIT_CONFIRMED:
|
||||
viewState.set(ViewState.OFFERER_BUYER_START_PAYMENT);
|
||||
break;
|
||||
|
||||
case FIAT_PAYMENT_STARTED:
|
||||
viewState.set(ViewState.OFFERER_BUYER_WAIT_CONFIRM_PAYMENT_RECEIVED);
|
||||
break;
|
||||
|
||||
case PAYOUT_PUBLISHED:
|
||||
viewState.set(ViewState.OFFERER_BUYER_COMPLETED);
|
||||
break;
|
||||
|
||||
case MESSAGE_SENDING_FAILED:
|
||||
viewState.set(ViewState.MESSAGE_SENDING_FAILED);
|
||||
break;
|
||||
case EXCEPTION:
|
||||
viewState.set(ViewState.EXCEPTION);
|
||||
break;
|
||||
|
||||
default:
|
||||
log.warn("unhandled viewState " + processState);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
package io.bitsquare.storage;
|
||||
|
||||
|
||||
import io.bitsquare.gui.components.Popups;
|
||||
|
||||
import org.bitcoinj.core.Utils;
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
package io.bitsquare.storage;
|
||||
|
||||
import io.bitsquare.gui.components.Popups;
|
||||
import com.google.common.base.Throwables;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
|
@ -132,7 +132,7 @@ public class Storage<T extends Serializable> {
|
|||
} catch (IOException | ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
log.error(e.getMessage());
|
||||
Popups.openErrorPopup("An exception occurred at reading data from disc.", e.getMessage());
|
||||
Throwables.propagate(e);
|
||||
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -64,7 +64,7 @@ public class OffererTrade extends Trade implements Serializable {
|
|||
PAYOUT_PUBLISHED,
|
||||
|
||||
MESSAGE_SENDING_FAILED,
|
||||
UNSPECIFIC_FAULT
|
||||
EXCEPTION
|
||||
}
|
||||
|
||||
protected OffererProcessState processState;
|
||||
|
@ -104,7 +104,7 @@ public class OffererTrade extends Trade implements Serializable {
|
|||
processStateProperty.set(processState);
|
||||
|
||||
switch (processState) {
|
||||
case UNSPECIFIC_FAULT:
|
||||
case EXCEPTION:
|
||||
disposeProtocol();
|
||||
setLifeCycleState(OffererLifeCycleState.FAILED);
|
||||
break;
|
||||
|
|
|
@ -69,8 +69,8 @@ abstract public class Trade implements Serializable {
|
|||
|
||||
transient protected String errorMessage;
|
||||
transient protected Throwable throwable;
|
||||
transient protected ObjectProperty<Coin> tradeAmountProperty = new SimpleObjectProperty<>(tradeAmount);
|
||||
transient protected ObjectProperty<Fiat> tradeVolumeProperty = new SimpleObjectProperty<>(getTradeVolume());
|
||||
transient protected ObjectProperty<Coin> tradeAmountProperty;
|
||||
transient protected ObjectProperty<Fiat> tradeVolumeProperty;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -80,6 +80,8 @@ abstract public class Trade implements Serializable {
|
|||
public Trade(Offer offer) {
|
||||
this.offer = offer;
|
||||
date = new Date();
|
||||
tradeAmountProperty = new SimpleObjectProperty<>(tradeAmount);
|
||||
tradeVolumeProperty = new SimpleObjectProperty<>(getTradeVolume()); // cannot be set before offer is set
|
||||
}
|
||||
|
||||
// Serialized object does not create our transient objects
|
||||
|
|
|
@ -18,9 +18,11 @@
|
|||
package io.bitsquare.trade;
|
||||
|
||||
import io.bitsquare.arbitration.ArbitrationRepository;
|
||||
import io.bitsquare.btc.AddressEntry;
|
||||
import io.bitsquare.btc.BlockChainService;
|
||||
import io.bitsquare.btc.WalletService;
|
||||
import io.bitsquare.common.handlers.ErrorMessageHandler;
|
||||
import io.bitsquare.common.handlers.FaultHandler;
|
||||
import io.bitsquare.common.handlers.ResultHandler;
|
||||
import io.bitsquare.crypto.EncryptionService;
|
||||
import io.bitsquare.crypto.SignatureService;
|
||||
|
@ -47,9 +49,14 @@ import io.bitsquare.trade.protocol.trade.taker.models.TakerAsSellerModel;
|
|||
import io.bitsquare.user.AccountSettings;
|
||||
import io.bitsquare.user.User;
|
||||
|
||||
import org.bitcoinj.core.AddressFormatException;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.InsufficientMoneyException;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.bitcoinj.utils.Fiat;
|
||||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
@ -62,6 +69,8 @@ import javax.inject.Named;
|
|||
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -259,7 +268,20 @@ public class TradeManager {
|
|||
((TakerTrade) trade).onFiatPaymentReceived();
|
||||
}
|
||||
|
||||
public void onWithdrawAtTradeCompleted(Trade trade) {
|
||||
public void requestWithdraw(String toAddress, Trade trade, ResultHandler resultHandler, FaultHandler faultHandler) {
|
||||
AddressEntry addressEntry = walletService.getAddressEntry(trade.getId());
|
||||
String fromAddress = addressEntry.getAddressString();
|
||||
|
||||
// TODO handle overpaid securityDeposit
|
||||
Coin amountToWithdraw = trade.getSecurityDeposit();
|
||||
if (trade instanceof OffererTrade)
|
||||
amountToWithdraw = amountToWithdraw.add(trade.getTradeAmount());
|
||||
|
||||
FutureCallback<Transaction> callback = new FutureCallback<Transaction>() {
|
||||
@Override
|
||||
public void onSuccess(@javax.annotation.Nullable Transaction transaction) {
|
||||
if (transaction != null) {
|
||||
log.info("onWithdraw onSuccess tx ID:" + transaction.getHashAsString());
|
||||
if (trade instanceof OffererTrade)
|
||||
((OffererTrade) trade).setLifeCycleState(OffererTrade.OffererLifeCycleState.COMPLETED);
|
||||
else
|
||||
|
@ -267,6 +289,25 @@ public class TradeManager {
|
|||
|
||||
pendingTrades.remove(trade);
|
||||
closedTrades.add(trade);
|
||||
|
||||
resultHandler.handleResult();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NotNull Throwable t) {
|
||||
t.printStackTrace();
|
||||
log.error(t.getMessage());
|
||||
faultHandler.handleFault("An exception occurred at requestWithdraw (onFailure).", t);
|
||||
}
|
||||
};
|
||||
try {
|
||||
walletService.sendFunds(fromAddress, toAddress, amountToWithdraw, callback);
|
||||
} catch (AddressFormatException | InsufficientMoneyException e) {
|
||||
e.printStackTrace();
|
||||
log.error(e.getMessage());
|
||||
faultHandler.handleFault("An exception occurred at requestWithdraw.", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -437,5 +478,4 @@ public class TradeManager {
|
|||
log.error(fault.getMessage());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -19,9 +19,10 @@ package io.bitsquare.user;
|
|||
|
||||
import io.bitsquare.crypto.EncryptionService;
|
||||
import io.bitsquare.fiat.FiatAccount;
|
||||
import io.bitsquare.gui.components.Popups;
|
||||
import io.bitsquare.storage.Storage;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import java.security.KeyPair;
|
||||
|
@ -94,7 +95,7 @@ public class User implements Serializable {
|
|||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
log.error(e.getMessage());
|
||||
Popups.openExceptionPopup(e);
|
||||
Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
storage.save();
|
||||
|
|
Loading…
Add table
Reference in a new issue