mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-07-26 00:15:18 -04:00
Improve locked funds screen, add total balance for locked funds
This commit is contained in:
parent
c70df863d6
commit
6b3df246a1
21 changed files with 361 additions and 366 deletions
|
@ -171,7 +171,7 @@ abstract public class Trade implements Tradable, Model, Serializable {
|
||||||
transient private ObjectProperty<Coin> tradeAmountProperty;
|
transient private ObjectProperty<Coin> tradeAmountProperty;
|
||||||
transient private ObjectProperty<Fiat> tradeVolumeProperty;
|
transient private ObjectProperty<Fiat> tradeVolumeProperty;
|
||||||
@Nullable
|
@Nullable
|
||||||
private Transaction takeOfferFeeTx;
|
private String takeOfferFeeTxId;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -562,12 +562,12 @@ abstract public class Trade implements Tradable, Model, Serializable {
|
||||||
return contractHash;
|
return contractHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTakeOfferFeeTx(Transaction takeOfferFeeTx) {
|
public void setTakeOfferFeeTxId(String takeOfferFeeTxId) {
|
||||||
this.takeOfferFeeTx = takeOfferFeeTx;
|
this.takeOfferFeeTxId = takeOfferFeeTxId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Transaction getTakeOfferFeeTx() {
|
public String getTakeOfferFeeTxId() {
|
||||||
return takeOfferFeeTx;
|
return takeOfferFeeTxId;
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -628,7 +628,7 @@ abstract public class Trade implements Tradable, Model, Serializable {
|
||||||
"\n\tdisputeState=" + disputeState +
|
"\n\tdisputeState=" + disputeState +
|
||||||
"\n\ttradePeriodState=" + tradePeriodState +
|
"\n\ttradePeriodState=" + tradePeriodState +
|
||||||
"\n\tdepositTx=" + depositTx +
|
"\n\tdepositTx=" + depositTx +
|
||||||
"\n\ttakeOfferFeeTx.getHashAsString()=" + (takeOfferFeeTx != null ? takeOfferFeeTx.getHashAsString() : "") +
|
"\n\ttakeOfferFeeTxId=" + takeOfferFeeTxId +
|
||||||
"\n\tcontract=" + contract +
|
"\n\tcontract=" + contract +
|
||||||
"\n\ttakerContractSignature.hashCode()='" + (takerContractSignature != null ? takerContractSignature.hashCode() : "") + '\'' +
|
"\n\ttakerContractSignature.hashCode()='" + (takerContractSignature != null ? takerContractSignature.hashCode() : "") + '\'' +
|
||||||
"\n\toffererContractSignature.hashCode()='" + (offererContractSignature != null ? offererContractSignature.hashCode() : "") + '\'' +
|
"\n\toffererContractSignature.hashCode()='" + (offererContractSignature != null ? offererContractSignature.hashCode() : "") + '\'' +
|
||||||
|
|
|
@ -36,6 +36,7 @@ import io.bitsquare.trade.offer.Offer;
|
||||||
import io.bitsquare.trade.offer.OpenOfferManager;
|
import io.bitsquare.trade.offer.OpenOfferManager;
|
||||||
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
||||||
import io.bitsquare.user.User;
|
import io.bitsquare.user.User;
|
||||||
|
import org.bitcoinj.core.Transaction;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -65,7 +66,6 @@ public class ProcessModel implements Model, Serializable {
|
||||||
// Mutable
|
// Mutable
|
||||||
public final TradingPeer tradingPeer;
|
public final TradingPeer tradingPeer;
|
||||||
transient private TradeMessage tradeMessage;
|
transient private TradeMessage tradeMessage;
|
||||||
private String takeOfferFeeTxId;
|
|
||||||
private byte[] payoutTxSignature;
|
private byte[] payoutTxSignature;
|
||||||
|
|
||||||
private List<NodeAddress> takerAcceptedArbitratorNodeAddresses;
|
private List<NodeAddress> takerAcceptedArbitratorNodeAddresses;
|
||||||
|
@ -78,6 +78,7 @@ public class ProcessModel implements Model, Serializable {
|
||||||
private long changeOutputValue;
|
private long changeOutputValue;
|
||||||
@Nullable
|
@Nullable
|
||||||
private String changeOutputAddress;
|
private String changeOutputAddress;
|
||||||
|
private Transaction takeOfferFeeTx;
|
||||||
|
|
||||||
public ProcessModel() {
|
public ProcessModel() {
|
||||||
tradingPeer = new TradingPeer();
|
tradingPeer = new TradingPeer();
|
||||||
|
@ -194,14 +195,6 @@ public class ProcessModel implements Model, Serializable {
|
||||||
this.payoutTxSignature = payoutTxSignature;
|
this.payoutTxSignature = payoutTxSignature;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTakeOfferFeeTxId() {
|
|
||||||
return takeOfferFeeTxId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTakeOfferFeeTxId(String takeOfferFeeTxId) {
|
|
||||||
this.takeOfferFeeTxId = takeOfferFeeTxId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void persist() {
|
public void persist() {
|
||||||
}
|
}
|
||||||
|
@ -274,4 +267,12 @@ public class ProcessModel implements Model, Serializable {
|
||||||
public String getChangeOutputAddress() {
|
public String getChangeOutputAddress() {
|
||||||
return changeOutputAddress;
|
return changeOutputAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setTakeOfferFeeTx(Transaction takeOfferFeeTx) {
|
||||||
|
this.takeOfferFeeTx = takeOfferFeeTx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Transaction getTakeOfferFeeTx() {
|
||||||
|
return takeOfferFeeTx;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ public class CreateAndSignContract extends TradeTask {
|
||||||
protected void run() {
|
protected void run() {
|
||||||
try {
|
try {
|
||||||
runInterceptHook();
|
runInterceptHook();
|
||||||
checkNotNull(processModel.getTakeOfferFeeTxId(), "processModel.getTakeOfferFeeTxId() must not be null");
|
checkNotNull(trade.getTakeOfferFeeTxId(), "trade.getTakeOfferFeeTxId() must not be null");
|
||||||
|
|
||||||
TradingPeer taker = processModel.tradingPeer;
|
TradingPeer taker = processModel.tradingPeer;
|
||||||
PaymentAccountContractData offererPaymentAccountContractData = processModel.getPaymentAccountContractData(trade);
|
PaymentAccountContractData offererPaymentAccountContractData = processModel.getPaymentAccountContractData(trade);
|
||||||
|
@ -58,7 +58,7 @@ public class CreateAndSignContract extends TradeTask {
|
||||||
Contract contract = new Contract(
|
Contract contract = new Contract(
|
||||||
processModel.getOffer(),
|
processModel.getOffer(),
|
||||||
trade.getTradeAmount(),
|
trade.getTradeAmount(),
|
||||||
processModel.getTakeOfferFeeTxId(),
|
trade.getTakeOfferFeeTxId(),
|
||||||
buyerNodeAddress,
|
buyerNodeAddress,
|
||||||
sellerNodeAddress,
|
sellerNodeAddress,
|
||||||
trade.getArbitratorNodeAddress(),
|
trade.getArbitratorNodeAddress(),
|
||||||
|
|
|
@ -71,7 +71,7 @@ public class ProcessPayDepositRequest extends TradeTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
processModel.tradingPeer.setAccountId(nonEmptyStringOf(payDepositRequest.takerAccountId));
|
processModel.tradingPeer.setAccountId(nonEmptyStringOf(payDepositRequest.takerAccountId));
|
||||||
processModel.setTakeOfferFeeTxId(nonEmptyStringOf(payDepositRequest.takeOfferFeeTxId));
|
trade.setTakeOfferFeeTxId(nonEmptyStringOf(payDepositRequest.takeOfferFeeTxId));
|
||||||
processModel.setTakerAcceptedArbitratorNodeAddresses(checkNotNull(payDepositRequest.acceptedArbitratorNodeAddresses));
|
processModel.setTakerAcceptedArbitratorNodeAddresses(checkNotNull(payDepositRequest.acceptedArbitratorNodeAddresses));
|
||||||
if (payDepositRequest.acceptedArbitratorNodeAddresses.size() < 1)
|
if (payDepositRequest.acceptedArbitratorNodeAddresses.size() < 1)
|
||||||
failed("acceptedArbitratorNames size must be at least 1");
|
failed("acceptedArbitratorNames size must be at least 1");
|
||||||
|
|
|
@ -37,7 +37,7 @@ public class BroadcastTakeOfferFeeTx extends TradeTask {
|
||||||
protected void run() {
|
protected void run() {
|
||||||
try {
|
try {
|
||||||
runInterceptHook();
|
runInterceptHook();
|
||||||
processModel.getTradeWalletService().broadcastTx(trade.getTakeOfferFeeTx(),
|
processModel.getTradeWalletService().broadcastTx(processModel.getTakeOfferFeeTx(),
|
||||||
new FutureCallback<Transaction>() {
|
new FutureCallback<Transaction>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(Transaction transaction) {
|
public void onSuccess(Transaction transaction) {
|
||||||
|
|
|
@ -50,10 +50,8 @@ public class CreateTakeOfferFeeTx extends TradeTask {
|
||||||
FeePolicy.getTakeOfferFee(),
|
FeePolicy.getTakeOfferFee(),
|
||||||
selectedArbitrator.getBtcAddress());
|
selectedArbitrator.getBtcAddress());
|
||||||
|
|
||||||
trade.setTakeOfferFeeTx(createTakeOfferFeeTx);
|
processModel.setTakeOfferFeeTx(createTakeOfferFeeTx);
|
||||||
|
trade.setTakeOfferFeeTxId(createTakeOfferFeeTx.getHashAsString());
|
||||||
// TODO check if needed as we have stored tx already at setTakeOfferFeeTx
|
|
||||||
processModel.setTakeOfferFeeTxId(createTakeOfferFeeTx.getHashAsString());
|
|
||||||
|
|
||||||
complete();
|
complete();
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
|
|
|
@ -38,8 +38,11 @@ public class SendPayDepositRequest extends TradeTask {
|
||||||
protected void run() {
|
protected void run() {
|
||||||
try {
|
try {
|
||||||
runInterceptHook();
|
runInterceptHook();
|
||||||
if (trade.getTakeOfferFeeTx() != null) {
|
|
||||||
checkNotNull(trade.getTradeAmount());
|
checkNotNull(trade.getTradeAmount(), "TradeAmount must not be null");
|
||||||
|
checkNotNull(trade.getTakeOfferFeeTxId(), "TakeOfferFeeTxId must not be null");
|
||||||
|
checkNotNull(processModel.getAddressEntry(), "AddressEntry must not be null");
|
||||||
|
|
||||||
PayDepositRequest payDepositRequest = new PayDepositRequest(
|
PayDepositRequest payDepositRequest = new PayDepositRequest(
|
||||||
processModel.getMyAddress(),
|
processModel.getMyAddress(),
|
||||||
processModel.getId(),
|
processModel.getId(),
|
||||||
|
@ -52,7 +55,7 @@ public class SendPayDepositRequest extends TradeTask {
|
||||||
processModel.getPubKeyRing(),
|
processModel.getPubKeyRing(),
|
||||||
processModel.getPaymentAccountContractData(trade),
|
processModel.getPaymentAccountContractData(trade),
|
||||||
processModel.getAccountId(),
|
processModel.getAccountId(),
|
||||||
trade.getTakeOfferFeeTx().getHashAsString(),
|
trade.getTakeOfferFeeTxId(),
|
||||||
processModel.getUser().getAcceptedArbitratorAddresses(),
|
processModel.getUser().getAcceptedArbitratorAddresses(),
|
||||||
trade.getArbitratorNodeAddress()
|
trade.getArbitratorNodeAddress()
|
||||||
);
|
);
|
||||||
|
@ -81,10 +84,6 @@ public class SendPayDepositRequest extends TradeTask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
log.error("trade.getTakeOfferFeeTx() = " + trade.getTakeOfferFeeTx());
|
|
||||||
failed("TakeOfferFeeTx is null");
|
|
||||||
}
|
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
failed(t);
|
failed(t);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,8 @@ import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
public class VerifyAndSignContract extends TradeTask {
|
public class VerifyAndSignContract extends TradeTask {
|
||||||
private static final Logger log = LoggerFactory.getLogger(VerifyAndSignContract.class);
|
private static final Logger log = LoggerFactory.getLogger(VerifyAndSignContract.class);
|
||||||
|
|
||||||
|
@ -42,7 +44,8 @@ public class VerifyAndSignContract extends TradeTask {
|
||||||
try {
|
try {
|
||||||
runInterceptHook();
|
runInterceptHook();
|
||||||
|
|
||||||
if (trade.getTakeOfferFeeTx() != null) {
|
checkNotNull(trade.getTakeOfferFeeTxId(), "TakeOfferFeeTxId must not be null");
|
||||||
|
|
||||||
TradingPeer offerer = processModel.tradingPeer;
|
TradingPeer offerer = processModel.tradingPeer;
|
||||||
PaymentAccountContractData offererPaymentAccountContractData = offerer.getPaymentAccountContractData();
|
PaymentAccountContractData offererPaymentAccountContractData = offerer.getPaymentAccountContractData();
|
||||||
PaymentAccountContractData takerPaymentAccountContractData = processModel.getPaymentAccountContractData(trade);
|
PaymentAccountContractData takerPaymentAccountContractData = processModel.getPaymentAccountContractData(trade);
|
||||||
|
@ -57,7 +60,7 @@ public class VerifyAndSignContract extends TradeTask {
|
||||||
Contract contract = new Contract(
|
Contract contract = new Contract(
|
||||||
processModel.getOffer(),
|
processModel.getOffer(),
|
||||||
trade.getTradeAmount(),
|
trade.getTradeAmount(),
|
||||||
trade.getTakeOfferFeeTx().getHashAsString(),
|
trade.getTakeOfferFeeTxId(),
|
||||||
buyerNodeAddress,
|
buyerNodeAddress,
|
||||||
sellerNodeAddress,
|
sellerNodeAddress,
|
||||||
trade.getArbitratorNodeAddress(),
|
trade.getArbitratorNodeAddress(),
|
||||||
|
@ -88,9 +91,6 @@ public class VerifyAndSignContract extends TradeTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
complete();
|
complete();
|
||||||
} else {
|
|
||||||
failed("processModel.getTakeOfferFeeTx() = null");
|
|
||||||
}
|
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
failed(t);
|
failed(t);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ public class HyperlinkWithIcon extends AnchorPane {
|
||||||
AnchorPane.setLeftAnchor(hyperlink, 0.0);
|
AnchorPane.setLeftAnchor(hyperlink, 0.0);
|
||||||
AnchorPane.setRightAnchor(hyperlink, 15.0);
|
AnchorPane.setRightAnchor(hyperlink, 15.0);
|
||||||
AnchorPane.setRightAnchor(openLinkIcon, 4.0);
|
AnchorPane.setRightAnchor(openLinkIcon, 4.0);
|
||||||
AnchorPane.setTopAnchor(openLinkIcon, 3.0);
|
AnchorPane.setTopAnchor(openLinkIcon, awesomeIcon == AwesomeIcon.INFO_SIGN ? 2.0 : 3.0);
|
||||||
|
|
||||||
getChildren().addAll(hyperlink, openLinkIcon);
|
getChildren().addAll(hyperlink, openLinkIcon);
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,10 +124,14 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
||||||
Tuple2<TextField, VBox> availableBalanceBox = getBalanceBox("Available balance");
|
Tuple2<TextField, VBox> availableBalanceBox = getBalanceBox("Available balance");
|
||||||
availableBalanceBox.first.textProperty().bind(model.availableBalance);
|
availableBalanceBox.first.textProperty().bind(model.availableBalance);
|
||||||
|
|
||||||
|
Tuple2<TextField, VBox> reservedBalanceBox = getBalanceBox("Reserved balance");
|
||||||
|
reservedBalanceBox.first.textProperty().bind(model.reservedBalance);
|
||||||
|
|
||||||
Tuple2<TextField, VBox> lockedBalanceBox = getBalanceBox("Locked balance");
|
Tuple2<TextField, VBox> lockedBalanceBox = getBalanceBox("Locked balance");
|
||||||
lockedBalanceBox.first.textProperty().bind(model.lockedBalance);
|
lockedBalanceBox.first.textProperty().bind(model.lockedBalance);
|
||||||
|
|
||||||
HBox rightNavPane = new HBox(availableBalanceBox.second, lockedBalanceBox.second, settingsButton, accountButton) {{
|
HBox rightNavPane = new HBox(availableBalanceBox.second, reservedBalanceBox.second, lockedBalanceBox.second,
|
||||||
|
settingsButton, accountButton) {{
|
||||||
setSpacing(10);
|
setSpacing(10);
|
||||||
setRightAnchor(this, 10d);
|
setRightAnchor(this, 10d);
|
||||||
setTopAnchor(this, 0d);
|
setTopAnchor(this, 0d);
|
||||||
|
|
|
@ -26,10 +26,7 @@ import io.bitsquare.app.Version;
|
||||||
import io.bitsquare.arbitration.ArbitratorManager;
|
import io.bitsquare.arbitration.ArbitratorManager;
|
||||||
import io.bitsquare.arbitration.Dispute;
|
import io.bitsquare.arbitration.Dispute;
|
||||||
import io.bitsquare.arbitration.DisputeManager;
|
import io.bitsquare.arbitration.DisputeManager;
|
||||||
import io.bitsquare.btc.AddressEntry;
|
import io.bitsquare.btc.*;
|
||||||
import io.bitsquare.btc.BitcoinNetwork;
|
|
||||||
import io.bitsquare.btc.TradeWalletService;
|
|
||||||
import io.bitsquare.btc.WalletService;
|
|
||||||
import io.bitsquare.btc.listeners.BalanceListener;
|
import io.bitsquare.btc.listeners.BalanceListener;
|
||||||
import io.bitsquare.common.UserThread;
|
import io.bitsquare.common.UserThread;
|
||||||
import io.bitsquare.gui.common.model.ViewModel;
|
import io.bitsquare.gui.common.model.ViewModel;
|
||||||
|
@ -94,6 +91,7 @@ public class MainViewModel implements ViewModel {
|
||||||
final StringProperty walletServiceErrorMsg = new SimpleStringProperty();
|
final StringProperty walletServiceErrorMsg = new SimpleStringProperty();
|
||||||
final StringProperty btcSplashSyncIconId = new SimpleStringProperty();
|
final StringProperty btcSplashSyncIconId = new SimpleStringProperty();
|
||||||
final StringProperty availableBalance = new SimpleStringProperty();
|
final StringProperty availableBalance = new SimpleStringProperty();
|
||||||
|
final StringProperty reservedBalance = new SimpleStringProperty();
|
||||||
final StringProperty lockedBalance = new SimpleStringProperty();
|
final StringProperty lockedBalance = new SimpleStringProperty();
|
||||||
|
|
||||||
// P2P network
|
// P2P network
|
||||||
|
@ -493,21 +491,42 @@ public class MainViewModel implements ViewModel {
|
||||||
|
|
||||||
private void updateBalance() {
|
private void updateBalance() {
|
||||||
updateAvailableBalance();
|
updateAvailableBalance();
|
||||||
|
updateReservedBalance();
|
||||||
updateLockedBalance();
|
updateLockedBalance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateReservedBalance() {
|
||||||
|
Coin sum = Coin.valueOf(Stream.concat(openOfferManager.getOpenOffers().stream(), tradeManager.getTrades().stream())
|
||||||
|
.map(tradable -> walletService.getAddressEntryByOfferId(tradable.getId()))
|
||||||
|
.map(addressEntry -> walletService.getBalanceForAddress(addressEntry.getAddress()))
|
||||||
|
.mapToLong(Coin::getValue)
|
||||||
|
.sum());
|
||||||
|
reservedBalance.set(formatter.formatCoinWithCode(sum));
|
||||||
|
}
|
||||||
|
|
||||||
private void updateLockedBalance() {
|
private void updateLockedBalance() {
|
||||||
List<AddressEntry> result = new ArrayList<>();
|
Coin sum = Coin.valueOf(tradeManager.getTrades().stream()
|
||||||
|
.map(trade -> {
|
||||||
result.addAll(Stream.concat(openOfferManager.getOpenOffers().stream(), tradeManager.getTrades().stream())
|
switch (trade.getState().getPhase()) {
|
||||||
.map(tradable -> walletService.getAddressEntryByOfferId(tradable.getOffer().getId()))
|
case DEPOSIT_REQUESTED:
|
||||||
.collect(Collectors.toList()));
|
case DEPOSIT_PAID:
|
||||||
|
case FIAT_SENT:
|
||||||
Optional<Coin> totalLockedOptional = result.stream().map(e -> walletService.getBalanceForAddress(e.getAddress())).reduce((a, b) -> a.add(b));
|
case FIAT_RECEIVED:
|
||||||
if (totalLockedOptional.isPresent())
|
Coin balanceInDeposit = FeePolicy.getSecurityDeposit().add(FeePolicy.getFeePerKb());
|
||||||
lockedBalance.set(formatter.formatCoinWithCode(totalLockedOptional.get()));
|
if (trade.getContract() != null &&
|
||||||
else
|
trade.getTradeAmount() != null &&
|
||||||
lockedBalance.set(formatter.formatCoinWithCode(Coin.ZERO));
|
trade.getContract().getSellerPayoutAddressString()
|
||||||
|
.equals(walletService.getAddressEntryByOfferId(trade.getId()).getAddressString())) {
|
||||||
|
balanceInDeposit = balanceInDeposit.add(trade.getTradeAmount());
|
||||||
|
}
|
||||||
|
return balanceInDeposit;
|
||||||
|
default:
|
||||||
|
return Coin.ZERO;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.mapToLong(Coin::getValue)
|
||||||
|
.sum());
|
||||||
|
lockedBalance.set(formatter.formatCoinWithCode(sum));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateAvailableBalance() {
|
private void updateAvailableBalance() {
|
||||||
|
|
|
@ -24,8 +24,8 @@
|
||||||
AnchorPane.topAnchor="0.0"
|
AnchorPane.topAnchor="0.0"
|
||||||
xmlns:fx="http://javafx.com/fxml">
|
xmlns:fx="http://javafx.com/fxml">
|
||||||
|
|
||||||
<Tab fx:id="reservedTab" text="Reserved for trades" closable="false"></Tab>
|
<Tab fx:id="reservedTab" text="Reserved/Locked funds" closable="false"></Tab>
|
||||||
<Tab fx:id="withdrawalTab" text="Open for withdrawal" closable="false"/>
|
<Tab fx:id="withdrawalTab" text="Available for withdrawal" closable="false"/>
|
||||||
<Tab fx:id="transactionsTab" text="Transactions" closable="false"/>
|
<Tab fx:id="transactionsTab" text="Transactions" closable="false"/>
|
||||||
|
|
||||||
</TabPane>
|
</TabPane>
|
|
@ -20,19 +20,16 @@ package io.bitsquare.gui.main.funds.reserved;
|
||||||
import io.bitsquare.btc.AddressEntry;
|
import io.bitsquare.btc.AddressEntry;
|
||||||
import io.bitsquare.btc.FeePolicy;
|
import io.bitsquare.btc.FeePolicy;
|
||||||
import io.bitsquare.btc.WalletService;
|
import io.bitsquare.btc.WalletService;
|
||||||
import io.bitsquare.btc.listeners.AddressConfidenceListener;
|
|
||||||
import io.bitsquare.btc.listeners.BalanceListener;
|
import io.bitsquare.btc.listeners.BalanceListener;
|
||||||
import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator;
|
|
||||||
import io.bitsquare.gui.util.BSFormatter;
|
import io.bitsquare.gui.util.BSFormatter;
|
||||||
import io.bitsquare.trade.Tradable;
|
import io.bitsquare.trade.Tradable;
|
||||||
import io.bitsquare.trade.Trade;
|
import io.bitsquare.trade.Trade;
|
||||||
|
import io.bitsquare.trade.offer.OpenOffer;
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
import javafx.beans.property.StringProperty;
|
import javafx.beans.property.StringProperty;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.Tooltip;
|
|
||||||
import org.bitcoinj.core.Address;
|
import org.bitcoinj.core.Address;
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
import org.bitcoinj.core.TransactionConfidence;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -41,19 +38,12 @@ public class ReservedListItem {
|
||||||
|
|
||||||
private final StringProperty date = new SimpleStringProperty();
|
private final StringProperty date = new SimpleStringProperty();
|
||||||
private final BalanceListener balanceListener;
|
private final BalanceListener balanceListener;
|
||||||
|
|
||||||
private final Label balanceLabel;
|
private final Label balanceLabel;
|
||||||
|
private String fundsInfo;
|
||||||
private final Tradable tradable;
|
private final Tradable tradable;
|
||||||
private final AddressEntry addressEntry;
|
private final AddressEntry addressEntry;
|
||||||
|
|
||||||
private final WalletService walletService;
|
private final WalletService walletService;
|
||||||
private final BSFormatter formatter;
|
private final BSFormatter formatter;
|
||||||
private final AddressConfidenceListener confidenceListener;
|
|
||||||
|
|
||||||
private final ConfidenceProgressIndicator progressIndicator;
|
|
||||||
|
|
||||||
private final Tooltip tooltip;
|
|
||||||
private final String addressString;
|
private final String addressString;
|
||||||
private Coin balance;
|
private Coin balance;
|
||||||
|
|
||||||
|
@ -64,25 +54,7 @@ public class ReservedListItem {
|
||||||
this.formatter = formatter;
|
this.formatter = formatter;
|
||||||
addressString = addressEntry.getAddressString();
|
addressString = addressEntry.getAddressString();
|
||||||
|
|
||||||
// confidence
|
date.set(formatter.formatDateTime(tradable.getDate()));
|
||||||
progressIndicator = new ConfidenceProgressIndicator();
|
|
||||||
progressIndicator.setId("funds-confidence");
|
|
||||||
tooltip = new Tooltip("Not used yet");
|
|
||||||
progressIndicator.setProgress(0);
|
|
||||||
progressIndicator.setPrefSize(24, 24);
|
|
||||||
Tooltip.install(progressIndicator, tooltip);
|
|
||||||
|
|
||||||
confidenceListener = walletService.addAddressConfidenceListener(new AddressConfidenceListener(getAddress()) {
|
|
||||||
@Override
|
|
||||||
public void onTransactionConfidenceChanged(TransactionConfidence confidence) {
|
|
||||||
updateConfidence(confidence);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
updateConfidence(walletService.getConfidenceForAddress(getAddress()));
|
|
||||||
|
|
||||||
//date.set(formatter.formatDateTime(transaction.getUpdateTime()));
|
|
||||||
|
|
||||||
|
|
||||||
// balance
|
// balance
|
||||||
balanceLabel = new Label();
|
balanceLabel = new Label();
|
||||||
|
@ -97,113 +69,67 @@ public class ReservedListItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cleanup() {
|
public void cleanup() {
|
||||||
walletService.removeAddressConfidenceListener(confidenceListener);
|
|
||||||
walletService.removeBalanceListener(balanceListener);
|
walletService.removeBalanceListener(balanceListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateBalance(Coin balance) {
|
private void updateBalance(Coin balance) {
|
||||||
this.balance = balance;
|
this.balance = balance;
|
||||||
if (balance != null) {
|
if (balance != null) {
|
||||||
|
balanceLabel.setText(formatter.formatCoin(balance));
|
||||||
|
|
||||||
if (tradable instanceof Trade) {
|
if (tradable instanceof Trade) {
|
||||||
Trade trade = (Trade) tradable;
|
Trade trade = (Trade) tradable;
|
||||||
Trade.Phase phase = trade.getState().getPhase();
|
Trade.Phase phase = trade.getState().getPhase();
|
||||||
switch (phase) {
|
switch (phase) {
|
||||||
case PREPARATION:
|
case PREPARATION:
|
||||||
case TAKER_FEE_PAID:
|
case TAKER_FEE_PAID:
|
||||||
balanceLabel.setText(formatter.formatCoinWithCode(balance) + " (locally reserved)");
|
fundsInfo = "Reserved in local wallet";
|
||||||
break;
|
break;
|
||||||
case DEPOSIT_REQUESTED:
|
case DEPOSIT_REQUESTED:
|
||||||
case DEPOSIT_PAID:
|
case DEPOSIT_PAID:
|
||||||
case FIAT_SENT:
|
case FIAT_SENT:
|
||||||
case FIAT_RECEIVED:
|
case FIAT_RECEIVED:
|
||||||
|
fundsInfo = "Locked in MultiSig";
|
||||||
// We ignore the tx fee as it will be paid by both (once deposit, once payout)
|
// We ignore the tx fee as it will be paid by both (once deposit, once payout)
|
||||||
Coin balanceInDeposit = FeePolicy.getSecurityDeposit();
|
Coin balanceInDeposit = FeePolicy.getSecurityDeposit().add(FeePolicy.getFeePerKb());
|
||||||
// For the seller we add the trade amount
|
// For the seller we add the trade amount
|
||||||
if (trade.getContract() != null &&
|
if (trade.getContract() != null &&
|
||||||
trade.getTradeAmount() != null &&
|
trade.getTradeAmount() != null &&
|
||||||
trade.getContract().getSellerPayoutAddressString().equals(addressString))
|
trade.getContract().getSellerPayoutAddressString().equals(addressString))
|
||||||
balanceInDeposit = balanceInDeposit.add(trade.getTradeAmount());
|
balanceInDeposit = balanceInDeposit.add(trade.getTradeAmount());
|
||||||
|
|
||||||
balanceLabel.setText(formatter.formatCoinWithCode(balanceInDeposit) + " (in MS escrow)");
|
balanceLabel.setText(formatter.formatCoin(balanceInDeposit));
|
||||||
break;
|
break;
|
||||||
case PAYOUT_PAID:
|
case PAYOUT_PAID:
|
||||||
balanceLabel.setText(formatter.formatCoinWithCode(balance) + " (in local wallet)");
|
fundsInfo = "Received in local wallet";
|
||||||
break;
|
break;
|
||||||
case WITHDRAWN:
|
case WITHDRAWN:
|
||||||
log.error("Invalid state at updateBalance (WITHDRAWN)");
|
log.error("Invalid state at updateBalance (WITHDRAWN)");
|
||||||
balanceLabel.setText(formatter.formatCoinWithCode(balance) + " already withdrawn");
|
|
||||||
break;
|
break;
|
||||||
case DISPUTE:
|
case DISPUTE:
|
||||||
balanceLabel.setText(formatter.formatCoinWithCode(balance) + " open dispute/ticket");
|
log.error("Invalid state at updateBalance (DISPUTE)");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log.warn("Not supported tradePhase: " + phase);
|
log.warn("Not supported tradePhase: " + phase);
|
||||||
}
|
}
|
||||||
|
} else if (tradable instanceof OpenOffer) {
|
||||||
} else
|
fundsInfo = "Reserved in local wallet";
|
||||||
balanceLabel.setText(formatter.formatCoin(balance));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateConfidence(TransactionConfidence confidence) {
|
|
||||||
if (confidence != null) {
|
|
||||||
//log.debug("Type numBroadcastPeers getDepthInBlocks " + confidence.getConfidenceType() + " / " +
|
|
||||||
// confidence.numBroadcastPeers() + " / " + confidence.getDepthInBlocks());
|
|
||||||
switch (confidence.getConfidenceType()) {
|
|
||||||
case UNKNOWN:
|
|
||||||
tooltip.setText("Unknown transaction status");
|
|
||||||
progressIndicator.setProgress(0);
|
|
||||||
break;
|
|
||||||
case PENDING:
|
|
||||||
tooltip.setText("Seen by " + confidence.numBroadcastPeers() + " peer(s) / 0 confirmations");
|
|
||||||
progressIndicator.setProgress(-1.0);
|
|
||||||
break;
|
|
||||||
case BUILDING:
|
|
||||||
tooltip.setText("Confirmed in " + confidence.getDepthInBlocks() + " block(s)");
|
|
||||||
progressIndicator.setProgress(Math.min(1, (double) confidence.getDepthInBlocks() / 6.0));
|
|
||||||
break;
|
|
||||||
case DEAD:
|
|
||||||
tooltip.setText("Transaction is invalid.");
|
|
||||||
progressIndicator.setProgress(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public final String getLabel() {
|
|
||||||
switch (addressEntry.getContext()) {
|
|
||||||
case TRADE:
|
|
||||||
if (tradable instanceof Trade)
|
|
||||||
return "Trade ID: " + addressEntry.getShortOfferId();
|
|
||||||
else
|
|
||||||
return "Offer ID: " + addressEntry.getShortOfferId();
|
|
||||||
case ARBITRATOR:
|
|
||||||
return "Arbitration deposit";
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Address getAddress() {
|
private Address getAddress() {
|
||||||
return addressEntry.getAddress();
|
return addressEntry.getAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public AddressEntry getAddressEntry() {
|
public AddressEntry getAddressEntry() {
|
||||||
return addressEntry;
|
return addressEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ConfidenceProgressIndicator getProgressIndicator() {
|
|
||||||
return progressIndicator;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Label getBalanceLabel() {
|
public Label getBalanceLabel() {
|
||||||
return balanceLabel;
|
return balanceLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Coin getBalance() {
|
public Coin getBalance() {
|
||||||
return balance;
|
return balance;
|
||||||
}
|
}
|
||||||
|
@ -211,4 +137,8 @@ public class ReservedListItem {
|
||||||
public String getAddressString() {
|
public String getAddressString() {
|
||||||
return addressString;
|
return addressString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getFundsInfo() {
|
||||||
|
return fundsInfo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,15 +29,14 @@
|
||||||
|
|
||||||
<TableView fx:id="table" VBox.vgrow="ALWAYS">
|
<TableView fx:id="table" VBox.vgrow="ALWAYS">
|
||||||
<columns>
|
<columns>
|
||||||
<TableColumn text="Date/Time" fx:id="dateColumn" minWidth="100" sortable="false">
|
<TableColumn text="Date/Time" fx:id="dateColumn" minWidth="170" maxWidth="170"/>
|
||||||
|
<TableColumn text="Details" fx:id="detailsColumn" minWidth="260"/>
|
||||||
|
<TableColumn text="Address" fx:id="addressColumn" minWidth="320" maxWidth="320">
|
||||||
<cellValueFactory>
|
<cellValueFactory>
|
||||||
<PropertyValueFactory property="date"/>
|
<PropertyValueFactory property="addressString"/>
|
||||||
</cellValueFactory>
|
</cellValueFactory>
|
||||||
</TableColumn>
|
</TableColumn>
|
||||||
<TableColumn text="Details" fx:id="detailsColumn" minWidth="100" sortable="false"/>
|
<TableColumn text="Balance (BTC)" fx:id="balanceColumn" minWidth="110"/>
|
||||||
<TableColumn text="Address" fx:id="addressColumn" minWidth="240" sortable="false"/>
|
|
||||||
<TableColumn text="Balance" fx:id="balanceColumn" minWidth="90" sortable="false"/>
|
|
||||||
<TableColumn text="Confirmations" fx:id="confidenceColumn" minWidth="30" sortable="false"/>
|
|
||||||
</columns>
|
</columns>
|
||||||
</TableView>
|
</TableView>
|
||||||
|
|
||||||
|
|
|
@ -17,15 +17,19 @@
|
||||||
|
|
||||||
package io.bitsquare.gui.main.funds.reserved;
|
package io.bitsquare.gui.main.funds.reserved;
|
||||||
|
|
||||||
|
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||||
|
import io.bitsquare.btc.AddressEntry;
|
||||||
import io.bitsquare.btc.WalletService;
|
import io.bitsquare.btc.WalletService;
|
||||||
import io.bitsquare.btc.listeners.BalanceListener;
|
import io.bitsquare.btc.listeners.BalanceListener;
|
||||||
import io.bitsquare.common.util.Utilities;
|
import io.bitsquare.common.util.Utilities;
|
||||||
import io.bitsquare.gui.common.view.ActivatableView;
|
import io.bitsquare.gui.common.view.ActivatableView;
|
||||||
import io.bitsquare.gui.common.view.FxmlView;
|
import io.bitsquare.gui.common.view.FxmlView;
|
||||||
|
import io.bitsquare.gui.components.HyperlinkWithIcon;
|
||||||
import io.bitsquare.gui.popups.OfferDetailsPopup;
|
import io.bitsquare.gui.popups.OfferDetailsPopup;
|
||||||
import io.bitsquare.gui.popups.Popup;
|
import io.bitsquare.gui.popups.Popup;
|
||||||
import io.bitsquare.gui.popups.TradeDetailsPopup;
|
import io.bitsquare.gui.popups.TradeDetailsPopup;
|
||||||
import io.bitsquare.gui.util.BSFormatter;
|
import io.bitsquare.gui.util.BSFormatter;
|
||||||
|
import io.bitsquare.trade.Tradable;
|
||||||
import io.bitsquare.trade.Trade;
|
import io.bitsquare.trade.Trade;
|
||||||
import io.bitsquare.trade.TradeManager;
|
import io.bitsquare.trade.TradeManager;
|
||||||
import io.bitsquare.trade.offer.OpenOffer;
|
import io.bitsquare.trade.offer.OpenOffer;
|
||||||
|
@ -59,7 +63,8 @@ public class ReservedView extends ActivatableView<VBox, Void> {
|
||||||
private final BSFormatter formatter;
|
private final BSFormatter formatter;
|
||||||
private final OfferDetailsPopup offerDetailsPopup;
|
private final OfferDetailsPopup offerDetailsPopup;
|
||||||
private final TradeDetailsPopup tradeDetailsPopup;
|
private final TradeDetailsPopup tradeDetailsPopup;
|
||||||
private final ObservableList<ReservedListItem> addressList = FXCollections.observableArrayList();
|
private final ObservableList<ReservedListItem> reservedAddresses = FXCollections.observableArrayList();
|
||||||
|
private BalanceListener balanceListener;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -82,30 +87,31 @@ public class ReservedView extends ActivatableView<VBox, Void> {
|
||||||
@Override
|
@Override
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||||
table.setPlaceholder(new Label("No funded are reserved in open offers or trades"));
|
table.setPlaceholder(new Label("No funds are reserved in open offers or trades"));
|
||||||
|
setDateColumnCellFactory();
|
||||||
setLabelColumnCellFactory();
|
setDetailsColumnCellFactory();
|
||||||
setAddressColumnCellFactory();
|
setAddressColumnCellFactory();
|
||||||
setBalanceColumnCellFactory();
|
setBalanceColumnCellFactory();
|
||||||
setConfidenceColumnCellFactory();
|
table.getSortOrder().add(dateColumn);
|
||||||
|
balanceListener = new BalanceListener() {
|
||||||
|
@Override
|
||||||
|
public void onBalanceChanged(Coin balance) {
|
||||||
|
updateList();
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void activate() {
|
protected void activate() {
|
||||||
updateList();
|
updateList();
|
||||||
table.setItems(addressList);
|
|
||||||
|
|
||||||
walletService.addBalanceListener(new BalanceListener() {
|
walletService.addBalanceListener(balanceListener);
|
||||||
@Override
|
|
||||||
public void onBalanceChanged(Coin balance) {
|
|
||||||
updateList();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void deactivate() {
|
protected void deactivate() {
|
||||||
addressList.forEach(ReservedListItem::cleanup);
|
reservedAddresses.forEach(ReservedListItem::cleanup);
|
||||||
|
walletService.removeBalanceListener(balanceListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -114,10 +120,13 @@ public class ReservedView extends ActivatableView<VBox, Void> {
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private void updateList() {
|
private void updateList() {
|
||||||
addressList.forEach(ReservedListItem::cleanup);
|
reservedAddresses.forEach(ReservedListItem::cleanup);
|
||||||
addressList.setAll(Stream.concat(openOfferManager.getOpenOffers().stream(), tradeManager.getTrades().stream())
|
reservedAddresses.setAll(Stream.concat(openOfferManager.getOpenOffers().stream(), tradeManager.getTrades().stream())
|
||||||
.map(tradable -> new ReservedListItem(tradable, walletService.getAddressEntryByOfferId(tradable.getOffer().getId()), walletService, formatter))
|
.map(tradable -> new ReservedListItem(tradable, walletService.getAddressEntryByOfferId(tradable.getOffer().getId()), walletService, formatter))
|
||||||
.collect(Collectors.toList()));
|
.collect(Collectors.toList()));
|
||||||
|
|
||||||
|
reservedAddresses.sort((o1, o2) -> getTradable(o2).get().getDate().compareTo(getTradable(o1).get().getDate()));
|
||||||
|
table.setItems(reservedAddresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openBlockExplorer(ReservedListItem item) {
|
private void openBlockExplorer(ReservedListItem item) {
|
||||||
|
@ -130,47 +139,115 @@ public class ReservedView extends ActivatableView<VBox, Void> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Optional<Tradable> getTradable(ReservedListItem item) {
|
||||||
|
String offerId = item.getAddressEntry().getOfferId();
|
||||||
|
Optional<Trade> tradeOptional = tradeManager.getTradeById(offerId);
|
||||||
|
if (tradeOptional.isPresent()) {
|
||||||
|
return Optional.of(tradeOptional.get());
|
||||||
|
} else if (openOfferManager.getOpenOfferById(offerId).isPresent()) {
|
||||||
|
return Optional.of(openOfferManager.getOpenOfferById(offerId).get());
|
||||||
|
} else {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openDetailPopup(ReservedListItem item) {
|
||||||
|
Optional<Tradable> tradableOptional = getTradable(item);
|
||||||
|
if (tradableOptional.isPresent()) {
|
||||||
|
Tradable tradable = tradableOptional.get();
|
||||||
|
if (tradable instanceof Trade) {
|
||||||
|
tradeDetailsPopup.show((Trade) tradable);
|
||||||
|
} else if (tradable instanceof OpenOffer) {
|
||||||
|
offerDetailsPopup.show(tradable.getOffer());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// ColumnCellFactories
|
// ColumnCellFactories
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private void setLabelColumnCellFactory() {
|
private void setDateColumnCellFactory() {
|
||||||
detailsColumn.setCellValueFactory((addressListItem) -> new ReadOnlyObjectWrapper<>(addressListItem.getValue()));
|
dateColumn.setCellValueFactory((addressListItem) -> new ReadOnlyObjectWrapper<>(addressListItem.getValue()));
|
||||||
detailsColumn.setCellFactory(new Callback<TableColumn<ReservedListItem, ReservedListItem>,
|
dateColumn.setCellFactory(new Callback<TableColumn<ReservedListItem, ReservedListItem>,
|
||||||
TableCell<ReservedListItem,
|
TableCell<ReservedListItem, ReservedListItem>>() {
|
||||||
ReservedListItem>>() {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TableCell<ReservedListItem, ReservedListItem> call(TableColumn<ReservedListItem,
|
public TableCell<ReservedListItem, ReservedListItem> call(TableColumn<ReservedListItem,
|
||||||
ReservedListItem> column) {
|
ReservedListItem> column) {
|
||||||
return new TableCell<ReservedListItem, ReservedListItem>() {
|
return new TableCell<ReservedListItem, ReservedListItem>() {
|
||||||
|
|
||||||
private Hyperlink hyperlink;
|
@Override
|
||||||
|
public void updateItem(final ReservedListItem item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
if (item != null && !empty) {
|
||||||
|
if (getTradable(item).isPresent())
|
||||||
|
setText(formatter.formatDateTime(getTradable(item).get().getDate()));
|
||||||
|
else
|
||||||
|
setText("No date available");
|
||||||
|
} else {
|
||||||
|
setText("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDetailsColumnCellFactory() {
|
||||||
|
detailsColumn.setCellValueFactory((addressListItem) -> new ReadOnlyObjectWrapper<>(addressListItem.getValue()));
|
||||||
|
detailsColumn.setCellFactory(new Callback<TableColumn<ReservedListItem, ReservedListItem>,
|
||||||
|
TableCell<ReservedListItem, ReservedListItem>>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TableCell<ReservedListItem, ReservedListItem> call(TableColumn<ReservedListItem,
|
||||||
|
ReservedListItem> column) {
|
||||||
|
return new TableCell<ReservedListItem, ReservedListItem>() {
|
||||||
|
|
||||||
|
private HyperlinkWithIcon field;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateItem(final ReservedListItem item, boolean empty) {
|
public void updateItem(final ReservedListItem item, boolean empty) {
|
||||||
super.updateItem(item, empty);
|
super.updateItem(item, empty);
|
||||||
|
|
||||||
if (item != null && !empty) {
|
if (item != null && !empty) {
|
||||||
hyperlink = new Hyperlink(item.getLabel());
|
Optional<Tradable> tradableOptional = getTradable(item);
|
||||||
if (item.getAddressEntry().getOfferId() != null) {
|
if (tradableOptional.isPresent()) {
|
||||||
Tooltip tooltip = new Tooltip(item.getAddressEntry().getOfferId());
|
AddressEntry addressEntry = item.getAddressEntry();
|
||||||
Tooltip.install(hyperlink, tooltip);
|
String details;
|
||||||
|
if (addressEntry.getContext() == AddressEntry.Context.TRADE) {
|
||||||
|
String prefix;
|
||||||
|
Tradable tradable = tradableOptional.get();
|
||||||
|
if (tradable instanceof Trade)
|
||||||
|
prefix = "Trade ID: ";
|
||||||
|
else if (tradable instanceof OpenOffer)
|
||||||
|
prefix = "Offer ID: ";
|
||||||
|
else
|
||||||
|
prefix = "";
|
||||||
|
|
||||||
hyperlink.setOnAction(event -> {
|
details = prefix + addressEntry.getShortOfferId();
|
||||||
Optional<Trade> tradeOptional = tradeManager.getTradeById(item.getAddressEntry().getOfferId());
|
} else if (addressEntry.getContext() == AddressEntry.Context.ARBITRATOR) {
|
||||||
Optional<OpenOffer> openOfferOptional = openOfferManager.getOpenOfferById(item.getAddressEntry().getOfferId());
|
details = "Arbitration fee";
|
||||||
if (tradeOptional.isPresent())
|
} else {
|
||||||
tradeDetailsPopup.show(tradeOptional.get());
|
details = "-";
|
||||||
else if (openOfferOptional.isPresent())
|
|
||||||
offerDetailsPopup.show(openOfferOptional.get().getOffer());
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
setGraphic(hyperlink);
|
|
||||||
|
field = new HyperlinkWithIcon(details + " (" + item.getFundsInfo() + ")",
|
||||||
|
AwesomeIcon.INFO_SIGN);
|
||||||
|
field.setOnAction(event -> openDetailPopup(item));
|
||||||
|
field.setTooltip(new Tooltip("Open popup for details"));
|
||||||
|
setGraphic(field);
|
||||||
|
} else if (item.getAddressEntry().getContext() == AddressEntry.Context.ARBITRATOR) {
|
||||||
|
setGraphic(new Label("Arbitrators fee"));
|
||||||
|
} else {
|
||||||
|
setGraphic(new Label("No details available"));
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
setGraphic(null);
|
setGraphic(null);
|
||||||
setId(null);
|
if (field != null)
|
||||||
|
field.setOnAction(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -188,19 +265,23 @@ public class ReservedView extends ActivatableView<VBox, Void> {
|
||||||
public TableCell<ReservedListItem, ReservedListItem> call(TableColumn<ReservedListItem,
|
public TableCell<ReservedListItem, ReservedListItem> call(TableColumn<ReservedListItem,
|
||||||
ReservedListItem> column) {
|
ReservedListItem> column) {
|
||||||
return new TableCell<ReservedListItem, ReservedListItem>() {
|
return new TableCell<ReservedListItem, ReservedListItem>() {
|
||||||
private Hyperlink hyperlink;
|
private HyperlinkWithIcon hyperlinkWithIcon;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateItem(final ReservedListItem item, boolean empty) {
|
public void updateItem(final ReservedListItem item, boolean empty) {
|
||||||
super.updateItem(item, empty);
|
super.updateItem(item, empty);
|
||||||
|
|
||||||
if (item != null && !empty) {
|
if (item != null && !empty) {
|
||||||
hyperlink = new Hyperlink(item.getAddressString());
|
String address = item.getAddressString();
|
||||||
hyperlink.setOnAction(event -> openBlockExplorer(item));
|
hyperlinkWithIcon = new HyperlinkWithIcon(address, AwesomeIcon.EXTERNAL_LINK);
|
||||||
setGraphic(hyperlink);
|
hyperlinkWithIcon.setOnAction(event -> openBlockExplorer(item));
|
||||||
|
hyperlinkWithIcon.setTooltip(new Tooltip("Open external blockchain explorer for " +
|
||||||
|
"address: " + address));
|
||||||
|
setGraphic(hyperlinkWithIcon);
|
||||||
} else {
|
} else {
|
||||||
setGraphic(null);
|
setGraphic(null);
|
||||||
setId(null);
|
if (hyperlinkWithIcon != null)
|
||||||
|
hyperlinkWithIcon.setOnAction(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -228,33 +309,6 @@ public class ReservedView extends ActivatableView<VBox, Void> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setConfidenceColumnCellFactory() {
|
|
||||||
confidenceColumn.setCellValueFactory((addressListItem) ->
|
|
||||||
new ReadOnlyObjectWrapper<>(addressListItem.getValue()));
|
|
||||||
confidenceColumn.setCellFactory(
|
|
||||||
new Callback<TableColumn<ReservedListItem, ReservedListItem>, TableCell<ReservedListItem,
|
|
||||||
ReservedListItem>>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TableCell<ReservedListItem, ReservedListItem> call(TableColumn<ReservedListItem,
|
|
||||||
ReservedListItem> column) {
|
|
||||||
return new TableCell<ReservedListItem, ReservedListItem>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateItem(final ReservedListItem item, boolean empty) {
|
|
||||||
super.updateItem(item, empty);
|
|
||||||
|
|
||||||
if (item != null && !empty) {
|
|
||||||
setGraphic(item.getProgressIndicator());
|
|
||||||
} else {
|
|
||||||
setGraphic(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -113,7 +113,7 @@ public class TransactionsListItem {
|
||||||
details = "Create offer fee: " + tradable.getShortId();
|
details = "Create offer fee: " + tradable.getShortId();
|
||||||
} else if (tradable instanceof Trade) {
|
} else if (tradable instanceof Trade) {
|
||||||
Trade trade = (Trade) tradable;
|
Trade trade = (Trade) tradable;
|
||||||
if (trade.getTakeOfferFeeTx() != null && trade.getTakeOfferFeeTx().getHashAsString().equals(txId)) {
|
if (trade.getTakeOfferFeeTxId() != null && trade.getTakeOfferFeeTxId().equals(txId)) {
|
||||||
details = "Take offer fee: " + tradable.getShortId();
|
details = "Take offer fee: " + tradable.getShortId();
|
||||||
} else if (trade.getOffer() != null &&
|
} else if (trade.getOffer() != null &&
|
||||||
trade.getOffer().getOfferFeePaymentTxID() != null &&
|
trade.getOffer().getOfferFeePaymentTxID() != null &&
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
<TableColumn text="Details" fx:id="detailsColumn" minWidth="210" maxWidth="210"/>
|
<TableColumn text="Details" fx:id="detailsColumn" minWidth="210" maxWidth="210"/>
|
||||||
<TableColumn text="Address" fx:id="addressColumn" minWidth="180"/>
|
<TableColumn text="Address" fx:id="addressColumn" minWidth="180"/>
|
||||||
<TableColumn text="Transaction" fx:id="transactionColumn" minWidth="100"/>
|
<TableColumn text="Transaction" fx:id="transactionColumn" minWidth="100"/>
|
||||||
<TableColumn text="Amount" fx:id="amountColumn" minWidth="110" maxWidth="110">
|
<TableColumn text="Amount (BTC)" fx:id="amountColumn" minWidth="110" maxWidth="110">
|
||||||
<cellValueFactory>
|
<cellValueFactory>
|
||||||
<PropertyValueFactory property="amount"/>
|
<PropertyValueFactory property="amount"/>
|
||||||
</cellValueFactory>
|
</cellValueFactory>
|
||||||
|
|
|
@ -73,7 +73,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
||||||
private final BSFormatter formatter;
|
private final BSFormatter formatter;
|
||||||
private final Preferences preferences;
|
private final Preferences preferences;
|
||||||
private final TradeDetailsPopup tradeDetailsPopup;
|
private final TradeDetailsPopup tradeDetailsPopup;
|
||||||
private DisputeManager disputeManager;
|
private final DisputeManager disputeManager;
|
||||||
private final OfferDetailsPopup offerDetailsPopup;
|
private final OfferDetailsPopup offerDetailsPopup;
|
||||||
private WalletEventListener walletEventListener;
|
private WalletEventListener walletEventListener;
|
||||||
|
|
||||||
|
@ -150,7 +150,6 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
||||||
@Override
|
@Override
|
||||||
protected void activate() {
|
protected void activate() {
|
||||||
updateList();
|
updateList();
|
||||||
table.setItems(transactionsListItems);
|
|
||||||
walletService.getWallet().addEventListener(walletEventListener);
|
walletService.getWallet().addEventListener(walletEventListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,19 +168,19 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
||||||
Stream<Tradable> concat1 = Stream.concat(openOfferManager.getOpenOffers().stream(), tradeManager.getTrades().stream());
|
Stream<Tradable> concat1 = Stream.concat(openOfferManager.getOpenOffers().stream(), tradeManager.getTrades().stream());
|
||||||
Stream<Tradable> concat2 = Stream.concat(concat1, closedTradableManager.getClosedTrades().stream());
|
Stream<Tradable> concat2 = Stream.concat(concat1, closedTradableManager.getClosedTrades().stream());
|
||||||
Stream<Tradable> concat3 = Stream.concat(concat2, failedTradesManager.getFailedTrades().stream());
|
Stream<Tradable> concat3 = Stream.concat(concat2, failedTradesManager.getFailedTrades().stream());
|
||||||
Set<Tradable> allTradables = concat3.collect(Collectors.toSet());
|
Set<Tradable> concated = concat3.collect(Collectors.toSet());
|
||||||
|
|
||||||
List<TransactionsListItem> listItems = walletService.getWallet().getRecentTransactions(1000, true).stream()
|
List<TransactionsListItem> listItems = walletService.getWallet().getRecentTransactions(1000, true).stream()
|
||||||
.map(transaction -> {
|
.map(transaction -> {
|
||||||
Optional<Tradable> tradableOptional = allTradables.stream()
|
Optional<Tradable> tradableOptional = concated.stream()
|
||||||
.filter(e -> {
|
.filter(e -> {
|
||||||
String txId = transaction.getHashAsString();
|
String txId = transaction.getHashAsString();
|
||||||
if (e instanceof OpenOffer)
|
if (e instanceof OpenOffer)
|
||||||
return e.getOffer().getOfferFeePaymentTxID().equals(txId);
|
return e.getOffer().getOfferFeePaymentTxID().equals(txId);
|
||||||
else if (e instanceof Trade) {
|
else if (e instanceof Trade) {
|
||||||
Trade trade = (Trade) e;
|
Trade trade = (Trade) e;
|
||||||
return (trade.getTakeOfferFeeTx() != null &&
|
return (trade.getTakeOfferFeeTxId() != null &&
|
||||||
trade.getTakeOfferFeeTx().getHashAsString().equals(txId)) ||
|
trade.getTakeOfferFeeTxId().equals(txId)) ||
|
||||||
(trade.getOffer() != null &&
|
(trade.getOffer() != null &&
|
||||||
trade.getOffer().getOfferFeePaymentTxID() != null &&
|
trade.getOffer().getOfferFeePaymentTxID() != null &&
|
||||||
trade.getOffer().getOfferFeePaymentTxID().equals(txId)) ||
|
trade.getOffer().getOfferFeePaymentTxID().equals(txId)) ||
|
||||||
|
@ -205,6 +204,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
||||||
// are sorted by getRecentTransactions
|
// are sorted by getRecentTransactions
|
||||||
transactionsListItems.forEach(TransactionsListItem::cleanup);
|
transactionsListItems.forEach(TransactionsListItem::cleanup);
|
||||||
transactionsListItems.setAll(listItems);
|
transactionsListItems.setAll(listItems);
|
||||||
|
table.setItems(transactionsListItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openBlockExplorer(TransactionsListItem item) {
|
private void openBlockExplorer(TransactionsListItem item) {
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
<PropertyValueFactory property="addressString"/>
|
<PropertyValueFactory property="addressString"/>
|
||||||
</cellValueFactory>
|
</cellValueFactory>
|
||||||
</TableColumn>
|
</TableColumn>
|
||||||
<TableColumn text="Balance" fx:id="balanceColumn" minWidth="110"/>
|
<TableColumn text="Balance (BTC)" fx:id="balanceColumn" minWidth="110"/>
|
||||||
<TableColumn text="Selection" fx:id="selectColumn" minWidth="160" sortable="false"/>
|
<TableColumn text="Selection" fx:id="selectColumn" minWidth="160" sortable="false"/>
|
||||||
</columns>
|
</columns>
|
||||||
</TableView>
|
</TableView>
|
||||||
|
|
|
@ -21,7 +21,6 @@ import com.google.common.util.concurrent.FutureCallback;
|
||||||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||||
import io.bitsquare.app.BitsquareApp;
|
import io.bitsquare.app.BitsquareApp;
|
||||||
import io.bitsquare.btc.AddressEntry;
|
import io.bitsquare.btc.AddressEntry;
|
||||||
import io.bitsquare.btc.FeePolicy;
|
|
||||||
import io.bitsquare.btc.Restrictions;
|
import io.bitsquare.btc.Restrictions;
|
||||||
import io.bitsquare.btc.WalletService;
|
import io.bitsquare.btc.WalletService;
|
||||||
import io.bitsquare.btc.listeners.BalanceListener;
|
import io.bitsquare.btc.listeners.BalanceListener;
|
||||||
|
@ -92,6 +91,8 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||||
private final TradeDetailsPopup tradeDetailsPopup;
|
private final TradeDetailsPopup tradeDetailsPopup;
|
||||||
private final ObservableList<WithdrawalListItem> fundedAddresses = FXCollections.observableArrayList();
|
private final ObservableList<WithdrawalListItem> fundedAddresses = FXCollections.observableArrayList();
|
||||||
private Set<WithdrawalListItem> selectedItems = new HashSet<>();
|
private Set<WithdrawalListItem> selectedItems = new HashSet<>();
|
||||||
|
private BalanceListener balanceListener;
|
||||||
|
private Set<String> fromAddresses;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -121,7 +122,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||||
@Override
|
@Override
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||||
table.setPlaceholder(new Label("No funds for withdrawal available"));
|
table.setPlaceholder(new Label("No funds for withdrawal are available"));
|
||||||
setDateColumnCellFactory();
|
setDateColumnCellFactory();
|
||||||
setDetailsColumnCellFactory();
|
setDetailsColumnCellFactory();
|
||||||
setAddressColumnCellFactory();
|
setAddressColumnCellFactory();
|
||||||
|
@ -129,19 +130,22 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||||
setSelectColumnCellFactory();
|
setSelectColumnCellFactory();
|
||||||
table.getSortOrder().add(dateColumn);
|
table.getSortOrder().add(dateColumn);
|
||||||
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
|
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
|
||||||
|
|
||||||
|
balanceListener = new BalanceListener() {
|
||||||
|
@Override
|
||||||
|
public void onBalanceChanged(Coin balance) {
|
||||||
|
updateList();
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void activate() {
|
protected void activate() {
|
||||||
updateList();
|
updateList();
|
||||||
table.setItems(fundedAddresses);
|
|
||||||
reset();
|
reset();
|
||||||
walletService.addBalanceListener(new BalanceListener() {
|
|
||||||
@Override
|
walletService.addBalanceListener(balanceListener);
|
||||||
public void onBalanceChanged(Coin balance) {
|
|
||||||
updateList();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
withdrawButton.disableProperty().bind(Bindings.createBooleanBinding(() -> !areInputsValid(),
|
withdrawButton.disableProperty().bind(Bindings.createBooleanBinding(() -> !areInputsValid(),
|
||||||
amountTextField.textProperty(), withdrawToTextField.textProperty()));
|
amountTextField.textProperty(), withdrawToTextField.textProperty()));
|
||||||
}
|
}
|
||||||
|
@ -150,6 +154,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||||
protected void deactivate() {
|
protected void deactivate() {
|
||||||
fundedAddresses.forEach(WithdrawalListItem::cleanup);
|
fundedAddresses.forEach(WithdrawalListItem::cleanup);
|
||||||
withdrawButton.disableProperty().unbind();
|
withdrawButton.disableProperty().unbind();
|
||||||
|
walletService.removeBalanceListener(balanceListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -160,7 +165,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||||
@FXML
|
@FXML
|
||||||
public void onWithdraw() {
|
public void onWithdraw() {
|
||||||
Coin senderAmount = formatter.parseToCoin(amountTextField.getText());
|
Coin senderAmount = formatter.parseToCoin(amountTextField.getText());
|
||||||
if (Restrictions.isAboveDust(senderAmount)) {
|
if (Restrictions.isAboveFixedTxFeeAndDust(senderAmount)) {
|
||||||
FutureCallback<Transaction> callback = new FutureCallback<Transaction>() {
|
FutureCallback<Transaction> callback = new FutureCallback<Transaction>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(@javax.annotation.Nullable Transaction transaction) {
|
public void onSuccess(@javax.annotation.Nullable Transaction transaction) {
|
||||||
|
@ -176,12 +181,9 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||||
log.error("onWithdraw onFailure");
|
log.error("onWithdraw onFailure");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// try {
|
try {
|
||||||
/* Coin requiredFee = walletService.getRequiredFee(withdrawFromTextField.getText(),
|
Coin requiredFee = walletService.getRequiredFeeForMultipleAddresses(fromAddresses,
|
||||||
withdrawToTextField.getText(), senderAmount, null);*/
|
withdrawToTextField.getText(), senderAmount, null);
|
||||||
// TODO static fee might be not enough when using many inputs, but for now its high enough to get probably into the blockchain
|
|
||||||
// Use bitcoinJ fee calculation instead....
|
|
||||||
Coin requiredFee = FeePolicy.getFeePerKb();
|
|
||||||
Coin receiverAmount = senderAmount.subtract(requiredFee);
|
Coin receiverAmount = senderAmount.subtract(requiredFee);
|
||||||
if (BitsquareApp.DEV_MODE) {
|
if (BitsquareApp.DEV_MODE) {
|
||||||
doWithdraw(receiverAmount, callback);
|
doWithdraw(receiverAmount, callback);
|
||||||
|
@ -197,12 +199,14 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||||
.show();
|
.show();
|
||||||
|
|
||||||
}
|
}
|
||||||
/*} catch (AddressFormatException | InsufficientMoneyException e) {
|
} catch (AddressFormatException | InsufficientMoneyException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
log.error(e.getMessage());
|
log.error(e.getMessage());
|
||||||
}*/
|
}
|
||||||
} else {
|
} else {
|
||||||
new Popup().warning("The amount to transfer is lower than the transaction fee and the min. possible tx value.").show();
|
new Popup()
|
||||||
|
.warning("The amount to transfer is lower than the transaction fee and the min. possible tx value (dust).")
|
||||||
|
.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,6 +216,10 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||||
else
|
else
|
||||||
selectedItems.remove(item);
|
selectedItems.remove(item);
|
||||||
|
|
||||||
|
fromAddresses = selectedItems.stream()
|
||||||
|
.map(WithdrawalListItem::getAddressString)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
if (!selectedItems.isEmpty()) {
|
if (!selectedItems.isEmpty()) {
|
||||||
Coin sum = Coin.valueOf(selectedItems.stream().mapToLong(e -> e.getBalance().getValue()).sum());
|
Coin sum = Coin.valueOf(selectedItems.stream().mapToLong(e -> e.getBalance().getValue()).sum());
|
||||||
if (sum.isPositive()) {
|
if (sum.isPositive()) {
|
||||||
|
@ -225,10 +233,9 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||||
withdrawFromTextField.setText(selectedItems.stream().findAny().get().getAddressEntry().getAddressString());
|
withdrawFromTextField.setText(selectedItems.stream().findAny().get().getAddressEntry().getAddressString());
|
||||||
withdrawFromTextField.setTooltip(null);
|
withdrawFromTextField.setTooltip(null);
|
||||||
} else {
|
} else {
|
||||||
//selectedItems.stream().
|
|
||||||
String tooltipText = "Withdraw from multiple addresses:\n" +
|
String tooltipText = "Withdraw from multiple addresses:\n" +
|
||||||
selectedItems.stream()
|
selectedItems.stream()
|
||||||
.map(e -> e.getAddressString())
|
.map(WithdrawalListItem::getAddressString)
|
||||||
.collect(Collectors.joining(",\n"));
|
.collect(Collectors.joining(",\n"));
|
||||||
int abbr = Math.max(10, 66 / selectedItems.size());
|
int abbr = Math.max(10, 66 / selectedItems.size());
|
||||||
String text = "Withdraw from multiple addresses (" +
|
String text = "Withdraw from multiple addresses (" +
|
||||||
|
@ -299,6 +306,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||||
|
|
||||||
return date2.compareTo(date1);
|
return date2.compareTo(date1);
|
||||||
});
|
});
|
||||||
|
table.setItems(fundedAddresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doWithdraw(Coin amount, FutureCallback<Transaction> callback) {
|
private void doWithdraw(Coin amount, FutureCallback<Transaction> callback) {
|
||||||
|
@ -306,19 +314,13 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||||
walletPasswordPopup.show().onAesKey(aesKey -> sendFunds(amount, aesKey, callback));
|
walletPasswordPopup.show().onAesKey(aesKey -> sendFunds(amount, aesKey, callback));
|
||||||
else
|
else
|
||||||
sendFunds(amount, null, callback);
|
sendFunds(amount, null, callback);
|
||||||
updateList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendFunds(Coin amount, KeyParameter aesKey, FutureCallback<Transaction> callback) {
|
private void sendFunds(Coin amount, KeyParameter aesKey, FutureCallback<Transaction> callback) {
|
||||||
try {
|
try {
|
||||||
Set<String> fromAddresses = selectedItems.stream()
|
|
||||||
.map(e -> e.getAddressString())
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
if (!fromAddresses.isEmpty()) {
|
|
||||||
walletService.sendFundsForMultipleAddresses(fromAddresses, withdrawToTextField.getText(), amount, null, aesKey, callback);
|
walletService.sendFundsForMultipleAddresses(fromAddresses, withdrawToTextField.getText(), amount, null, aesKey, callback);
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
}
|
updateList();
|
||||||
} catch (AddressFormatException e) {
|
} catch (AddressFormatException e) {
|
||||||
new Popup().error("The address is not correct. Please check the address format.").show();
|
new Popup().error("The address is not correct. Please check the address format.").show();
|
||||||
} catch (InsufficientMoneyException e) {
|
} catch (InsufficientMoneyException e) {
|
||||||
|
@ -346,7 +348,6 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||||
withdrawToTextField.setText("mxAkWWaQBqwqcYstKzqLku3kzR6pbu2zHq");
|
withdrawToTextField.setText("mxAkWWaQBqwqcYstKzqLku3kzR6pbu2zHq");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Optional<Tradable> getTradable(WithdrawalListItem item) {
|
private Optional<Tradable> getTradable(WithdrawalListItem item) {
|
||||||
String offerId = item.getAddressEntry().getOfferId();
|
String offerId = item.getAddressEntry().getOfferId();
|
||||||
Optional<Tradable> tradableOptional = closedTradableManager.getTradableById(offerId);
|
Optional<Tradable> tradableOptional = closedTradableManager.getTradableById(offerId);
|
||||||
|
@ -359,12 +360,6 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isTradableAvailable(WithdrawalListItem item) {
|
|
||||||
String offerId = item.getAddressEntry().getOfferId();
|
|
||||||
return closedTradableManager.getTradableById(offerId).isPresent() ||
|
|
||||||
failedTradesManager.getTradeById(offerId).isPresent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean areInputsValid() {
|
private boolean areInputsValid() {
|
||||||
return btcAddressValidator.validate(withdrawToTextField.getText()).isValid &&
|
return btcAddressValidator.validate(withdrawToTextField.getText()).isValid &&
|
||||||
amountTextField.getText().length() > 0 &&
|
amountTextField.getText().length() > 0 &&
|
||||||
|
@ -420,22 +415,19 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||||
super.updateItem(item, empty);
|
super.updateItem(item, empty);
|
||||||
|
|
||||||
if (item != null && !empty) {
|
if (item != null && !empty) {
|
||||||
if (isTradableAvailable(item)) {
|
Optional<Tradable> tradableOptional = getTradable(item);
|
||||||
|
if (tradableOptional.isPresent()) {
|
||||||
AddressEntry addressEntry = item.getAddressEntry();
|
AddressEntry addressEntry = item.getAddressEntry();
|
||||||
String details;
|
String details;
|
||||||
if (addressEntry.getContext() == AddressEntry.Context.TRADE) {
|
if (addressEntry.getContext() == AddressEntry.Context.TRADE) {
|
||||||
String prefix;
|
String prefix;
|
||||||
if (getTradable(item).isPresent()) {
|
Tradable tradable = tradableOptional.get();
|
||||||
Tradable tradable = getTradable(item).get();
|
|
||||||
if (tradable instanceof Trade)
|
if (tradable instanceof Trade)
|
||||||
prefix = "Trade ID: ";
|
prefix = "Trade ID: ";
|
||||||
else if (tradable instanceof OpenOffer)
|
else if (tradable instanceof OpenOffer)
|
||||||
prefix = "Offer ID: ";
|
prefix = "Offer ID: ";
|
||||||
else
|
else
|
||||||
prefix = "";
|
prefix = "";
|
||||||
} else {
|
|
||||||
prefix = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
details = prefix + addressEntry.getShortOfferId();
|
details = prefix + addressEntry.getShortOfferId();
|
||||||
} else if (addressEntry.getContext() == AddressEntry.Context.ARBITRATOR) {
|
} else if (addressEntry.getContext() == AddressEntry.Context.ARBITRATOR) {
|
||||||
|
|
|
@ -121,11 +121,10 @@ public class TradeDetailsPopup extends Popup {
|
||||||
|
|
||||||
if (buyerPaymentAccountContractData == null && sellerPaymentAccountContractData == null)
|
if (buyerPaymentAccountContractData == null && sellerPaymentAccountContractData == null)
|
||||||
rows++;
|
rows++;
|
||||||
|
|
||||||
if (trade.getTakeOfferFeeTx() != null)
|
|
||||||
rows++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (trade.getTakeOfferFeeTxId() != null)
|
||||||
|
rows++;
|
||||||
if (trade.getDepositTx() != null)
|
if (trade.getDepositTx() != null)
|
||||||
rows++;
|
rows++;
|
||||||
if (trade.getPayoutTx() != null)
|
if (trade.getPayoutTx() != null)
|
||||||
|
@ -156,8 +155,8 @@ public class TradeDetailsPopup extends Popup {
|
||||||
}
|
}
|
||||||
|
|
||||||
addLabelTxIdTextField(gridPane, ++rowIndex, "Offer fee transaction ID:", offer.getOfferFeePaymentTxID());
|
addLabelTxIdTextField(gridPane, ++rowIndex, "Offer fee transaction ID:", offer.getOfferFeePaymentTxID());
|
||||||
if (contract != null && trade.getTakeOfferFeeTx() != null)
|
if (trade.getTakeOfferFeeTxId() != null)
|
||||||
addLabelTxIdTextField(gridPane, ++rowIndex, "Taker fee transaction ID:", trade.getTakeOfferFeeTx().getHashAsString());
|
addLabelTxIdTextField(gridPane, ++rowIndex, "Taker fee transaction ID:", trade.getTakeOfferFeeTxId());
|
||||||
|
|
||||||
if (trade.getDepositTx() != null)
|
if (trade.getDepositTx() != null)
|
||||||
addLabelTxIdTextField(gridPane, ++rowIndex, "Deposit transaction ID:", trade.getDepositTx().getHashAsString());
|
addLabelTxIdTextField(gridPane, ++rowIndex, "Deposit transaction ID:", trade.getDepositTx().getHashAsString());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue