mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-07-26 00:15:18 -04:00
Improve UI, add notification popups, fee warning,...
This commit is contained in:
parent
9438bc818e
commit
1f8b1b0e01
50 changed files with 634 additions and 435 deletions
|
@ -50,4 +50,6 @@ public class Tuple3<A, B, C> implements Serializable {
|
||||||
result = 31 * result + (third != null ? third.hashCode() : 0);
|
result = 31 * result + (third != null ? third.hashCode() : 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,5 +52,6 @@
|
||||||
<version>4.8</version>
|
<version>4.8</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -60,6 +60,11 @@ public class FeePolicy {
|
||||||
return FEE_PER_KB;
|
return FEE_PER_KB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Some wallets (Mycelium) don't support higher fees
|
||||||
|
public static Coin getMinFundingFee() {
|
||||||
|
return Coin.valueOf(20_000);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 0.001 BTC 0.1% of 1 BTC about 0.4 EUR @ 400 EUR/BTC
|
// 0.001 BTC 0.1% of 1 BTC about 0.4 EUR @ 400 EUR/BTC
|
||||||
public static Coin getCreateOfferFee() {
|
public static Coin getCreateOfferFee() {
|
||||||
|
|
|
@ -53,7 +53,6 @@ import java.util.*;
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
@ -90,7 +89,6 @@ public class WalletService {
|
||||||
private final IntegerProperty numPeers = new SimpleIntegerProperty(0);
|
private final IntegerProperty numPeers = new SimpleIntegerProperty(0);
|
||||||
private final ObjectProperty<List<Peer>> connectedPeers = new SimpleObjectProperty<>();
|
private final ObjectProperty<List<Peer>> connectedPeers = new SimpleObjectProperty<>();
|
||||||
public final BooleanProperty shutDownDone = new SimpleBooleanProperty();
|
public final BooleanProperty shutDownDone = new SimpleBooleanProperty();
|
||||||
private ArbitraryTransactionBloomFilter arbitraryTransactionBloomFilter;
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -705,86 +703,4 @@ public class WalletService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void requestTransactionBlockchainProvider(Transaction transaction, Consumer<Coin> resultHandler) {
|
|
||||||
// TODO use http server over tor to request tx in question
|
|
||||||
// https://btc.blockr.io/api/v1/tx/info/9a0c37209a45a0e61a50a62fcb7d0f52f3d6ed41faaf0afc044d642ab541b675
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void requestTransactionFromBlockChain(Transaction transaction, Consumer<Coin> resultHandler) {
|
|
||||||
requestTransactionBlockchainProvider(transaction, resultHandler);
|
|
||||||
|
|
||||||
/* arbitraryTransactionBloomFilter = new ArbitraryTransactionBloomFilter(transaction, resultHandler);
|
|
||||||
PeerGroup peerGroup = walletAppKit.peerGroup();
|
|
||||||
peerGroup.addEventListener(arbitraryTransactionBloomFilter);
|
|
||||||
peerGroup.addPeerFilterProvider(arbitraryTransactionBloomFilter);
|
|
||||||
|
|
||||||
log.debug("transaction=" + transaction);
|
|
||||||
log.debug("transaction.fee=" + transaction.getFee());*/
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ArbitraryTransactionBloomFilter extends AbstractPeerEventListener implements PeerFilterProvider {
|
|
||||||
private final Transaction transaction;
|
|
||||||
private final Consumer<Coin> resultHandler;
|
|
||||||
private final Set<TransactionOutPoint> transactionOutPoints;
|
|
||||||
|
|
||||||
public ArbitraryTransactionBloomFilter(Transaction transaction, Consumer<Coin> resultHandler) {
|
|
||||||
this.transaction = transaction;
|
|
||||||
this.resultHandler = resultHandler;
|
|
||||||
|
|
||||||
transactionOutPoints = transaction.getInputs().stream()
|
|
||||||
.map(e -> e.getOutpoint() != null ? e.getOutpoint() : null)
|
|
||||||
.filter(e -> e != null)
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
|
|
||||||
log.debug("transaction=" + transaction);
|
|
||||||
log.debug("transaction.fee=" + transaction.getFee());
|
|
||||||
log.debug("outpoints=" + transactionOutPoints);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getEarliestKeyCreationTime() {
|
|
||||||
return System.currentTimeMillis() / 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void beginBloomFilterCalculation() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBloomFilterElementCount() {
|
|
||||||
return transactionOutPoints.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BloomFilter getBloomFilter(int size, double falsePositiveRate, long nTweak) {
|
|
||||||
BloomFilter filter = new BloomFilter(size, falsePositiveRate, nTweak);
|
|
||||||
for (TransactionOutPoint transactionOutPoint : transactionOutPoints) {
|
|
||||||
filter.insert(transactionOutPoint.bitcoinSerialize());
|
|
||||||
}
|
|
||||||
return filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRequiringUpdateAllBloomFilter() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void endBloomFilterCalculation() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTransaction(Peer peer, Transaction tx) {
|
|
||||||
if (transactionOutPoints.contains(tx))
|
|
||||||
transactionOutPoints.remove(tx);
|
|
||||||
|
|
||||||
if (transactionOutPoints.isEmpty())
|
|
||||||
resultHandler.accept(transaction.getFee());
|
|
||||||
|
|
||||||
log.debug("## onTransaction: transaction=" + tx);
|
|
||||||
log.debug("## onTransaction: transaction.fee=" + tx.getFee());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package io.bitsquare.btc.http;
|
||||||
|
|
||||||
|
import org.bitcoinj.core.Coin;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public interface BlockchainApiProvider extends Serializable {
|
||||||
|
Coin getFee(String transactionId) throws IOException, HttpException;
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package io.bitsquare.btc.http;
|
||||||
|
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import io.bitsquare.app.Log;
|
||||||
|
import org.bitcoinj.core.Coin;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
// TODO route over tor, support several providers
|
||||||
|
public class BlockrIOProvider implements BlockchainApiProvider {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(BlockrIOProvider.class);
|
||||||
|
|
||||||
|
private final HttpClient httpClient;
|
||||||
|
|
||||||
|
public static void main(String[] args) throws HttpException, IOException {
|
||||||
|
Coin fee = new BlockrIOProvider()
|
||||||
|
.getFee("df67414652722d38b43dcbcac6927c97626a65bd4e76a2e2787e22948a7c5c47");
|
||||||
|
log.debug("fee " + fee.toFriendlyString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockrIOProvider() {
|
||||||
|
httpClient = new HttpClient("https://btc.blockr.io/api/v1/tx/info/");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Coin getFee(String transactionId) throws IOException, HttpException {
|
||||||
|
Log.traceCall("transactionId=" + transactionId);
|
||||||
|
try {
|
||||||
|
return Coin.parseCoin(new JsonParser()
|
||||||
|
.parse(httpClient.requestWithGET(transactionId))
|
||||||
|
.getAsJsonObject()
|
||||||
|
.get("data")
|
||||||
|
.getAsJsonObject()
|
||||||
|
.get("fee")
|
||||||
|
.getAsString());
|
||||||
|
} catch (IOException | HttpException e) {
|
||||||
|
log.warn("Error at requesting transaction data from block explorer " + httpClient + "\n" +
|
||||||
|
"Error =" + e.getMessage());
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
52
core/src/main/java/io/bitsquare/btc/http/HttpClient.java
Normal file
52
core/src/main/java/io/bitsquare/btc/http/HttpClient.java
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package io.bitsquare.btc.http;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
// TODO route over tor
|
||||||
|
public class HttpClient implements Serializable {
|
||||||
|
|
||||||
|
private String baseUrl;
|
||||||
|
|
||||||
|
public HttpClient(String baseUrl) {
|
||||||
|
this.baseUrl = baseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String requestWithGET(String param) throws IOException, HttpException {
|
||||||
|
HttpURLConnection connection = null;
|
||||||
|
try {
|
||||||
|
URL url = new URL(baseUrl + param);
|
||||||
|
connection = (HttpURLConnection) url.openConnection();
|
||||||
|
connection.setRequestMethod("GET");
|
||||||
|
connection.setConnectTimeout(10000);
|
||||||
|
|
||||||
|
if (connection.getResponseCode() == 200) {
|
||||||
|
return convertInputStreamToString(connection.getInputStream());
|
||||||
|
} else {
|
||||||
|
connection.getErrorStream().close();
|
||||||
|
throw new HttpException(convertInputStreamToString(connection.getErrorStream()));
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (connection != null)
|
||||||
|
connection.getInputStream().close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String convertInputStreamToString(InputStream inputStream) throws IOException {
|
||||||
|
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
String line;
|
||||||
|
while ((line = bufferedReader.readLine()) != null) {
|
||||||
|
stringBuilder.append(line);
|
||||||
|
}
|
||||||
|
return stringBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "HttpClient{" +
|
||||||
|
"baseUrl='" + baseUrl + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package io.bitsquare.btc.http;
|
||||||
|
|
||||||
|
public class HttpException extends Exception {
|
||||||
|
public HttpException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,7 +61,7 @@ public class PaymentMethod implements Serializable, Comparable {
|
||||||
public static final List<PaymentMethod> ALL_VALUES = new ArrayList<>(Arrays.asList(
|
public static final List<PaymentMethod> ALL_VALUES = new ArrayList<>(Arrays.asList(
|
||||||
OK_PAY = new PaymentMethod(OK_PAY_ID, 0, DAY), // tx instant so min. wait time
|
OK_PAY = new PaymentMethod(OK_PAY_ID, 0, DAY), // tx instant so min. wait time
|
||||||
PERFECT_MONEY = new PaymentMethod(PERFECT_MONEY_ID, 0, DAY),
|
PERFECT_MONEY = new PaymentMethod(PERFECT_MONEY_ID, 0, DAY),
|
||||||
SEPA = new PaymentMethod(SEPA_ID, 0, 7 * DAY), // sepa takes 1-3 business days. We use 7 days to include safety for holidays
|
SEPA = new PaymentMethod(SEPA_ID, 0, 8 * DAY), // sepa takes 1-3 business days. We use 8 days to include safety for holidays
|
||||||
SWISH = new PaymentMethod(SWISH_ID, 0, DAY),
|
SWISH = new PaymentMethod(SWISH_ID, 0, DAY),
|
||||||
ALI_PAY = new PaymentMethod(ALI_PAY_ID, 0, DAY),
|
ALI_PAY = new PaymentMethod(ALI_PAY_ID, 0, DAY),
|
||||||
/* FED_WIRE = new PaymentMethod(FED_WIRE_ID, 0, DAY),*/
|
/* FED_WIRE = new PaymentMethod(FED_WIRE_ID, 0, DAY),*/
|
||||||
|
|
|
@ -147,6 +147,7 @@ abstract public class Trade implements Tradable, Model, Serializable {
|
||||||
// Mutable
|
// Mutable
|
||||||
private DecryptedMsgWithPubKey decryptedMsgWithPubKey;
|
private DecryptedMsgWithPubKey decryptedMsgWithPubKey;
|
||||||
private Date takeOfferDate = new Date(0); // in some error cases the date is not set and cause null pointers, so we set a default
|
private Date takeOfferDate = new Date(0); // in some error cases the date is not set and cause null pointers, so we set a default
|
||||||
|
private int takeOfferDateAsBlockHeight;
|
||||||
private Coin tradeAmount;
|
private Coin tradeAmount;
|
||||||
private NodeAddress tradingPeerNodeAddress;
|
private NodeAddress tradingPeerNodeAddress;
|
||||||
protected State state;
|
protected State state;
|
||||||
|
@ -164,8 +165,6 @@ abstract public class Trade implements Tradable, Model, Serializable {
|
||||||
private int checkPaymentTimeAsBlockHeight;
|
private int checkPaymentTimeAsBlockHeight;
|
||||||
private NodeAddress arbitratorNodeAddress;
|
private NodeAddress arbitratorNodeAddress;
|
||||||
private String takerPaymentAccountId;
|
private String takerPaymentAccountId;
|
||||||
private boolean halfTradePeriodReachedWarningDisplayed;
|
|
||||||
private boolean tradePeriodOverWarningDisplayed;
|
|
||||||
private String errorMessage;
|
private String errorMessage;
|
||||||
transient private StringProperty errorMessageProperty;
|
transient private StringProperty errorMessageProperty;
|
||||||
transient private ObjectProperty<Coin> tradeAmountProperty;
|
transient private ObjectProperty<Coin> tradeAmountProperty;
|
||||||
|
@ -418,6 +417,14 @@ abstract public class Trade implements Tradable, Model, Serializable {
|
||||||
this.takeOfferDate = takeOfferDate;
|
this.takeOfferDate = takeOfferDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getTakeOfferDateAsBlockHeight() {
|
||||||
|
return takeOfferDateAsBlockHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTakeOfferDateAsBlockHeight(int blockHeight) {
|
||||||
|
takeOfferDateAsBlockHeight = blockHeight;
|
||||||
|
}
|
||||||
|
|
||||||
public void setTradingPeerNodeAddress(NodeAddress tradingPeerNodeAddress) {
|
public void setTradingPeerNodeAddress(NodeAddress tradingPeerNodeAddress) {
|
||||||
if (tradingPeerNodeAddress == null)
|
if (tradingPeerNodeAddress == null)
|
||||||
log.error("tradingPeerAddress=null");
|
log.error("tradingPeerAddress=null");
|
||||||
|
@ -536,24 +543,6 @@ abstract public class Trade implements Tradable, Model, Serializable {
|
||||||
this.takerPaymentAccountId = takerPaymentAccountId;
|
this.takerPaymentAccountId = takerPaymentAccountId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHalfTradePeriodReachedWarningDisplayed(boolean halfTradePeriodReachedWarningDisplayed) {
|
|
||||||
this.halfTradePeriodReachedWarningDisplayed = halfTradePeriodReachedWarningDisplayed;
|
|
||||||
persist();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isHalfTradePeriodReachedWarningDisplayed() {
|
|
||||||
return halfTradePeriodReachedWarningDisplayed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTradePeriodOverWarningDisplayed(boolean tradePeriodOverWarningDisplayed) {
|
|
||||||
this.tradePeriodOverWarningDisplayed = tradePeriodOverWarningDisplayed;
|
|
||||||
persist();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isTradePeriodOverWarningDisplayed() {
|
|
||||||
return tradePeriodOverWarningDisplayed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setContractHash(byte[] contractHash) {
|
public void setContractHash(byte[] contractHash) {
|
||||||
this.contractHash = contractHash;
|
this.contractHash = contractHash;
|
||||||
}
|
}
|
||||||
|
@ -638,8 +627,6 @@ abstract public class Trade implements Tradable, Model, Serializable {
|
||||||
"\n\tcheckPaymentTimeAsBlockHeight=" + checkPaymentTimeAsBlockHeight +
|
"\n\tcheckPaymentTimeAsBlockHeight=" + checkPaymentTimeAsBlockHeight +
|
||||||
"\n\tarbitratorNodeAddress=" + arbitratorNodeAddress +
|
"\n\tarbitratorNodeAddress=" + arbitratorNodeAddress +
|
||||||
"\n\ttakerPaymentAccountId='" + takerPaymentAccountId + '\'' +
|
"\n\ttakerPaymentAccountId='" + takerPaymentAccountId + '\'' +
|
||||||
"\n\thalfTradePeriodReachedWarningDisplayed=" + halfTradePeriodReachedWarningDisplayed +
|
|
||||||
"\n\ttradePeriodOverWarningDisplayed=" + tradePeriodOverWarningDisplayed +
|
|
||||||
"\n\terrorMessage='" + errorMessage + '\'' +
|
"\n\terrorMessage='" + errorMessage + '\'' +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
|
@ -281,6 +281,7 @@ public class TradeManager {
|
||||||
trade = new BuyerAsTakerTrade(offer, amount, model.getPeerNodeAddress(), tradableListStorage);
|
trade = new BuyerAsTakerTrade(offer, amount, model.getPeerNodeAddress(), tradableListStorage);
|
||||||
|
|
||||||
trade.setTakeOfferDate(new Date());
|
trade.setTakeOfferDate(new Date());
|
||||||
|
trade.setTakeOfferDateAsBlockHeight(tradeWalletService.getBestChainHeight());
|
||||||
trade.setTakerPaymentAccountId(paymentAccountId);
|
trade.setTakerPaymentAccountId(paymentAccountId);
|
||||||
|
|
||||||
initTrade(trade);
|
initTrade(trade);
|
||||||
|
@ -382,8 +383,11 @@ public class TradeManager {
|
||||||
return offer.isMyOffer(keyRing);
|
return offer.isMyOffer(keyRing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isMyOfferInBtcBuyerRole(Offer offer) {
|
||||||
|
return !(isMyOffer(offer) ^ offer.getDirection() == Offer.Direction.BUY);
|
||||||
|
}
|
||||||
|
|
||||||
public Optional<Trade> getTradeById(String tradeId) {
|
public Optional<Trade> getTradeById(String tradeId) {
|
||||||
return trades.stream().filter(e -> e.getId().equals(tradeId)).findFirst();
|
return trades.stream().filter(e -> e.getId().equals(tradeId)).findFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -133,10 +133,7 @@ public class BuyerAsOffererProtocol extends TradeProtocol implements BuyerProtoc
|
||||||
TradeTaskRunner taskRunner = new TradeTaskRunner(buyerAsOffererTrade,
|
TradeTaskRunner taskRunner = new TradeTaskRunner(buyerAsOffererTrade,
|
||||||
() -> handleTaskRunnerSuccess("handle DepositTxPublishedMessage"),
|
() -> handleTaskRunnerSuccess("handle DepositTxPublishedMessage"),
|
||||||
this::handleTaskRunnerFault);
|
this::handleTaskRunnerFault);
|
||||||
taskRunner.addTasks(
|
taskRunner.addTasks(ProcessDepositTxPublishedMessage.class);
|
||||||
ProcessDepositTxPublishedMessage.class,
|
|
||||||
AddDepositTxToWallet.class
|
|
||||||
);
|
|
||||||
taskRunner.run();
|
taskRunner.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -132,10 +132,7 @@ public class SellerAsOffererProtocol extends TradeProtocol implements SellerProt
|
||||||
() -> handleTaskRunnerSuccess("DepositTxPublishedMessage"),
|
() -> handleTaskRunnerSuccess("DepositTxPublishedMessage"),
|
||||||
this::handleTaskRunnerFault);
|
this::handleTaskRunnerFault);
|
||||||
|
|
||||||
taskRunner.addTasks(
|
taskRunner.addTasks(ProcessDepositTxPublishedMessage.class);
|
||||||
ProcessDepositTxPublishedMessage.class,
|
|
||||||
AddDepositTxToWallet.class
|
|
||||||
);
|
|
||||||
taskRunner.run();
|
taskRunner.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,7 @@ public class SignAndPublishDepositTxAsBuyer extends TradeTask {
|
||||||
|
|
||||||
trade.setDepositTx(transaction);
|
trade.setDepositTx(transaction);
|
||||||
trade.setTakeOfferDate(new Date());
|
trade.setTakeOfferDate(new Date());
|
||||||
|
trade.setTakeOfferDateAsBlockHeight(processModel.getTradeWalletService().getBestChainHeight());
|
||||||
trade.setState(Trade.State.DEPOSIT_PUBLISHED);
|
trade.setState(Trade.State.DEPOSIT_PUBLISHED);
|
||||||
|
|
||||||
complete();
|
complete();
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of Bitsquare.
|
|
||||||
*
|
|
||||||
* Bitsquare is free software: you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or (at
|
|
||||||
* your option) any later version.
|
|
||||||
*
|
|
||||||
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
|
||||||
* License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.bitsquare.trade.protocol.trade.tasks.offerer;
|
|
||||||
|
|
||||||
import io.bitsquare.common.taskrunner.TaskRunner;
|
|
||||||
import io.bitsquare.trade.Trade;
|
|
||||||
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
|
|
||||||
import org.bitcoinj.core.Transaction;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class AddDepositTxToWallet extends TradeTask {
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(AddDepositTxToWallet.class);
|
|
||||||
|
|
||||||
public AddDepositTxToWallet(TaskRunner taskHandler, Trade trade) {
|
|
||||||
super(taskHandler, trade);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void run() {
|
|
||||||
try {
|
|
||||||
runInterceptHook();
|
|
||||||
// To access tx confidence we need to add that tx into our wallet.
|
|
||||||
Transaction depositTx = processModel.getTradeWalletService().addTransactionToWallet(trade.getDepositTx());
|
|
||||||
// update with full tx
|
|
||||||
trade.setDepositTx(depositTx);
|
|
||||||
|
|
||||||
complete();
|
|
||||||
} catch (Throwable t) {
|
|
||||||
failed(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -22,6 +22,7 @@ import io.bitsquare.trade.OffererTrade;
|
||||||
import io.bitsquare.trade.Trade;
|
import io.bitsquare.trade.Trade;
|
||||||
import io.bitsquare.trade.protocol.trade.messages.DepositTxPublishedMessage;
|
import io.bitsquare.trade.protocol.trade.messages.DepositTxPublishedMessage;
|
||||||
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
|
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
|
||||||
|
import org.bitcoinj.core.Transaction;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -47,9 +48,15 @@ public class ProcessDepositTxPublishedMessage extends TradeTask {
|
||||||
checkTradeId(processModel.getId(), message);
|
checkTradeId(processModel.getId(), message);
|
||||||
checkNotNull(message);
|
checkNotNull(message);
|
||||||
checkArgument(message.depositTx != null);
|
checkArgument(message.depositTx != null);
|
||||||
trade.setDepositTx(processModel.getWalletService().getTransactionFromSerializedTx(message.depositTx));
|
|
||||||
|
// To access tx confidence we need to add that tx into our wallet.
|
||||||
|
Transaction transactionFromSerializedTx = processModel.getWalletService().getTransactionFromSerializedTx(message.depositTx);
|
||||||
|
// update with full tx
|
||||||
|
trade.setDepositTx(processModel.getTradeWalletService().addTransactionToWallet(transactionFromSerializedTx));
|
||||||
|
|
||||||
trade.setState(Trade.State.DEPOSIT_PUBLISHED_MSG_RECEIVED);
|
trade.setState(Trade.State.DEPOSIT_PUBLISHED_MSG_RECEIVED);
|
||||||
trade.setTakeOfferDate(new Date());
|
trade.setTakeOfferDate(new Date());
|
||||||
|
trade.setTakeOfferDateAsBlockHeight(processModel.getTradeWalletService().getBestChainHeight());
|
||||||
|
|
||||||
if (trade instanceof OffererTrade)
|
if (trade instanceof OffererTrade)
|
||||||
processModel.getOpenOfferManager().closeOpenOffer(trade.getOffer());
|
processModel.getOpenOfferManager().closeOpenOffer(trade.getOffer());
|
||||||
|
|
|
@ -63,6 +63,7 @@ public class SignAndPublishDepositTxAsSeller extends TradeTask {
|
||||||
|
|
||||||
trade.setDepositTx(transaction);
|
trade.setDepositTx(transaction);
|
||||||
trade.setTakeOfferDate(new Date());
|
trade.setTakeOfferDate(new Date());
|
||||||
|
trade.setTakeOfferDateAsBlockHeight(processModel.getTradeWalletService().getBestChainHeight());
|
||||||
trade.setState(Trade.State.DEPOSIT_PUBLISHED);
|
trade.setState(Trade.State.DEPOSIT_PUBLISHED);
|
||||||
|
|
||||||
complete();
|
complete();
|
||||||
|
|
|
@ -21,6 +21,8 @@ import io.bitsquare.app.BitsquareEnvironment;
|
||||||
import io.bitsquare.app.Version;
|
import io.bitsquare.app.Version;
|
||||||
import io.bitsquare.btc.BitcoinNetwork;
|
import io.bitsquare.btc.BitcoinNetwork;
|
||||||
import io.bitsquare.btc.FeePolicy;
|
import io.bitsquare.btc.FeePolicy;
|
||||||
|
import io.bitsquare.btc.http.BlockchainApiProvider;
|
||||||
|
import io.bitsquare.btc.http.BlockrIOProvider;
|
||||||
import io.bitsquare.locale.CountryUtil;
|
import io.bitsquare.locale.CountryUtil;
|
||||||
import io.bitsquare.locale.CurrencyUtil;
|
import io.bitsquare.locale.CurrencyUtil;
|
||||||
import io.bitsquare.locale.TradeCurrency;
|
import io.bitsquare.locale.TradeCurrency;
|
||||||
|
@ -65,12 +67,15 @@ public class Preferences implements Serializable {
|
||||||
new BlockChainExplorer("Blockr.io", "https://btc.blockr.io/tx/info/", "https://btc.blockr.io/address/info/"),
|
new BlockChainExplorer("Blockr.io", "https://btc.blockr.io/tx/info/", "https://btc.blockr.io/address/info/"),
|
||||||
new BlockChainExplorer("Biteasy", "https://www.biteasy.com/transactions/", "https://www.biteasy.com/addresses/")
|
new BlockChainExplorer("Biteasy", "https://www.biteasy.com/transactions/", "https://www.biteasy.com/addresses/")
|
||||||
));
|
));
|
||||||
|
private BlockchainApiProvider blockchainApiProvider;
|
||||||
|
|
||||||
public static List<String> getBtcDenominations() {
|
public static List<String> getBtcDenominations() {
|
||||||
return BTC_DENOMINATIONS;
|
return BTC_DENOMINATIONS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Locale defaultLocale = Locale.getDefault();
|
private static Locale defaultLocale = Locale.getDefault();
|
||||||
|
//TODO test with other locales
|
||||||
|
//private static Locale defaultLocale = Locale.US;
|
||||||
|
|
||||||
public static Locale getDefaultLocale() {
|
public static Locale getDefaultLocale() {
|
||||||
return defaultLocale;
|
return defaultLocale;
|
||||||
|
@ -91,7 +96,6 @@ public class Preferences implements Serializable {
|
||||||
private String btcDenomination = MonetaryFormat.CODE_BTC;
|
private String btcDenomination = MonetaryFormat.CODE_BTC;
|
||||||
private boolean useAnimations = true;
|
private boolean useAnimations = true;
|
||||||
private boolean useEffects = true;
|
private boolean useEffects = true;
|
||||||
private boolean displaySecurityDepositInfo = true;
|
|
||||||
private final ArrayList<TradeCurrency> tradeCurrencies;
|
private final ArrayList<TradeCurrency> tradeCurrencies;
|
||||||
private BlockChainExplorer blockChainExplorerMainNet;
|
private BlockChainExplorer blockChainExplorerMainNet;
|
||||||
private BlockChainExplorer blockChainExplorerTestNet;
|
private BlockChainExplorer blockChainExplorerTestNet;
|
||||||
|
@ -130,7 +134,6 @@ public class Preferences implements Serializable {
|
||||||
setUseEffects(persisted.useEffects);
|
setUseEffects(persisted.useEffects);
|
||||||
setTradeCurrencies(persisted.tradeCurrencies);
|
setTradeCurrencies(persisted.tradeCurrencies);
|
||||||
tradeCurrencies = new ArrayList<>(tradeCurrenciesAsObservable);
|
tradeCurrencies = new ArrayList<>(tradeCurrenciesAsObservable);
|
||||||
displaySecurityDepositInfo = persisted.getDisplaySecurityDepositInfo();
|
|
||||||
|
|
||||||
setBlockChainExplorerTestNet(persisted.getBlockChainExplorerTestNet());
|
setBlockChainExplorerTestNet(persisted.getBlockChainExplorerTestNet());
|
||||||
setBlockChainExplorerMainNet(persisted.getBlockChainExplorerMainNet());
|
setBlockChainExplorerMainNet(persisted.getBlockChainExplorerMainNet());
|
||||||
|
@ -153,6 +156,8 @@ public class Preferences implements Serializable {
|
||||||
defaultTradeCurrency = preferredTradeCurrency;
|
defaultTradeCurrency = preferredTradeCurrency;
|
||||||
useTorForBitcoinJ = persisted.getUseTorForBitcoinJ();
|
useTorForBitcoinJ = persisted.getUseTorForBitcoinJ();
|
||||||
|
|
||||||
|
blockchainApiProvider = persisted.getBlockchainApiProvider();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setTxFeePerKB(persisted.getTxFeePerKB());
|
setTxFeePerKB(persisted.getTxFeePerKB());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -175,6 +180,8 @@ public class Preferences implements Serializable {
|
||||||
preferredLocale = getDefaultLocale();
|
preferredLocale = getDefaultLocale();
|
||||||
preferredTradeCurrency = getDefaultTradeCurrency();
|
preferredTradeCurrency = getDefaultTradeCurrency();
|
||||||
|
|
||||||
|
blockchainApiProvider = new BlockrIOProvider();
|
||||||
|
|
||||||
storage.queueUpForSave();
|
storage.queueUpForSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,11 +230,6 @@ public class Preferences implements Serializable {
|
||||||
this.useEffectsProperty.set(useEffectsProperty);
|
this.useEffectsProperty.set(useEffectsProperty);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDisplaySecurityDepositInfo(boolean displaySecurityDepositInfo) {
|
|
||||||
this.displaySecurityDepositInfo = displaySecurityDepositInfo;
|
|
||||||
storage.queueUpForSave(2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBitcoinNetwork(BitcoinNetwork bitcoinNetwork) {
|
public void setBitcoinNetwork(BitcoinNetwork bitcoinNetwork) {
|
||||||
if (this.bitcoinNetwork != bitcoinNetwork)
|
if (this.bitcoinNetwork != bitcoinNetwork)
|
||||||
bitsquareEnvironment.saveBitcoinNetwork(bitcoinNetwork);
|
bitsquareEnvironment.saveBitcoinNetwork(bitcoinNetwork);
|
||||||
|
@ -302,6 +304,10 @@ public class Preferences implements Serializable {
|
||||||
storage.queueUpForSave();
|
storage.queueUpForSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setBlockchainApiProvider(BlockchainApiProvider blockchainApiProvider) {
|
||||||
|
this.blockchainApiProvider = blockchainApiProvider;
|
||||||
|
storage.queueUpForSave();
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Getter
|
// Getter
|
||||||
|
@ -319,10 +325,6 @@ public class Preferences implements Serializable {
|
||||||
return useAnimationsProperty.get();
|
return useAnimationsProperty.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getDisplaySecurityDepositInfo() {
|
|
||||||
return displaySecurityDepositInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public StringProperty btcDenominationProperty() {
|
public StringProperty btcDenominationProperty() {
|
||||||
return btcDenominationProperty;
|
return btcDenominationProperty;
|
||||||
}
|
}
|
||||||
|
@ -425,4 +427,9 @@ public class Preferences implements Serializable {
|
||||||
public boolean getUseTorForBitcoinJ() {
|
public boolean getUseTorForBitcoinJ() {
|
||||||
return useTorForBitcoinJ;
|
return useTorForBitcoinJ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BlockchainApiProvider getBlockchainApiProvider() {
|
||||||
|
return blockchainApiProvider;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ import static io.bitsquare.app.BitsquareEnvironment.APP_NAME_KEY;
|
||||||
public class BitsquareApp extends Application {
|
public class BitsquareApp extends Application {
|
||||||
private static final Logger log = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(BitsquareApp.class);
|
private static final Logger log = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(BitsquareApp.class);
|
||||||
|
|
||||||
public static final boolean DEV_MODE = true;
|
public static final boolean DEV_MODE = false;
|
||||||
public static final boolean IS_RELEASE_VERSION = !DEV_MODE && true;
|
public static final boolean IS_RELEASE_VERSION = !DEV_MODE && true;
|
||||||
|
|
||||||
private static Environment env;
|
private static Environment env;
|
||||||
|
|
|
@ -585,12 +585,14 @@ textfield */
|
||||||
-fx-text-fill: -bs-grey;
|
-fx-text-fill: -bs-grey;
|
||||||
-fx-body-color: linear-gradient(to bottom, -bs-content-bg-grey, #F0F0F0);
|
-fx-body-color: linear-gradient(to bottom, -bs-content-bg-grey, #F0F0F0);
|
||||||
-fx-outer-border: linear-gradient(to bottom, -bs-bg-grey, #ccc);
|
-fx-outer-border: linear-gradient(to bottom, -bs-bg-grey, #ccc);
|
||||||
|
/* -fx-body-color: #F0F0F0;
|
||||||
|
-fx-outer-border: #ccc;*/
|
||||||
-fx-background-color: -fx-shadow-highlight-color,
|
-fx-background-color: -fx-shadow-highlight-color,
|
||||||
-fx-outer-border,
|
-fx-outer-border,
|
||||||
-fx-inner-border,
|
-fx-inner-border,
|
||||||
-fx-body-color;
|
-fx-body-color;
|
||||||
-fx-background-insets: 0 0 -1 0, 0, 1, 2;
|
-fx-background-insets: 0 0 -1 0, 0, 1, 2;
|
||||||
-fx-background-radius: 3px, 3px, 2px, 1px;
|
-fx-background-radius: 1px, 1px, 1px, 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#trade-wizard-item-background-active {
|
#trade-wizard-item-background-active {
|
||||||
|
@ -598,23 +600,27 @@ textfield */
|
||||||
-fx-font-size: 14;
|
-fx-font-size: 14;
|
||||||
-fx-body-color: linear-gradient(to bottom, #f1f6f7, #e7f5f9);
|
-fx-body-color: linear-gradient(to bottom, #f1f6f7, #e7f5f9);
|
||||||
-fx-outer-border: linear-gradient(to bottom, #b5e1ef, #6aa4b6);
|
-fx-outer-border: linear-gradient(to bottom, #b5e1ef, #6aa4b6);
|
||||||
|
/* -fx-body-color: #e7f5f9;
|
||||||
|
-fx-outer-border: #6aa4b6;*/
|
||||||
-fx-background-color: -fx-shadow-highlight-color,
|
-fx-background-color: -fx-shadow-highlight-color,
|
||||||
-fx-outer-border,
|
-fx-outer-border,
|
||||||
-fx-inner-border,
|
-fx-inner-border,
|
||||||
-fx-body-color;
|
-fx-body-color;
|
||||||
-fx-background-insets: 0 0 -1 0, 0, 1, 2;
|
-fx-background-insets: 0 0 -1 0, 0, 1, 2;
|
||||||
-fx-background-radius: 3px, 3px, 2px, 1px;
|
-fx-background-radius: 1px, 1px, 1px, 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#trade-wizard-item-background-completed {
|
#trade-wizard-item-background-completed {
|
||||||
-fx-body-color: linear-gradient(to bottom, -bs-content-bg-grey, #E1E9E1);
|
-fx-body-color: linear-gradient(to bottom, -bs-content-bg-grey, #E1E9E1);
|
||||||
-fx-outer-border: linear-gradient(to bottom, #99ba9c, #619865);
|
-fx-outer-border: linear-gradient(to bottom, #99ba9c, #619865);
|
||||||
|
/* -fx-body-color: #def6df;
|
||||||
|
-fx-outer-border: #7db581;*/
|
||||||
-fx-background-color: -fx-shadow-highlight-color,
|
-fx-background-color: -fx-shadow-highlight-color,
|
||||||
-fx-outer-border,
|
-fx-outer-border,
|
||||||
-fx-inner-border,
|
-fx-inner-border,
|
||||||
-fx-body-color;
|
-fx-body-color;
|
||||||
-fx-background-insets: 0 0 -1 0, 0, 1, 2;
|
-fx-background-insets: 0 0 -1 0, 0, 1, 2;
|
||||||
-fx-background-radius: 3px, 3px, 2px, 1px;
|
-fx-background-radius: 1px, 1px, 1px, 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#open-support-button {
|
#open-support-button {
|
||||||
|
|
|
@ -30,7 +30,6 @@ public class HyperlinkWithIcon extends HBox {
|
||||||
|
|
||||||
icon = new Label();
|
icon = new Label();
|
||||||
icon.getStyleClass().add("external-link-icon");
|
icon.getStyleClass().add("external-link-icon");
|
||||||
|
|
||||||
AwesomeDude.setIcon(icon, awesomeIcon);
|
AwesomeDude.setIcon(icon, awesomeIcon);
|
||||||
icon.setMinWidth(20);
|
icon.setMinWidth(20);
|
||||||
icon.setOpacity(0.7);
|
icon.setOpacity(0.7);
|
||||||
|
|
|
@ -23,7 +23,6 @@ import io.bitsquare.common.UserThread;
|
||||||
import io.bitsquare.common.util.Tuple2;
|
import io.bitsquare.common.util.Tuple2;
|
||||||
import io.bitsquare.gui.Navigation;
|
import io.bitsquare.gui.Navigation;
|
||||||
import io.bitsquare.gui.common.view.*;
|
import io.bitsquare.gui.common.view.*;
|
||||||
import io.bitsquare.gui.components.SystemNotification;
|
|
||||||
import io.bitsquare.gui.main.account.AccountView;
|
import io.bitsquare.gui.main.account.AccountView;
|
||||||
import io.bitsquare.gui.main.disputes.DisputesView;
|
import io.bitsquare.gui.main.disputes.DisputesView;
|
||||||
import io.bitsquare.gui.main.funds.FundsView;
|
import io.bitsquare.gui.main.funds.FundsView;
|
||||||
|
@ -454,10 +453,10 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
||||||
notification.visibleProperty().bind(model.showPendingTradesNotification);
|
notification.visibleProperty().bind(model.showPendingTradesNotification);
|
||||||
buttonHolder.getChildren().add(notification);
|
buttonHolder.getChildren().add(notification);
|
||||||
|
|
||||||
model.showPendingTradesNotification.addListener((ov, oldValue, newValue) -> {
|
/* model.showPendingTradesNotification.addListener((ov, oldValue, newValue) -> {
|
||||||
if (newValue)
|
if (newValue)
|
||||||
SystemNotification.openInfoNotification(title, "You received a new trade message.");
|
SystemNotification.openInfoNotification(title, "You received a new trade message.");
|
||||||
});
|
});*/
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupDisputesIcon(Pane buttonHolder) {
|
private void setupDisputesIcon(Pane buttonHolder) {
|
||||||
|
@ -478,10 +477,10 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
||||||
notification.visibleProperty().bind(model.showOpenDisputesNotification);
|
notification.visibleProperty().bind(model.showOpenDisputesNotification);
|
||||||
buttonHolder.getChildren().add(notification);
|
buttonHolder.getChildren().add(notification);
|
||||||
|
|
||||||
model.showOpenDisputesNotification.addListener((ov, oldValue, newValue) -> {
|
/* model.showOpenDisputesNotification.addListener((ov, oldValue, newValue) -> {
|
||||||
if (newValue)
|
if (newValue)
|
||||||
SystemNotification.openInfoNotification(title, "You received a dispute message.");
|
SystemNotification.openInfoNotification(title, "You received a dispute message.");
|
||||||
});
|
});*/
|
||||||
}
|
}
|
||||||
|
|
||||||
private class NavButton extends ToggleButton {
|
private class NavButton extends ToggleButton {
|
||||||
|
|
|
@ -29,10 +29,14 @@ import io.bitsquare.arbitration.DisputeManager;
|
||||||
import io.bitsquare.btc.*;
|
import io.bitsquare.btc.*;
|
||||||
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.Navigation;
|
||||||
import io.bitsquare.gui.common.model.ViewModel;
|
import io.bitsquare.gui.common.model.ViewModel;
|
||||||
|
import io.bitsquare.gui.common.view.ViewPath;
|
||||||
import io.bitsquare.gui.components.BalanceTextField;
|
import io.bitsquare.gui.components.BalanceTextField;
|
||||||
import io.bitsquare.gui.components.BalanceWithConfirmationTextField;
|
import io.bitsquare.gui.components.BalanceWithConfirmationTextField;
|
||||||
import io.bitsquare.gui.components.TxIdTextField;
|
import io.bitsquare.gui.components.TxIdTextField;
|
||||||
|
import io.bitsquare.gui.main.portfolio.PortfolioView;
|
||||||
|
import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesView;
|
||||||
import io.bitsquare.gui.popups.DisplayAlertMessagePopup;
|
import io.bitsquare.gui.popups.DisplayAlertMessagePopup;
|
||||||
import io.bitsquare.gui.popups.Popup;
|
import io.bitsquare.gui.popups.Popup;
|
||||||
import io.bitsquare.gui.popups.WalletPasswordPopup;
|
import io.bitsquare.gui.popups.WalletPasswordPopup;
|
||||||
|
@ -57,6 +61,7 @@ import javafx.collections.ListChangeListener;
|
||||||
import org.bitcoinj.core.*;
|
import org.bitcoinj.core.*;
|
||||||
import org.bitcoinj.store.BlockStoreException;
|
import org.bitcoinj.store.BlockStoreException;
|
||||||
import org.fxmisc.easybind.EasyBind;
|
import org.fxmisc.easybind.EasyBind;
|
||||||
|
import org.fxmisc.easybind.Subscription;
|
||||||
import org.fxmisc.easybind.monadic.MonadicBinding;
|
import org.fxmisc.easybind.monadic.MonadicBinding;
|
||||||
import org.reactfx.util.FxTimer;
|
import org.reactfx.util.FxTimer;
|
||||||
import org.reactfx.util.Timer;
|
import org.reactfx.util.Timer;
|
||||||
|
@ -85,6 +90,7 @@ public class MainViewModel implements ViewModel {
|
||||||
private final Preferences preferences;
|
private final Preferences preferences;
|
||||||
private final AlertManager alertManager;
|
private final AlertManager alertManager;
|
||||||
private final WalletPasswordPopup walletPasswordPopup;
|
private final WalletPasswordPopup walletPasswordPopup;
|
||||||
|
private Navigation navigation;
|
||||||
private final BSFormatter formatter;
|
private final BSFormatter formatter;
|
||||||
|
|
||||||
// BTC network
|
// BTC network
|
||||||
|
@ -135,7 +141,7 @@ public class MainViewModel implements ViewModel {
|
||||||
ArbitratorManager arbitratorManager, P2PService p2PService, TradeManager tradeManager,
|
ArbitratorManager arbitratorManager, P2PService p2PService, TradeManager tradeManager,
|
||||||
OpenOfferManager openOfferManager, DisputeManager disputeManager, Preferences preferences,
|
OpenOfferManager openOfferManager, DisputeManager disputeManager, Preferences preferences,
|
||||||
User user, AlertManager alertManager, WalletPasswordPopup walletPasswordPopup,
|
User user, AlertManager alertManager, WalletPasswordPopup walletPasswordPopup,
|
||||||
BSFormatter formatter) {
|
Navigation navigation, BSFormatter formatter) {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.walletService = walletService;
|
this.walletService = walletService;
|
||||||
this.tradeWalletService = tradeWalletService;
|
this.tradeWalletService = tradeWalletService;
|
||||||
|
@ -147,6 +153,7 @@ public class MainViewModel implements ViewModel {
|
||||||
this.preferences = preferences;
|
this.preferences = preferences;
|
||||||
this.alertManager = alertManager;
|
this.alertManager = alertManager;
|
||||||
this.walletPasswordPopup = walletPasswordPopup;
|
this.walletPasswordPopup = walletPasswordPopup;
|
||||||
|
this.navigation = navigation;
|
||||||
this.formatter = formatter;
|
this.formatter = formatter;
|
||||||
|
|
||||||
btcNetworkAsString = formatter.formatBitcoinNetwork(preferences.getBitcoinNetwork()) +
|
btcNetworkAsString = formatter.formatBitcoinNetwork(preferences.getBitcoinNetwork()) +
|
||||||
|
@ -362,10 +369,12 @@ public class MainViewModel implements ViewModel {
|
||||||
tradeManager.getTrades().addListener((ListChangeListener<Trade>) change -> {
|
tradeManager.getTrades().addListener((ListChangeListener<Trade>) change -> {
|
||||||
change.next();
|
change.next();
|
||||||
addDisputeStateListeners(change.getAddedSubList());
|
addDisputeStateListeners(change.getAddedSubList());
|
||||||
|
addTradeStateListeners(change.getAddedSubList());
|
||||||
pendingTradesChanged();
|
pendingTradesChanged();
|
||||||
});
|
});
|
||||||
pendingTradesChanged();
|
pendingTradesChanged();
|
||||||
addDisputeStateListeners(tradeManager.getTrades());
|
addDisputeStateListeners(tradeManager.getTrades());
|
||||||
|
addTradeStateListeners(tradeManager.getTrades());
|
||||||
|
|
||||||
|
|
||||||
// arbitratorManager
|
// arbitratorManager
|
||||||
|
@ -653,25 +662,25 @@ public class MainViewModel implements ViewModel {
|
||||||
case HALF_REACHED:
|
case HALF_REACHED:
|
||||||
id = "displayHalfTradePeriodOver" + trade.getId();
|
id = "displayHalfTradePeriodOver" + trade.getId();
|
||||||
if (preferences.showAgain(id)) {
|
if (preferences.showAgain(id)) {
|
||||||
|
preferences.dontShowAgain(id);
|
||||||
new Popup().warning("Your trade with ID " + trade.getShortId() +
|
new Popup().warning("Your trade with ID " + trade.getShortId() +
|
||||||
" has reached the half of the max. allowed trading period and " +
|
" has reached the half of the max. allowed trading period and " +
|
||||||
"is still not completed.\n\n" +
|
"is still not completed.\n\n" +
|
||||||
"The trade period ends on " + limitDate + "\n\n" +
|
"The trade period ends on " + limitDate + "\n\n" +
|
||||||
"Please check your trade state at \"Portfolio/Open trades\" for further information.")
|
"Please check your trade state at \"Portfolio/Open trades\" for further information.")
|
||||||
.onClose(() -> preferences.dontShowAgain(id))
|
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TRADE_PERIOD_OVER:
|
case TRADE_PERIOD_OVER:
|
||||||
id = "displayTradePeriodOver" + trade.getId();
|
id = "displayTradePeriodOver" + trade.getId();
|
||||||
if (preferences.showAgain(id)) {
|
if (preferences.showAgain(id)) {
|
||||||
|
preferences.dontShowAgain(id);
|
||||||
new Popup().warning("Your trade with ID " + trade.getShortId() +
|
new Popup().warning("Your trade with ID " + trade.getShortId() +
|
||||||
" has reached the max. allowed trading period and is " +
|
" has reached the max. allowed trading period and is " +
|
||||||
"not completed.\n\n" +
|
"not completed.\n\n" +
|
||||||
"The trade period ended on " + limitDate + "\n\n" +
|
"The trade period ended on " + limitDate + "\n\n" +
|
||||||
"Please check your trade at \"Portfolio/Open trades\" for contacting " +
|
"Please check your trade at \"Portfolio/Open trades\" for contacting " +
|
||||||
"the arbitrator.")
|
"the arbitrator.")
|
||||||
.onClose(() -> preferences.dontShowAgain(id))
|
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -706,6 +715,142 @@ public class MainViewModel implements ViewModel {
|
||||||
showPendingTradesNotification.set(numPendingTrades > 0);
|
showPendingTradesNotification.set(numPendingTrades > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addTradeStateListeners(List<? extends Trade> addedTrades) {
|
||||||
|
addedTrades.stream().forEach(trade -> {
|
||||||
|
Subscription tradeStateSubscription = EasyBind.subscribe(trade.stateProperty(), newValue -> {
|
||||||
|
if (newValue != null) {
|
||||||
|
applyState(trade);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* addedTrades.stream()
|
||||||
|
.forEach(trade -> trade.stateProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
String msg = "";
|
||||||
|
log.debug("addTradeStateListeners " + newValue);
|
||||||
|
switch (newValue) {
|
||||||
|
case PREPARATION:
|
||||||
|
case TAKER_FEE_PAID:
|
||||||
|
case DEPOSIT_PUBLISH_REQUESTED:
|
||||||
|
case DEPOSIT_PUBLISHED:
|
||||||
|
case DEPOSIT_SEEN_IN_NETWORK:
|
||||||
|
case DEPOSIT_PUBLISHED_MSG_SENT:
|
||||||
|
case DEPOSIT_PUBLISHED_MSG_RECEIVED:
|
||||||
|
break;
|
||||||
|
case DEPOSIT_CONFIRMED:
|
||||||
|
msg = newValue.name();
|
||||||
|
break;
|
||||||
|
case FIAT_PAYMENT_STARTED:
|
||||||
|
break;
|
||||||
|
case FIAT_PAYMENT_STARTED_MSG_SENT:
|
||||||
|
break;
|
||||||
|
case FIAT_PAYMENT_STARTED_MSG_RECEIVED:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FIAT_PAYMENT_RECEIPT:
|
||||||
|
break;
|
||||||
|
case FIAT_PAYMENT_RECEIPT_MSG_SENT:
|
||||||
|
break;
|
||||||
|
case FIAT_PAYMENT_RECEIPT_MSG_RECEIVED:
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case PAYOUT_TX_SENT:
|
||||||
|
break;
|
||||||
|
case PAYOUT_TX_RECEIVED:
|
||||||
|
break;
|
||||||
|
case PAYOUT_TX_COMMITTED:
|
||||||
|
break;
|
||||||
|
case PAYOUT_BROAD_CASTED:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WITHDRAW_COMPLETED:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
log.warn("unhandled processState " + newValue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//new Popup().information(msg).show();
|
||||||
|
|
||||||
|
}));*/
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyState(Trade trade) {
|
||||||
|
Trade.State state = trade.getState();
|
||||||
|
log.debug("addTradeStateListeners " + state);
|
||||||
|
boolean isBtcBuyer = tradeManager.isMyOfferInBtcBuyerRole(trade.getOffer());
|
||||||
|
String headLine = "Notification for trade with ID " + trade.getShortId();
|
||||||
|
String message = null;
|
||||||
|
String id = "notificationPopup_" + state + trade.getId();
|
||||||
|
if (isBtcBuyer) {
|
||||||
|
switch (state) {
|
||||||
|
case DEPOSIT_PUBLISHED_MSG_RECEIVED:
|
||||||
|
message = "Your offer has been accepted by a seller.\n" +
|
||||||
|
"You need to wait for one blockchain confirmation before starting the payment.";
|
||||||
|
break;
|
||||||
|
case DEPOSIT_CONFIRMED:
|
||||||
|
message = "The deposit transaction of your trade has got the first blockchain confirmation.\n" +
|
||||||
|
"You have to start the payment to the bitcoin seller now.";
|
||||||
|
break;
|
||||||
|
/* case FIAT_PAYMENT_RECEIPT_MSG_RECEIVED:
|
||||||
|
case PAYOUT_TX_COMMITTED:
|
||||||
|
case PAYOUT_TX_SENT:*/
|
||||||
|
case PAYOUT_BROAD_CASTED:
|
||||||
|
message = "The bitcoin seller has confirmed the receipt of your payment and the payout transaction has been published.\n" +
|
||||||
|
"The trade is now completed and you can withdraw your funds.";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (state) {
|
||||||
|
case DEPOSIT_PUBLISHED_MSG_RECEIVED:
|
||||||
|
message = "Your offer has been accepted by a buyer.\n" +
|
||||||
|
"You need to wait for one blockchain confirmation before starting the payment.";
|
||||||
|
break;
|
||||||
|
case FIAT_PAYMENT_STARTED_MSG_RECEIVED:
|
||||||
|
message = "The bitcoin buyer has started the payment.\n" +
|
||||||
|
"Please check your payment account if you have received his payment.";
|
||||||
|
break;
|
||||||
|
/* case FIAT_PAYMENT_RECEIPT_MSG_SENT:
|
||||||
|
case PAYOUT_TX_RECEIVED:
|
||||||
|
case PAYOUT_TX_COMMITTED:*/
|
||||||
|
case PAYOUT_BROAD_CASTED:
|
||||||
|
message = "The payout transaction has been published.\n" +
|
||||||
|
"The trade is now completed and you can withdraw your funds.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewPath currentPath = navigation.getCurrentPath();
|
||||||
|
boolean isPendingTradesViewCurrentView = currentPath != null &&
|
||||||
|
currentPath.size() == 3 &&
|
||||||
|
currentPath.get(2).equals(PendingTradesView.class);
|
||||||
|
if (message != null) {
|
||||||
|
//TODO we get that called initially before the navigation is inited
|
||||||
|
if (isPendingTradesViewCurrentView || currentPath == null) {
|
||||||
|
if (preferences.showAgain(id))
|
||||||
|
new Popup().headLine(headLine)
|
||||||
|
.message(message)
|
||||||
|
.show();
|
||||||
|
preferences.dontShowAgain(id);
|
||||||
|
} else {
|
||||||
|
if (preferences.showAgain(id))
|
||||||
|
new Popup().headLine(headLine)
|
||||||
|
.message(message)
|
||||||
|
.actionButtonText("Go to \"Portfolio/Open trades\"")
|
||||||
|
.onAction(() -> {
|
||||||
|
FxTimer.runLater(Duration.ofMillis(100),
|
||||||
|
() -> navigation.navigateTo(MainView.class, PortfolioView.class, PendingTradesView.class)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.show();
|
||||||
|
preferences.dontShowAgain(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void addDisputeStateListeners(List<? extends Trade> addedTrades) {
|
private void addDisputeStateListeners(List<? extends Trade> addedTrades) {
|
||||||
addedTrades.stream().forEach(trade -> trade.disputeStateProperty().addListener((observable, oldValue, newValue) -> {
|
addedTrades.stream().forEach(trade -> trade.disputeStateProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
switch (newValue) {
|
switch (newValue) {
|
||||||
|
|
|
@ -89,7 +89,7 @@ public class FundsView extends ActivatableViewAndModel<TabPane, Activatable> {
|
||||||
String text = "Bitsquare does not use a single application wallet, but dedicated wallets for every trade.\n" +
|
String text = "Bitsquare does not use a single application wallet, but dedicated wallets for every trade.\n" +
|
||||||
"Funding of the wallet will be done when needed, for instance when you create or take an offer.\n" +
|
"Funding of the wallet will be done when needed, for instance when you create or take an offer.\n" +
|
||||||
"Withdrawing funds can be done after a trade is completed.\n" +
|
"Withdrawing funds can be done after a trade is completed.\n" +
|
||||||
"Dedicated wallets help protect user privacy and prevent leaking information of previous trades to other\n" +
|
"Dedicated wallets help protect user privacy and prevent leaking information of previous trades to other" +
|
||||||
"traders.\n\n" +
|
"traders.\n\n" +
|
||||||
"For more background information please see the Bitsquare FAQ on our web page.";
|
"For more background information please see the Bitsquare FAQ on our web page.";
|
||||||
if (preferences.showAgain(key) && !BitsquareApp.DEV_MODE)
|
if (preferences.showAgain(key) && !BitsquareApp.DEV_MODE)
|
||||||
|
|
|
@ -346,7 +346,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||||
withdrawToTextField.setPromptText("Fill in your destination address");
|
withdrawToTextField.setPromptText("Fill in your destination address");
|
||||||
|
|
||||||
if (BitsquareApp.DEV_MODE)
|
if (BitsquareApp.DEV_MODE)
|
||||||
withdrawToTextField.setText("mxAkWWaQBqwqcYstKzqLku3kzR6pbu2zHq");
|
withdrawToTextField.setText("mhpVDvMjJT1Gn7da44dkq1HXd3wXdFZpXu");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<Tradable> getTradable(WithdrawalListItem item) {
|
private Optional<Tradable> getTradable(WithdrawalListItem item) {
|
||||||
|
|
|
@ -33,12 +33,12 @@ public class BuyOfferView extends OfferView {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getCreateOfferTabName() {
|
protected String getCreateOfferTabName() {
|
||||||
return "Create offer for buying bitcoin";
|
return "Create offer";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getTakeOfferTabName() {
|
protected String getTakeOfferTabName() {
|
||||||
return "Take offer for buying bitcoin";
|
return "Take offer";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,12 +33,12 @@ public class SellOfferView extends OfferView {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getCreateOfferTabName() {
|
protected String getCreateOfferTabName() {
|
||||||
return "Create offer for selling bitcoin";
|
return "Create offer";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getTakeOfferTabName() {
|
protected String getTakeOfferTabName() {
|
||||||
return "Take offer for selling bitcoin";
|
return "Take offer";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -165,11 +165,8 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||||
|
|
||||||
boolean isFeeFromFundingTxSufficient() {
|
boolean isFeeFromFundingTxSufficient() {
|
||||||
// if fee was never set because of api provider not available we check with default value and return true
|
// if fee was never set because of api provider not available we check with default value and return true
|
||||||
log.debug("FeePolicy.getFeePerKb() " + FeePolicy.getFeePerKb());
|
|
||||||
log.debug("feeFromFundingTxProperty " + feeFromFundingTxProperty);
|
|
||||||
log.debug(">? " + (feeFromFundingTxProperty.get().compareTo(FeePolicy.getFeePerKb()) >= 0));
|
|
||||||
return feeFromFundingTxProperty.get().equals(Coin.NEGATIVE_SATOSHI) ||
|
return feeFromFundingTxProperty.get().equals(Coin.NEGATIVE_SATOSHI) ||
|
||||||
feeFromFundingTxProperty.get().compareTo(FeePolicy.getFeePerKb()) >= 0;
|
feeFromFundingTxProperty.get().compareTo(FeePolicy.getMinFundingFee()) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addListeners() {
|
private void addListeners() {
|
||||||
|
@ -177,7 +174,7 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||||
walletService.getWallet().addEventListener(new WalletEventListener() {
|
walletService.getWallet().addEventListener(new WalletEventListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
||||||
requestFee(tx.getHashAsString());
|
requestFeeFromBlockchain(tx.getHashAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -207,7 +204,7 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||||
user.getPaymentAccountsAsObservable().addListener(paymentAccountsChangeListener);
|
user.getPaymentAccountsAsObservable().addListener(paymentAccountsChangeListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void requestFee(String transactionId) {
|
private void requestFeeFromBlockchain(String transactionId) {
|
||||||
try {
|
try {
|
||||||
feeFromFundingTxProperty.set(preferences.getBlockchainApiProvider().getFee(transactionId));
|
feeFromFundingTxProperty.set(preferences.getBlockchainApiProvider().getFee(transactionId));
|
||||||
} catch (IOException | HttpException e) {
|
} catch (IOException | HttpException e) {
|
||||||
|
@ -216,7 +213,7 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||||
retryRequestFeeCounter++;
|
retryRequestFeeCounter++;
|
||||||
log.warn("We try again after 5 seconds");
|
log.warn("We try again after 5 seconds");
|
||||||
// TODO if we have more providers, try another one
|
// TODO if we have more providers, try another one
|
||||||
UserThread.runAfter(() -> requestFee(transactionId), 5);
|
UserThread.runAfter(() -> requestFeeFromBlockchain(transactionId), 5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -292,11 +289,6 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onSecurityDepositInfoDisplayed() {
|
|
||||||
preferences.setDisplaySecurityDepositInfo(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void onPaymentAccountSelected(PaymentAccount paymentAccount) {
|
public void onPaymentAccountSelected(PaymentAccount paymentAccount) {
|
||||||
if (paymentAccount != null)
|
if (paymentAccount != null)
|
||||||
this.paymentAccount = paymentAccount;
|
this.paymentAccount = paymentAccount;
|
||||||
|
@ -336,10 +328,6 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||||
return addressEntry;
|
return addressEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean getDisplaySecurityDepositInfo() {
|
|
||||||
return preferences.getDisplaySecurityDepositInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
public TradeCurrency getTradeCurrency() {
|
public TradeCurrency getTradeCurrency() {
|
||||||
return tradeCurrency;
|
return tradeCurrency;
|
||||||
}
|
}
|
||||||
|
|
|
@ -229,16 +229,24 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
|
||||||
|
|
||||||
private void onShowFundsScreen() {
|
private void onShowFundsScreen() {
|
||||||
if (!BitsquareApp.DEV_MODE) {
|
if (!BitsquareApp.DEV_MODE) {
|
||||||
if (model.getDisplaySecurityDepositInfo()) {
|
String id = "tradeWalletInfoPopup";
|
||||||
|
if (model.dataModel.getPreferences().showAgain(id)) {
|
||||||
new Popup().information("To ensure that both traders follow the trade protocol they need to pay a security deposit.\n\n" +
|
new Popup().information("To ensure that both traders follow the trade protocol they need to pay a security deposit.\n\n" +
|
||||||
"The deposit will stay in your local trading wallet until the offer gets accepted by another trader.\n" +
|
"The deposit will stay in your local trading wallet until the offer gets accepted by another trader.\n" +
|
||||||
"It will be refunded to you after the trade has successfully completed.\n\n" +
|
"It will be refunded to you after the trade has successfully completed.\n\n" +
|
||||||
"You need to pay in the exact amount displayed to you from your external bitcoin wallet into the " +
|
"You need to pay in the exact amount displayed to you from your external bitcoin wallet into the " +
|
||||||
"Bitsquare trade wallet. The amount is the sum of the security deposit, the trading fee and " +
|
"Bitsquare trade wallet.\n" +
|
||||||
|
"The amount is the sum of the security deposit, the trading fee and " +
|
||||||
"the bitcoin mining fee.\n" +
|
"the bitcoin mining fee.\n" +
|
||||||
"You can see the details when you move the mouse over the question mark.").show();
|
"You can see the details when you move the mouse over the question mark.\n\n" +
|
||||||
|
"Important notice!\n" +
|
||||||
model.onSecurityDepositInfoDisplayed();
|
"Please take care that you use a mining fee of at least " +
|
||||||
|
model.formatter.formatCoinWithCode(FeePolicy.getMinFundingFee()) + " when you transfer bitcoin from your external " +
|
||||||
|
"wallet to ensure the trade transactions will get into the blockchain.\n" +
|
||||||
|
"A too low mining fee might result in a delayed trade and will be rejected!")
|
||||||
|
.closeButtonText("I understand")
|
||||||
|
.show();
|
||||||
|
model.dataModel.getPreferences().dontShowAgain(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,7 +448,7 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
|
||||||
if (!model.dataModel.isFeeFromFundingTxSufficient()) {
|
if (!model.dataModel.isFeeFromFundingTxSufficient()) {
|
||||||
new Popup().warning("The mining fee from your funding transaction is not sufficiently high.\n\n" +
|
new Popup().warning("The mining fee from your funding transaction is not sufficiently high.\n\n" +
|
||||||
"You need to use at least a mining fee of " +
|
"You need to use at least a mining fee of " +
|
||||||
model.formatCoin(FeePolicy.getFeePerKb()) + ".\n\n" +
|
model.formatCoin(FeePolicy.getMinFundingFee()) + ".\n\n" +
|
||||||
"The fee used in your funding transaction was only " + model.formatCoin(newValue) + ".\n\n" +
|
"The fee used in your funding transaction was only " + model.formatCoin(newValue) + ".\n\n" +
|
||||||
"The trade transactions might take too much time to be included in " +
|
"The trade transactions might take too much time to be included in " +
|
||||||
"a block if the fee is too low.\n" +
|
"a block if the fee is too low.\n" +
|
||||||
|
|
|
@ -45,7 +45,7 @@ import static javafx.beans.binding.Bindings.createStringBinding;
|
||||||
class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel> implements ViewModel {
|
class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel> implements ViewModel {
|
||||||
private final BtcValidator btcValidator;
|
private final BtcValidator btcValidator;
|
||||||
private final P2PService p2PService;
|
private final P2PService p2PService;
|
||||||
private final BSFormatter formatter;
|
final BSFormatter formatter;
|
||||||
private final FiatValidator fiatValidator;
|
private final FiatValidator fiatValidator;
|
||||||
|
|
||||||
private String amountDescription;
|
private String amountDescription;
|
||||||
|
@ -322,10 +322,6 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
|
||||||
isPlaceOfferButtonVisible.set(true);
|
isPlaceOfferButtonVisible.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onSecurityDepositInfoDisplayed() {
|
|
||||||
dataModel.onSecurityDepositInfoDisplayed();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onPaymentAccountSelected(PaymentAccount paymentAccount) {
|
public void onPaymentAccountSelected(PaymentAccount paymentAccount) {
|
||||||
dataModel.onPaymentAccountSelected(paymentAccount);
|
dataModel.onPaymentAccountSelected(paymentAccount);
|
||||||
}
|
}
|
||||||
|
@ -431,10 +427,6 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
|
||||||
return formatter;
|
return formatter;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean getDisplaySecurityDepositInfo() {
|
|
||||||
return dataModel.getDisplaySecurityDepositInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isSellOffer() {
|
boolean isSellOffer() {
|
||||||
return dataModel.getDirection() == Offer.Direction.SELL;
|
return dataModel.getDirection() == Offer.Direction.SELL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,10 +184,6 @@ class TakeOfferDataModel extends ActivatableDataModel {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onSecurityDepositInfoDisplayed() {
|
|
||||||
preferences.setDisplaySecurityDepositInfo(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onPaymentAccountSelected(PaymentAccount paymentAccount) {
|
public void onPaymentAccountSelected(PaymentAccount paymentAccount) {
|
||||||
if (paymentAccount != null)
|
if (paymentAccount != null)
|
||||||
this.paymentAccount = paymentAccount;
|
this.paymentAccount = paymentAccount;
|
||||||
|
@ -202,10 +198,6 @@ class TakeOfferDataModel extends ActivatableDataModel {
|
||||||
return offer.getDirection();
|
return offer.getDirection();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean getDisplaySecurityDepositInfo() {
|
|
||||||
return preferences.getDisplaySecurityDepositInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Offer getOffer() {
|
public Offer getOffer() {
|
||||||
return offer;
|
return offer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ package io.bitsquare.gui.main.offer.takeoffer;
|
||||||
import de.jensd.fx.fontawesome.AwesomeDude;
|
import de.jensd.fx.fontawesome.AwesomeDude;
|
||||||
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.FeePolicy;
|
||||||
import io.bitsquare.common.UserThread;
|
import io.bitsquare.common.UserThread;
|
||||||
import io.bitsquare.common.util.Tuple2;
|
import io.bitsquare.common.util.Tuple2;
|
||||||
import io.bitsquare.common.util.Tuple3;
|
import io.bitsquare.common.util.Tuple3;
|
||||||
|
@ -214,7 +215,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
||||||
FxTimer.runLater(Duration.ofMillis(100),
|
FxTimer.runLater(Duration.ofMillis(100),
|
||||||
() -> {
|
() -> {
|
||||||
new Popup().information(BSResources.get("takeOffer.success.info"))
|
new Popup().information(BSResources.get("takeOffer.success.info"))
|
||||||
.actionButtonText("Go to \"Open trades\"")
|
.actionButtonText("Go to \"Portfolio/Open trades\"")
|
||||||
.onAction(() -> {
|
.onAction(() -> {
|
||||||
close();
|
close();
|
||||||
FxTimer.runLater(Duration.ofMillis(100),
|
FxTimer.runLater(Duration.ofMillis(100),
|
||||||
|
@ -335,17 +336,23 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
||||||
|
|
||||||
private void onShowPayFundsScreen() {
|
private void onShowPayFundsScreen() {
|
||||||
if (!BitsquareApp.DEV_MODE) {
|
if (!BitsquareApp.DEV_MODE) {
|
||||||
if (model.getDisplaySecurityDepositInfo()) {
|
String id = "tradeWalletInfoPopup";
|
||||||
MainView.blur();
|
if (model.dataModel.getPreferences().showAgain(id)) {
|
||||||
new Popup().information("To ensure that both traders follow the trade protocol they need to pay a security deposit.\n\n" +
|
new Popup().information("To ensure that both traders follow the trade protocol they need to pay a security deposit.\n\n" +
|
||||||
"The security deposit will be refunded to you after the trade has successfully completed.\n\n" +
|
"The deposit will be refunded to you after the trade has successfully completed.\n\n" +
|
||||||
"You need to pay in the exact amount displayed to you from your external bitcoin wallet into the " +
|
"You need to pay in the exact amount displayed to you from your external bitcoin wallet into the " +
|
||||||
"Bitsquare trade wallet. In case you over pay, you will get it refunded after the trade.\n\n" +
|
"Bitsquare trade wallet.\n" +
|
||||||
"The amount needed for funding is the sum of the trade amount, the security deposit, " +
|
"The amount is the sum of the trade amount, the security deposit, the trading fee and " +
|
||||||
"the trading fee and the bitcoin mining fee.\n" +
|
"the bitcoin mining fee.\n" +
|
||||||
"You can see the details when you move the mouse over the question mark.").show();
|
"You can see the details when you move the mouse over the question mark.\n\n" +
|
||||||
|
"Important notice!\n" +
|
||||||
model.onSecurityDepositInfoDisplayed();
|
"Please take care that you use a mining fee of at least " +
|
||||||
|
model.formatter.formatCoinWithCode(FeePolicy.getMinFundingFee()) + " when you transfer bitcoin from your external " +
|
||||||
|
"wallet to ensure the trade transactions will get into the blockchain.\n" +
|
||||||
|
"A too low mining fee might result in a delayed trade and will be rejected!")
|
||||||
|
.closeButtonText("I understand")
|
||||||
|
.show();
|
||||||
|
model.dataModel.getPreferences().dontShowAgain(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ import static javafx.beans.binding.Bindings.createStringBinding;
|
||||||
class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> implements ViewModel {
|
class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> implements ViewModel {
|
||||||
private final BtcValidator btcValidator;
|
private final BtcValidator btcValidator;
|
||||||
private P2PService p2PService;
|
private P2PService p2PService;
|
||||||
private final BSFormatter formatter;
|
final BSFormatter formatter;
|
||||||
|
|
||||||
private String amountRange;
|
private String amountRange;
|
||||||
private String addressAsString;
|
private String addressAsString;
|
||||||
|
@ -194,10 +194,6 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||||
dataModel.onPaymentAccountSelected(paymentAccount);
|
dataModel.onPaymentAccountSelected(paymentAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onSecurityDepositInfoDisplayed() {
|
|
||||||
dataModel.onSecurityDepositInfoDisplayed();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Handle focus
|
// Handle focus
|
||||||
|
@ -471,10 +467,6 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||||
return formatter;
|
return formatter;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean getDisplaySecurityDepositInfo() {
|
|
||||||
return dataModel.getDisplaySecurityDepositInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isSeller() {
|
boolean isSeller() {
|
||||||
return dataModel.getDirection() == Offer.Direction.BUY;
|
return dataModel.getDirection() == Offer.Direction.BUY;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,10 +61,19 @@ public class BuyerSubView extends TradeSubView {
|
||||||
step4 = new TradeWizardItem(BuyerStep4View.class, "Wait for payout unlock");
|
step4 = new TradeWizardItem(BuyerStep4View.class, "Wait for payout unlock");
|
||||||
step5 = new TradeWizardItem(BuyerStep5View.class, "Completed");
|
step5 = new TradeWizardItem(BuyerStep5View.class, "Completed");
|
||||||
|
|
||||||
if (model.getLockTime() > 0)
|
if (model.getLockTime() > 0) {
|
||||||
leftVBox.getChildren().setAll(step1, step2, step3, step4, step5);
|
addWizardsToGridPane(step1);
|
||||||
else
|
addWizardsToGridPane(step2);
|
||||||
leftVBox.getChildren().setAll(step1, step2, step3, step5);
|
addWizardsToGridPane(step3);
|
||||||
|
addWizardsToGridPane(step4);
|
||||||
|
addWizardsToGridPane(step5);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
addWizardsToGridPane(step1);
|
||||||
|
addWizardsToGridPane(step2);
|
||||||
|
addWizardsToGridPane(step3);
|
||||||
|
addWizardsToGridPane(step5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -24,17 +24,14 @@ import io.bitsquare.arbitration.DisputeManager;
|
||||||
import io.bitsquare.btc.FeePolicy;
|
import io.bitsquare.btc.FeePolicy;
|
||||||
import io.bitsquare.btc.TradeWalletService;
|
import io.bitsquare.btc.TradeWalletService;
|
||||||
import io.bitsquare.btc.WalletService;
|
import io.bitsquare.btc.WalletService;
|
||||||
import io.bitsquare.common.UserThread;
|
|
||||||
import io.bitsquare.common.crypto.KeyRing;
|
import io.bitsquare.common.crypto.KeyRing;
|
||||||
import io.bitsquare.common.handlers.ErrorMessageHandler;
|
import io.bitsquare.common.handlers.ErrorMessageHandler;
|
||||||
|
import io.bitsquare.common.handlers.FaultHandler;
|
||||||
import io.bitsquare.common.handlers.ResultHandler;
|
import io.bitsquare.common.handlers.ResultHandler;
|
||||||
import io.bitsquare.gui.Navigation;
|
import io.bitsquare.gui.Navigation;
|
||||||
import io.bitsquare.gui.common.model.ActivatableDataModel;
|
import io.bitsquare.gui.common.model.ActivatableDataModel;
|
||||||
import io.bitsquare.gui.main.MainView;
|
import io.bitsquare.gui.main.MainView;
|
||||||
import io.bitsquare.gui.main.disputes.DisputesView;
|
import io.bitsquare.gui.main.disputes.DisputesView;
|
||||||
import io.bitsquare.gui.main.portfolio.PortfolioView;
|
|
||||||
import io.bitsquare.gui.main.portfolio.closedtrades.ClosedTradesView;
|
|
||||||
import io.bitsquare.gui.popups.Popup;
|
|
||||||
import io.bitsquare.gui.popups.SelectDepositTxPopup;
|
import io.bitsquare.gui.popups.SelectDepositTxPopup;
|
||||||
import io.bitsquare.gui.popups.WalletPasswordPopup;
|
import io.bitsquare.gui.popups.WalletPasswordPopup;
|
||||||
import io.bitsquare.payment.PaymentAccountContractData;
|
import io.bitsquare.payment.PaymentAccountContractData;
|
||||||
|
@ -167,25 +164,29 @@ public class PendingTradesDataModel extends ActivatableDataModel {
|
||||||
((SellerTrade) trade).onFiatPaymentReceived();
|
((SellerTrade) trade).onFiatPaymentReceived();
|
||||||
}
|
}
|
||||||
|
|
||||||
void onWithdrawRequest(String toAddress) {
|
public void onWithdrawRequest(String toAddress, ResultHandler resultHandler, FaultHandler faultHandler) {
|
||||||
checkNotNull(trade, "trade must not be null");
|
checkNotNull(trade, "trade must not be null");
|
||||||
if (walletService.getWallet().isEncrypted()) {
|
if (walletService.getWallet().isEncrypted()) {
|
||||||
walletPasswordPopup.onAesKey(aesKey -> doWithdrawRequest(toAddress, aesKey)).show();
|
walletPasswordPopup.onAesKey(aesKey -> doWithdrawRequest(toAddress, aesKey, resultHandler, faultHandler)).show();
|
||||||
} else
|
} else
|
||||||
doWithdrawRequest(toAddress, null);
|
doWithdrawRequest(toAddress, null, resultHandler, faultHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doWithdrawRequest(String toAddress, KeyParameter aesKey) {
|
private void doWithdrawRequest(String toAddress, KeyParameter aesKey, ResultHandler resultHandler, FaultHandler faultHandler) {
|
||||||
if (toAddress != null && toAddress.length() > 0) {
|
if (toAddress != null && toAddress.length() > 0) {
|
||||||
tradeManager.onWithdrawRequest(
|
tradeManager.onWithdrawRequest(
|
||||||
toAddress,
|
toAddress,
|
||||||
aesKey,
|
aesKey,
|
||||||
trade,
|
trade,
|
||||||
() -> UserThread.execute(() -> navigation.navigateTo(MainView.class, PortfolioView.class, ClosedTradesView.class)),
|
() -> {
|
||||||
|
resultHandler.handleResult();
|
||||||
|
},
|
||||||
(errorMessage, throwable) -> {
|
(errorMessage, throwable) -> {
|
||||||
log.error(errorMessage);
|
log.error(errorMessage);
|
||||||
new Popup().error("An error occurred:\n" + throwable.getMessage()).show();
|
faultHandler.handleFault(errorMessage, throwable);
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
faultHandler.handleFault("No receiver address defined", null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -135,6 +135,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
||||||
|
|
||||||
if (dataModel.getTrade() != null) {
|
if (dataModel.getTrade() != null) {
|
||||||
tradeStateSubscription = EasyBind.subscribe(dataModel.getTrade().stateProperty(), newValue -> {
|
tradeStateSubscription = EasyBind.subscribe(dataModel.getTrade().stateProperty(), newValue -> {
|
||||||
|
log.debug("tradeStateSubscription " + newValue);
|
||||||
if (newValue != null) {
|
if (newValue != null) {
|
||||||
applyState(newValue);
|
applyState(newValue);
|
||||||
}
|
}
|
||||||
|
@ -191,10 +192,6 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
||||||
dataModel.onFiatPaymentReceived();
|
dataModel.onFiatPaymentReceived();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onWithdrawRequest(String withdrawToAddress) {
|
|
||||||
dataModel.onWithdrawRequest(withdrawToAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void withdrawAddressFocusOut(String text) {
|
public void withdrawAddressFocusOut(String text) {
|
||||||
withdrawalButtonDisable.set(!btcAddressValidator.validate(text).isValid);
|
withdrawalButtonDisable.set(!btcAddressValidator.validate(text).isValid);
|
||||||
}
|
}
|
||||||
|
@ -324,7 +321,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getOpenDisputeTimeAsFormattedDate() {
|
public String getOpenDisputeTimeAsFormattedDate() {
|
||||||
return formatter.addBlocksToNowDateFormatted(getOpenDisputeTimeAsBlockHeight() - getBestChainHeight());
|
return formatter.addBlocksToNowDateFormatted(getOpenDisputeTimeAsBlockHeight() - getBestChainHeight() + (getLockTime() - getBestChainHeight()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getReference() {
|
public String getReference() {
|
||||||
|
@ -448,9 +445,13 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WITHDRAW_COMPLETED:
|
case WITHDRAW_COMPLETED:
|
||||||
|
sellerState.set(UNDEFINED);
|
||||||
|
buyerState.set(PendingTradesViewModel.BuyerState.UNDEFINED);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
sellerState.set(UNDEFINED);
|
||||||
|
buyerState.set(PendingTradesViewModel.BuyerState.UNDEFINED);
|
||||||
log.warn("unhandled processState " + tradeState);
|
log.warn("unhandled processState " + tradeState);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ package io.bitsquare.gui.main.portfolio.pendingtrades;
|
||||||
import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeWizardItem;
|
import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeWizardItem;
|
||||||
import io.bitsquare.gui.main.portfolio.pendingtrades.steps.seller.*;
|
import io.bitsquare.gui.main.portfolio.pendingtrades.steps.seller.*;
|
||||||
import javafx.beans.value.ChangeListener;
|
import javafx.beans.value.ChangeListener;
|
||||||
|
import javafx.scene.layout.GridPane;
|
||||||
|
|
||||||
public class SellerSubView extends TradeSubView {
|
public class SellerSubView extends TradeSubView {
|
||||||
private TradeWizardItem step1;
|
private TradeWizardItem step1;
|
||||||
|
@ -61,10 +62,20 @@ public class SellerSubView extends TradeSubView {
|
||||||
step4 = new TradeWizardItem(SellerStep4aView.class, "Wait for payout unlock");
|
step4 = new TradeWizardItem(SellerStep4aView.class, "Wait for payout unlock");
|
||||||
step5 = new TradeWizardItem(SellerStep5View.class, "Completed");
|
step5 = new TradeWizardItem(SellerStep5View.class, "Completed");
|
||||||
|
|
||||||
if (model.getLockTime() > 0)
|
if (model.getLockTime() > 0) {
|
||||||
leftVBox.getChildren().setAll(step1, step2, step3, step4, step5);
|
addWizardsToGridPane(step1);
|
||||||
else
|
addWizardsToGridPane(step2);
|
||||||
leftVBox.getChildren().setAll(step1, step2, step3, step5);
|
addWizardsToGridPane(step3);
|
||||||
|
addWizardsToGridPane(step4);
|
||||||
|
addWizardsToGridPane(step5);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
addWizardsToGridPane(step1);
|
||||||
|
addWizardsToGridPane(step2);
|
||||||
|
addWizardsToGridPane(step3);
|
||||||
|
addWizardsToGridPane(step5);
|
||||||
|
GridPane.setRowSpan(tradeProcessTitledGroupBg, 4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,21 +17,18 @@
|
||||||
|
|
||||||
package io.bitsquare.gui.main.portfolio.pendingtrades;
|
package io.bitsquare.gui.main.portfolio.pendingtrades;
|
||||||
|
|
||||||
import io.bitsquare.common.util.Tuple3;
|
|
||||||
import io.bitsquare.gui.components.TitledGroupBg;
|
import io.bitsquare.gui.components.TitledGroupBg;
|
||||||
import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeStepView;
|
import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeStepView;
|
||||||
import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeWizardItem;
|
import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeWizardItem;
|
||||||
import io.bitsquare.gui.util.Layout;
|
import io.bitsquare.gui.util.Layout;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.layout.*;
|
import javafx.scene.layout.*;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import static io.bitsquare.gui.util.FormBuilder.addMultilineLabel;
|
import static io.bitsquare.gui.util.FormBuilder.*;
|
||||||
import static io.bitsquare.gui.util.FormBuilder.addTitledGroupBg;
|
|
||||||
|
|
||||||
public abstract class TradeSubView extends HBox {
|
public abstract class TradeSubView extends HBox {
|
||||||
protected final Logger log = LoggerFactory.getLogger(this.getClass());
|
protected final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||||
|
@ -41,7 +38,10 @@ public abstract class TradeSubView extends HBox {
|
||||||
protected AnchorPane contentPane;
|
protected AnchorPane contentPane;
|
||||||
protected TradeStepView tradeStepView;
|
protected TradeStepView tradeStepView;
|
||||||
private Button openDisputeButton;
|
private Button openDisputeButton;
|
||||||
private Tuple3<GridPane, TitledGroupBg, Label> notificationTuple;
|
private NotificationGroup notificationGroup;
|
||||||
|
protected GridPane leftGridPane;
|
||||||
|
protected TitledGroupBg tradeProcessTitledGroupBg;
|
||||||
|
protected int leftGridPaneRowIndex = 0;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -63,41 +63,66 @@ public abstract class TradeSubView extends HBox {
|
||||||
tradeStepView.doDeactivate();
|
tradeStepView.doDeactivate();
|
||||||
|
|
||||||
if (openDisputeButton != null)
|
if (openDisputeButton != null)
|
||||||
leftVBox.getChildren().remove(openDisputeButton);
|
leftGridPane.getChildren().remove(openDisputeButton);
|
||||||
if (notificationTuple != null)
|
if (notificationGroup != null)
|
||||||
leftVBox.getChildren().remove(notificationTuple.first);
|
notificationGroup.removeItselfFrom(leftGridPane);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buildViews() {
|
private void buildViews() {
|
||||||
addLeftBox();
|
addLeftBox();
|
||||||
addContentPane();
|
addContentPane();
|
||||||
|
|
||||||
|
leftGridPane = new GridPane();
|
||||||
|
leftGridPane.setPrefWidth(340);
|
||||||
|
VBox.setMargin(leftGridPane, new Insets(0, 10, 10, 10));
|
||||||
|
leftGridPane.setHgap(Layout.GRID_GAP);
|
||||||
|
leftGridPane.setVgap(Layout.GRID_GAP);
|
||||||
|
leftVBox.getChildren().add(leftGridPane);
|
||||||
|
|
||||||
|
leftGridPaneRowIndex = 0;
|
||||||
|
tradeProcessTitledGroupBg = addTitledGroupBg(leftGridPane, leftGridPaneRowIndex, 1, "Trade process");
|
||||||
|
|
||||||
addWizards();
|
addWizards();
|
||||||
|
|
||||||
openDisputeButton = new Button("Open Dispute");
|
TitledGroupBg noticeTitledGroupBg = addTitledGroupBg(leftGridPane, leftGridPaneRowIndex, 1, "", Layout.GROUP_DISTANCE);
|
||||||
openDisputeButton.setPrefHeight(40);
|
Label label = addMultilineLabel(leftGridPane, leftGridPaneRowIndex, "", Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
||||||
openDisputeButton.setPrefWidth(360);
|
openDisputeButton = addButtonAfterGroup(leftGridPane, ++leftGridPaneRowIndex, "Open Dispute");
|
||||||
openDisputeButton.setPadding(new Insets(0, 20, 0, 10));
|
GridPane.setColumnIndex(openDisputeButton, 0);
|
||||||
openDisputeButton.setAlignment(Pos.CENTER);
|
|
||||||
openDisputeButton.setDefaultButton(true);
|
|
||||||
openDisputeButton.setId("open-dispute-button");
|
openDisputeButton.setId("open-dispute-button");
|
||||||
openDisputeButton.setVisible(false);
|
|
||||||
openDisputeButton.setManaged(false);
|
|
||||||
leftVBox.getChildren().add(openDisputeButton);
|
|
||||||
VBox.setMargin(openDisputeButton, new Insets(10, 0, 0, 0));
|
|
||||||
|
|
||||||
// notification fields
|
notificationGroup = new NotificationGroup(noticeTitledGroupBg, label, openDisputeButton);
|
||||||
GridPane gridPane = new GridPane();
|
notificationGroup.setLabelAndHeadlineVisible(false);
|
||||||
gridPane.setPrefWidth(340);
|
notificationGroup.setButtonVisible(false);
|
||||||
VBox.setMargin(gridPane, new Insets(10, 10, 10, 10));
|
}
|
||||||
gridPane.setHgap(Layout.GRID_GAP);
|
|
||||||
gridPane.setVgap(Layout.GRID_GAP);
|
|
||||||
gridPane.setVisible(false);
|
|
||||||
gridPane.setManaged(false);
|
|
||||||
leftVBox.getChildren().add(gridPane);
|
|
||||||
|
|
||||||
TitledGroupBg titledGroupBg = addTitledGroupBg(gridPane, 0, 4, "Important notice", 20);
|
public static class NotificationGroup {
|
||||||
Label label = addMultilineLabel(gridPane, 0, Layout.FIRST_ROW_DISTANCE + 20);
|
public final TitledGroupBg titledGroupBg;
|
||||||
notificationTuple = new Tuple3<>(gridPane, titledGroupBg, label);
|
public final Label label;
|
||||||
|
public final Button button;
|
||||||
|
|
||||||
|
public NotificationGroup(TitledGroupBg titledGroupBg, Label label, Button button) {
|
||||||
|
this.titledGroupBg = titledGroupBg;
|
||||||
|
this.label = label;
|
||||||
|
this.button = button;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLabelAndHeadlineVisible(boolean isVisible) {
|
||||||
|
titledGroupBg.setVisible(isVisible);
|
||||||
|
label.setVisible(isVisible);
|
||||||
|
titledGroupBg.setManaged(isVisible);
|
||||||
|
label.setManaged(isVisible);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setButtonVisible(boolean isVisible) {
|
||||||
|
button.setVisible(isVisible);
|
||||||
|
button.setManaged(isVisible);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeItselfFrom(GridPane leftGridPane) {
|
||||||
|
leftGridPane.getChildren().remove(titledGroupBg);
|
||||||
|
leftGridPane.getChildren().remove(label);
|
||||||
|
leftGridPane.getChildren().remove(button);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void showItem(TradeWizardItem item) {
|
protected void showItem(TradeWizardItem item) {
|
||||||
|
@ -107,13 +132,22 @@ public abstract class TradeSubView extends HBox {
|
||||||
|
|
||||||
abstract protected void addWizards();
|
abstract protected void addWizards();
|
||||||
|
|
||||||
|
protected void addWizardsToGridPane(TradeWizardItem tradeWizardItem) {
|
||||||
|
if (leftGridPaneRowIndex == 0)
|
||||||
|
GridPane.setMargin(tradeWizardItem, new Insets(Layout.FIRST_ROW_DISTANCE, 0, 0, 0));
|
||||||
|
|
||||||
|
GridPane.setRowIndex(tradeWizardItem, leftGridPaneRowIndex++);
|
||||||
|
leftGridPane.getChildren().add(tradeWizardItem);
|
||||||
|
GridPane.setRowSpan(tradeProcessTitledGroupBg, leftGridPaneRowIndex);
|
||||||
|
GridPane.setFillWidth(tradeWizardItem, true);
|
||||||
|
}
|
||||||
|
|
||||||
private void createAndAddTradeStepView(Class<? extends TradeStepView> viewClass) {
|
private void createAndAddTradeStepView(Class<? extends TradeStepView> viewClass) {
|
||||||
try {
|
try {
|
||||||
tradeStepView = viewClass.getDeclaredConstructor(PendingTradesViewModel.class).newInstance(model);
|
tradeStepView = viewClass.getDeclaredConstructor(PendingTradesViewModel.class).newInstance(model);
|
||||||
contentPane.getChildren().setAll(tradeStepView);
|
contentPane.getChildren().setAll(tradeStepView);
|
||||||
|
|
||||||
tradeStepView.setNotificationFields(notificationTuple);
|
tradeStepView.setNotificationGroup(notificationGroup);
|
||||||
tradeStepView.setOpenDisputeButton(openDisputeButton);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,18 +18,16 @@
|
||||||
package io.bitsquare.gui.main.portfolio.pendingtrades.steps;
|
package io.bitsquare.gui.main.portfolio.pendingtrades.steps;
|
||||||
|
|
||||||
import io.bitsquare.arbitration.Dispute;
|
import io.bitsquare.arbitration.Dispute;
|
||||||
import io.bitsquare.common.util.Tuple3;
|
|
||||||
import io.bitsquare.gui.components.TitledGroupBg;
|
import io.bitsquare.gui.components.TitledGroupBg;
|
||||||
import io.bitsquare.gui.components.TxIdTextField;
|
import io.bitsquare.gui.components.TxIdTextField;
|
||||||
import io.bitsquare.gui.components.paymentmethods.PaymentMethodForm;
|
import io.bitsquare.gui.components.paymentmethods.PaymentMethodForm;
|
||||||
import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel;
|
import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel;
|
||||||
|
import io.bitsquare.gui.main.portfolio.pendingtrades.TradeSubView;
|
||||||
import io.bitsquare.gui.popups.Popup;
|
import io.bitsquare.gui.popups.Popup;
|
||||||
import io.bitsquare.gui.util.Layout;
|
import io.bitsquare.gui.util.Layout;
|
||||||
import io.bitsquare.trade.Trade;
|
import io.bitsquare.trade.Trade;
|
||||||
import io.bitsquare.user.Preferences;
|
import io.bitsquare.user.Preferences;
|
||||||
import javafx.beans.value.ChangeListener;
|
import javafx.beans.value.ChangeListener;
|
||||||
import javafx.scene.control.Button;
|
|
||||||
import javafx.scene.control.Label;
|
|
||||||
import javafx.scene.control.ProgressBar;
|
import javafx.scene.control.ProgressBar;
|
||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
|
@ -63,11 +61,8 @@ public abstract class TradeStepView extends AnchorPane {
|
||||||
protected TitledGroupBg tradeInfoTitledGroupBg;
|
protected TitledGroupBg tradeInfoTitledGroupBg;
|
||||||
private TextField timeLeftTextField;
|
private TextField timeLeftTextField;
|
||||||
private ProgressBar timeLeftProgressBar;
|
private ProgressBar timeLeftProgressBar;
|
||||||
private GridPane notificationGridPane;
|
|
||||||
private Label notificationLabel;
|
|
||||||
private TitledGroupBg notificationTitledGroupBg;
|
|
||||||
protected Button openDisputeButton;
|
|
||||||
private TxIdTextField txIdTextField;
|
private TxIdTextField txIdTextField;
|
||||||
|
protected TradeSubView.NotificationGroup notificationGroup;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -135,8 +130,8 @@ public abstract class TradeStepView extends AnchorPane {
|
||||||
if (tradePeriodStateSubscription != null)
|
if (tradePeriodStateSubscription != null)
|
||||||
tradePeriodStateSubscription.unsubscribe();
|
tradePeriodStateSubscription.unsubscribe();
|
||||||
|
|
||||||
if (openDisputeButton != null)
|
if (notificationGroup != null)
|
||||||
openDisputeButton.setOnAction(null);
|
notificationGroup.button.setOnAction(null);
|
||||||
|
|
||||||
if (timer != null)
|
if (timer != null)
|
||||||
timer.stop();
|
timer.stop();
|
||||||
|
@ -212,63 +207,68 @@ public abstract class TradeStepView extends AnchorPane {
|
||||||
|
|
||||||
// We have the dispute button and text field on the left side, but we handle the content here as it
|
// We have the dispute button and text field on the left side, but we handle the content here as it
|
||||||
// is trade state specific
|
// is trade state specific
|
||||||
public void setNotificationFields(Tuple3<GridPane, TitledGroupBg, Label> notificationTuple) {
|
public void setNotificationGroup(TradeSubView.NotificationGroup notificationGroup) {
|
||||||
this.notificationGridPane = notificationTuple.first;
|
this.notificationGroup = notificationGroup;
|
||||||
this.notificationTitledGroupBg = notificationTuple.second;
|
|
||||||
this.notificationLabel = notificationTuple.third;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOpenDisputeButton(Button openDisputeButton) {
|
|
||||||
this.openDisputeButton = openDisputeButton;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showDisputeInfoLabel() {
|
private void showDisputeInfoLabel() {
|
||||||
if (notificationGridPane != null) {
|
if (notificationGroup != null) {
|
||||||
notificationGridPane.setVisible(true);
|
notificationGroup.setLabelAndHeadlineVisible(true);
|
||||||
notificationGridPane.setManaged(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showOpenDisputeButton() {
|
private void showOpenDisputeButton() {
|
||||||
if (openDisputeButton != null) {
|
if (notificationGroup != null) {
|
||||||
openDisputeButton.setVisible(true);
|
notificationGroup.setButtonVisible(true);
|
||||||
openDisputeButton.setManaged(true);
|
notificationGroup.button.setOnAction(e -> {
|
||||||
openDisputeButton.setOnAction(e -> {
|
notificationGroup.button.setDisable(true);
|
||||||
openDisputeButton.setDisable(true);
|
|
||||||
onDisputeOpened();
|
onDisputeOpened();
|
||||||
setDisputeState();
|
|
||||||
model.dataModel.onOpenDispute();
|
model.dataModel.onOpenDispute();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setWarningState() {
|
protected void setWarningHeadline() {
|
||||||
if (notificationGridPane != null) {
|
if (notificationGroup != null) {
|
||||||
notificationTitledGroupBg.setText("Warning");
|
notificationGroup.titledGroupBg.setText("Warning");
|
||||||
//notificationGridPane.setId("trade-notification-warning");
|
//notificationGroup.setId("trade-notification-warning");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setInformationState() {
|
protected void setInformationHeadline() {
|
||||||
if (notificationGridPane != null) {
|
if (notificationGroup != null) {
|
||||||
notificationTitledGroupBg.setText("Notification");
|
notificationGroup.titledGroupBg.setText("Notification");
|
||||||
notificationTitledGroupBg.setId("titled-group-bg-warn");
|
//notificationGroup.titledGroupBg.setId("titled-group-bg-warn");
|
||||||
notificationTitledGroupBg.getLabel().setId("titled-group-bg-label-warn");
|
//notificationGroup.label.setId("titled-group-bg-label-warn");
|
||||||
//notificationLabel.setId("titled-group-bg-label-warn");
|
//notificationLabel.setId("titled-group-bg-label-warn");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setDisputeState() {
|
protected void setOpenDisputeHeadline() {
|
||||||
if (notificationGridPane != null) {
|
if (notificationGroup != null) {
|
||||||
notificationTitledGroupBg.setText("Dispute opened");
|
notificationGroup.titledGroupBg.setText("Open a dispute");
|
||||||
//notificationGridPane.setId("trade-notification-dispute");
|
//notificationGroup.setId("trade-notification-dispute");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setSupportState() {
|
protected void setDisputeOpenedHeadline() {
|
||||||
if (notificationGridPane != null) {
|
if (notificationGroup != null) {
|
||||||
notificationTitledGroupBg.setText("Support ticket opened");
|
notificationGroup.titledGroupBg.setText("Dispute opened");
|
||||||
//notificationGridPane.setId("trade-notification-support");
|
//notificationGroup.setId("trade-notification-dispute");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setRequestSupportHeadline() {
|
||||||
|
if (notificationGroup != null) {
|
||||||
|
notificationGroup.titledGroupBg.setText("Open support ticket");
|
||||||
|
//notificationGroup.setId("trade-notification-support");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setSupportOpenedHeadline() {
|
||||||
|
if (notificationGroup != null) {
|
||||||
|
notificationGroup.titledGroupBg.setText("Support ticket opened");
|
||||||
|
//notificationGroup.setId("trade-notification-support");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,10 +277,10 @@ public abstract class TradeStepView extends AnchorPane {
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private void showSupportFields() {
|
private void showSupportFields() {
|
||||||
if (openDisputeButton != null) {
|
if (notificationGroup != null) {
|
||||||
openDisputeButton.setText("Request support");
|
notificationGroup.button.setText("Request support");
|
||||||
openDisputeButton.setId("open-support-button");
|
notificationGroup.button.setId("open-support-button");
|
||||||
openDisputeButton.setOnAction(e -> model.dataModel.onOpenSupportTicket());
|
notificationGroup.button.setOnAction(e -> model.dataModel.onOpenSupportTicket());
|
||||||
}
|
}
|
||||||
new Popup().warning(trade.errorMessageProperty().getValue()
|
new Popup().warning(trade.errorMessageProperty().getValue()
|
||||||
+ "\n\nPlease report the problem to your arbitrator.\n\n" +
|
+ "\n\nPlease report the problem to your arbitrator.\n\n" +
|
||||||
|
@ -299,8 +299,8 @@ public abstract class TradeStepView extends AnchorPane {
|
||||||
private void showWarning() {
|
private void showWarning() {
|
||||||
showDisputeInfoLabel();
|
showDisputeInfoLabel();
|
||||||
|
|
||||||
if (notificationLabel != null)
|
if (notificationGroup != null)
|
||||||
notificationLabel.setText(getWarningText());
|
notificationGroup.label.setText(getWarningText());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getWarningText() {
|
protected String getWarningText() {
|
||||||
|
@ -315,19 +315,20 @@ public abstract class TradeStepView extends AnchorPane {
|
||||||
private void onOpenForDispute() {
|
private void onOpenForDispute() {
|
||||||
showDisputeInfoLabel();
|
showDisputeInfoLabel();
|
||||||
showOpenDisputeButton();
|
showOpenDisputeButton();
|
||||||
|
setOpenDisputeHeadline();
|
||||||
|
|
||||||
if (notificationLabel != null)
|
if (notificationGroup != null)
|
||||||
notificationLabel.setText(getOpenForDisputeText());
|
notificationGroup.label.setText(getOpenForDisputeText());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onDisputeOpened() {
|
private void onDisputeOpened() {
|
||||||
showDisputeInfoLabel();
|
showDisputeInfoLabel();
|
||||||
showOpenDisputeButton();
|
showOpenDisputeButton();
|
||||||
applyOnDisputeOpened();
|
applyOnDisputeOpened();
|
||||||
|
setDisputeOpenedHeadline();
|
||||||
|
|
||||||
|
if (notificationGroup != null)
|
||||||
if (openDisputeButton != null)
|
notificationGroup.button.setDisable(true);
|
||||||
openDisputeButton.setDisable(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getOpenForDisputeText() {
|
protected String getOpenForDisputeText() {
|
||||||
|
@ -337,6 +338,11 @@ public abstract class TradeStepView extends AnchorPane {
|
||||||
protected void applyOnDisputeOpened() {
|
protected void applyOnDisputeOpened() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void hideNotificationGroup() {
|
||||||
|
notificationGroup.setLabelAndHeadlineVisible(false);
|
||||||
|
notificationGroup.setButtonVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
private void updateDisputeState(Trade.DisputeState disputeState) {
|
private void updateDisputeState(Trade.DisputeState disputeState) {
|
||||||
Optional<Dispute> ownDispute;
|
Optional<Dispute> ownDispute;
|
||||||
switch (disputeState) {
|
switch (disputeState) {
|
||||||
|
@ -348,16 +354,16 @@ public abstract class TradeStepView extends AnchorPane {
|
||||||
ownDispute.ifPresent(dispute -> {
|
ownDispute.ifPresent(dispute -> {
|
||||||
String msg;
|
String msg;
|
||||||
if (dispute.isSupportTicket()) {
|
if (dispute.isSupportTicket()) {
|
||||||
setSupportState();
|
setSupportOpenedHeadline();
|
||||||
msg = "You opened already a support ticket.\n" +
|
msg = "You opened already a support ticket.\n" +
|
||||||
"Please communicate in the support section with the arbitrator.";
|
"Please communicate in the support section with the arbitrator.";
|
||||||
} else {
|
} else {
|
||||||
setDisputeState();
|
setDisputeOpenedHeadline();
|
||||||
msg = "You opened already a dispute.\n" +
|
msg = "You opened already a dispute.\n" +
|
||||||
"Please communicate in the support section with the arbitrator.";
|
"Please communicate in the support section with the arbitrator.";
|
||||||
}
|
}
|
||||||
if (notificationLabel != null)
|
if (notificationGroup != null)
|
||||||
notificationLabel.setText(msg);
|
notificationGroup.label.setText(msg);
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -367,16 +373,16 @@ public abstract class TradeStepView extends AnchorPane {
|
||||||
ownDispute.ifPresent(dispute -> {
|
ownDispute.ifPresent(dispute -> {
|
||||||
String msg;
|
String msg;
|
||||||
if (dispute.isSupportTicket()) {
|
if (dispute.isSupportTicket()) {
|
||||||
setSupportState();
|
setSupportOpenedHeadline();
|
||||||
msg = "Your trading peer opened a support ticket due technical problems.\n" +
|
msg = "Your trading peer opened a support ticket due technical problems.\n" +
|
||||||
"Please communicate in the support section with the arbitrator.";
|
"Please communicate in the support section with the arbitrator.";
|
||||||
} else {
|
} else {
|
||||||
setDisputeState();
|
setDisputeOpenedHeadline();
|
||||||
msg = "Your trading peer opened a dispute.\n" +
|
msg = "Your trading peer opened a dispute.\n" +
|
||||||
"Please communicate in the support section with the arbitrator.";
|
"Please communicate in the support section with the arbitrator.";
|
||||||
}
|
}
|
||||||
if (notificationLabel != null)
|
if (notificationGroup != null)
|
||||||
notificationLabel.setText(msg);
|
notificationGroup.label.setText(msg);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case DISPUTE_CLOSED:
|
case DISPUTE_CLOSED:
|
||||||
|
|
|
@ -39,7 +39,6 @@ public class TradeWizardItem extends Button {
|
||||||
setText(title);
|
setText(title);
|
||||||
setPrefHeight(40);
|
setPrefHeight(40);
|
||||||
setPrefWidth(360);
|
setPrefWidth(360);
|
||||||
setPadding(new Insets(0, 20, 0, 10));
|
|
||||||
setAlignment(Pos.CENTER_LEFT);
|
setAlignment(Pos.CENTER_LEFT);
|
||||||
setDisabled();
|
setDisabled();
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ public class BuyerStep2View extends TradeStepView {
|
||||||
public void doActivate() {
|
public void doActivate() {
|
||||||
super.doActivate();
|
super.doActivate();
|
||||||
|
|
||||||
String id = PopupId.SEND_PAYMENT_INFO;
|
/* String id = PopupId.SEND_PAYMENT_INFO;
|
||||||
if (preferences.showAgain(id) && !BitsquareApp.DEV_MODE) {
|
if (preferences.showAgain(id) && !BitsquareApp.DEV_MODE) {
|
||||||
//TODO use payment method and trade values
|
//TODO use payment method and trade values
|
||||||
new Popup().information("You need to transfer now the agreed amount to your trading partner.\n" +
|
new Popup().information("You need to transfer now the agreed amount to your trading partner.\n" +
|
||||||
|
@ -65,7 +65,7 @@ public class BuyerStep2View extends TradeStepView {
|
||||||
"Make sure that you make the transfer soon to not exceed the trading period.")
|
"Make sure that you make the transfer soon to not exceed the trading period.")
|
||||||
.onClose(() -> preferences.dontShowAgain(id))
|
.onClose(() -> preferences.dontShowAgain(id))
|
||||||
.show();
|
.show();
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -135,9 +135,9 @@ public class BuyerStep2View extends TradeStepView {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getWarningText() {
|
protected String getWarningText() {
|
||||||
setWarningState();
|
setWarningHeadline();
|
||||||
return "You still have not done your " + model.getCurrencyCode() + " payment!\n" +
|
return "You still have not done your " + model.getCurrencyCode() + " payment!\n" +
|
||||||
"Please not that the trade has to be completed until " +
|
"Please note that the trade has to be completed until " +
|
||||||
model.getOpenDisputeTimeAsFormattedDate() +
|
model.getOpenDisputeTimeAsFormattedDate() +
|
||||||
" otherwise the trade will be investigated by the arbitrator.";
|
" otherwise the trade will be investigated by the arbitrator.";
|
||||||
}
|
}
|
||||||
|
@ -150,9 +150,8 @@ public class BuyerStep2View extends TradeStepView {
|
||||||
@Override
|
@Override
|
||||||
protected String getOpenForDisputeText() {
|
protected String getOpenForDisputeText() {
|
||||||
return "You have not completed your payment!\n" +
|
return "You have not completed your payment!\n" +
|
||||||
"The max. period for the trade has elapsed (" +
|
"The max. period for the trade has elapsed.\n" +
|
||||||
model.getOpenDisputeTimeAsFormattedDate() + ")." +
|
"\nPlease contact the arbitrator for opening a dispute.";
|
||||||
"\nPlease contact now the arbitrator for opening a dispute.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -205,10 +204,10 @@ public class BuyerStep2View extends TradeStepView {
|
||||||
|
|
||||||
// In case the first send failed we got the support button displayed.
|
// In case the first send failed we got the support button displayed.
|
||||||
// If it succeeds at a second try we remove the support button again.
|
// If it succeeds at a second try we remove the support button again.
|
||||||
if (openDisputeButton != null) {
|
//TODO check for support. in case of a dispute we dont want to hid ethe button
|
||||||
openDisputeButton.setVisible(false);
|
/*if (notificationGroup != null) {
|
||||||
openDisputeButton.setManaged(false);
|
notificationGroup.setButtonVisible(false);
|
||||||
}
|
}*/
|
||||||
}, errorMessage -> {
|
}, errorMessage -> {
|
||||||
removeStatusProgressIndicator();
|
removeStatusProgressIndicator();
|
||||||
statusLabel.setText("Sending message to your trading partner failed.\n" +
|
statusLabel.setText("Sending message to your trading partner failed.\n" +
|
||||||
|
|
|
@ -55,7 +55,7 @@ public class BuyerStep3View extends TradeStepView {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getWarningText() {
|
protected String getWarningText() {
|
||||||
setInformationState();
|
setInformationHeadline();
|
||||||
String substitute = model.isBlockChainMethod() ?
|
String substitute = model.isBlockChainMethod() ?
|
||||||
"on the " + model.getCurrencyCode() + "blockchain" :
|
"on the " + model.getCurrencyCode() + "blockchain" :
|
||||||
"at your payment provider (e.g. bank)";
|
"at your payment provider (e.g. bank)";
|
||||||
|
@ -74,9 +74,8 @@ public class BuyerStep3View extends TradeStepView {
|
||||||
@Override
|
@Override
|
||||||
protected String getOpenForDisputeText() {
|
protected String getOpenForDisputeText() {
|
||||||
return "The seller has not confirmed your payment!\n" +
|
return "The seller has not confirmed your payment!\n" +
|
||||||
"The max. period for the trade has elapsed (" +
|
"The max. period for the trade has elapsed.\n" +
|
||||||
model.getOpenDisputeTimeAsFormattedDate() +
|
"Please contact the arbitrator for opening a dispute.";
|
||||||
") and you need to contact now the arbitrator to investigate the problem.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -19,7 +19,6 @@ package io.bitsquare.gui.main.portfolio.pendingtrades.steps.buyer;
|
||||||
|
|
||||||
import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel;
|
import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel;
|
||||||
import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeStepView;
|
import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeStepView;
|
||||||
import io.bitsquare.gui.util.Layout;
|
|
||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
import org.bitcoinj.core.*;
|
import org.bitcoinj.core.*;
|
||||||
|
@ -76,6 +75,7 @@ public class BuyerStep4View extends TradeStepView {
|
||||||
super.doActivate();
|
super.doActivate();
|
||||||
|
|
||||||
model.addBlockChainListener(blockChainListener);
|
model.addBlockChainListener(blockChainListener);
|
||||||
|
updateDateFromBlockHeight(model.getBestChainHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -93,9 +93,9 @@ public class BuyerStep4View extends TradeStepView {
|
||||||
@Override
|
@Override
|
||||||
protected void addContent() {
|
protected void addContent() {
|
||||||
addTradeInfoBlock();
|
addTradeInfoBlock();
|
||||||
blockTextField = addLabelTextField(gridPane, gridRow, "Block(s) to wait until lock time elapsed:", "", Layout.FIRST_ROW_DISTANCE).second;
|
blockTextField = addLabelTextField(gridPane, gridRow, "Block(s) to wait until lock time elapsed:", "").second;
|
||||||
timeTextField = addLabelTextField(gridPane, ++gridRow, "Approx. date when payout gets unlocked:").second;
|
timeTextField = addLabelTextField(gridPane, ++gridRow, "Approx. date when payout gets unlocked:").second;
|
||||||
GridPane.setRowSpan(tradeInfoTitledGroupBg, 4);
|
GridPane.setRowSpan(tradeInfoTitledGroupBg, 5);
|
||||||
|
|
||||||
addInfoBlock();
|
addInfoBlock();
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ public class BuyerStep4View extends TradeStepView {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getWarningText() {
|
protected String getWarningText() {
|
||||||
setInformationState();
|
setInformationHeadline();
|
||||||
return "The payout transaction is still blocked by the lock time!\n" +
|
return "The payout transaction is still blocked by the lock time!\n" +
|
||||||
"If the trade has not been completed on " +
|
"If the trade has not been completed on " +
|
||||||
model.getOpenDisputeTimeAsFormattedDate() +
|
model.getOpenDisputeTimeAsFormattedDate() +
|
||||||
|
|
|
@ -23,6 +23,7 @@ import io.bitsquare.common.util.Tuple2;
|
||||||
import io.bitsquare.gui.components.InputTextField;
|
import io.bitsquare.gui.components.InputTextField;
|
||||||
import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel;
|
import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel;
|
||||||
import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeStepView;
|
import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeStepView;
|
||||||
|
import io.bitsquare.gui.popups.Popup;
|
||||||
import io.bitsquare.gui.util.Layout;
|
import io.bitsquare.gui.util.Layout;
|
||||||
import javafx.beans.value.ChangeListener;
|
import javafx.beans.value.ChangeListener;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
|
@ -77,6 +78,8 @@ public class BuyerStep5View extends TradeStepView {
|
||||||
UserThread.execute(() -> withdrawAddressTextField.requestFocus());
|
UserThread.execute(() -> withdrawAddressTextField.requestFocus());
|
||||||
});*/
|
});*/
|
||||||
});
|
});
|
||||||
|
|
||||||
|
hideNotificationGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -113,22 +116,31 @@ public class BuyerStep5View extends TradeStepView {
|
||||||
withdrawAddressTextField = addLabelInputTextField(gridPane, ++gridRow, "Withdraw to address:").second;
|
withdrawAddressTextField = addLabelInputTextField(gridPane, ++gridRow, "Withdraw to address:").second;
|
||||||
withdrawButton = addButtonAfterGroup(gridPane, ++gridRow, "Withdraw to external wallet");
|
withdrawButton = addButtonAfterGroup(gridPane, ++gridRow, "Withdraw to external wallet");
|
||||||
withdrawButton.setOnAction(e -> {
|
withdrawButton.setOnAction(e -> {
|
||||||
model.onWithdrawRequest(withdrawAddressTextField.getText());
|
|
||||||
withdrawButton.setDisable(true);
|
withdrawButton.setDisable(true);
|
||||||
|
model.dataModel.onWithdrawRequest(withdrawAddressTextField.getText(),
|
||||||
|
() -> {
|
||||||
|
String id = "TradeCompletedInfoPopup";
|
||||||
|
if (preferences.showAgain(id)) {
|
||||||
|
new Popup()
|
||||||
|
.information("You can review your completed trades under \"Portfolio/History\" or " +
|
||||||
|
"review your transactions under \"Funds/Transactions\"")
|
||||||
|
.dontShowAgainId(id, preferences)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
withdrawButton.setDisable(true);
|
||||||
|
},
|
||||||
|
(errorMessage, throwable) -> {
|
||||||
|
withdrawButton.setDisable(false);
|
||||||
|
if (throwable == null)
|
||||||
|
new Popup().warning(errorMessage).show();
|
||||||
|
else
|
||||||
|
new Popup().error("An error occurred:\n" + throwable.getMessage()).show();
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (BitsquareApp.DEV_MODE)
|
if (BitsquareApp.DEV_MODE)
|
||||||
withdrawAddressTextField.setText("mxAkWWaQBqwqcYstKzqLku3kzR6pbu2zHq");
|
withdrawAddressTextField.setText("mhpVDvMjJT1Gn7da44dkq1HXd3wXdFZpXu");
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Warning
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getWarningText() {
|
|
||||||
setInformationState();
|
|
||||||
return "The trade took a bit longer as expected but has been completed successfully in the allowed trade period.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -56,8 +56,8 @@ public class SellerStep2View extends TradeStepView {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getWarningText() {
|
protected String getWarningText() {
|
||||||
setInformationState();
|
setInformationHeadline();
|
||||||
return "The buyer still has not done the " + model.getCurrencyCode() + " payment!\n" +
|
return "The buyer still has not done the " + model.getCurrencyCode() + " payment.\n" +
|
||||||
"You need to wait until he starts the payment.\n" +
|
"You need to wait until he starts the payment.\n" +
|
||||||
"If the trade has not been completed on " +
|
"If the trade has not been completed on " +
|
||||||
model.getOpenDisputeTimeAsFormattedDate() +
|
model.getOpenDisputeTimeAsFormattedDate() +
|
||||||
|
|
|
@ -122,7 +122,7 @@ public class SellerStep3View extends TradeStepView {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getWarningText() {
|
protected String getWarningText() {
|
||||||
setWarningState();
|
setWarningHeadline();
|
||||||
String substitute = model.isBlockChainMethod() ?
|
String substitute = model.isBlockChainMethod() ?
|
||||||
"on the " + model.getCurrencyCode() + "blockchain" :
|
"on the " + model.getCurrencyCode() + "blockchain" :
|
||||||
"at your payment provider (e.g. bank)";
|
"at your payment provider (e.g. bank)";
|
||||||
|
@ -141,9 +141,8 @@ public class SellerStep3View extends TradeStepView {
|
||||||
@Override
|
@Override
|
||||||
protected String getOpenForDisputeText() {
|
protected String getOpenForDisputeText() {
|
||||||
return "You have not confirmed the receipt of the payment!\n" +
|
return "You have not confirmed the receipt of the payment!\n" +
|
||||||
"The max. period for the trade has elapsed (" +
|
"The max. period for the trade has elapsed.\n" +
|
||||||
model.getOpenDisputeTimeAsFormattedDate() + ")." +
|
"Please contact the arbitrator for opening a dispute.";
|
||||||
"\nPlease contact now the arbitrator for opening a dispute.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -54,7 +54,7 @@ public class SellerStep4bView extends TradeStepView {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getWarningText() {
|
protected String getWarningText() {
|
||||||
setInformationState();
|
setInformationHeadline();
|
||||||
return "The trading peer has not finalized the payout transaction!\n" +
|
return "The trading peer has not finalized the payout transaction!\n" +
|
||||||
"He might be offline. You need to wait until he finalizes the payout transaction.\n" +
|
"He might be offline. You need to wait until he finalizes the payout transaction.\n" +
|
||||||
"If the trade has not been completed on " +
|
"If the trade has not been completed on " +
|
||||||
|
@ -70,9 +70,8 @@ public class SellerStep4bView extends TradeStepView {
|
||||||
@Override
|
@Override
|
||||||
protected String getOpenForDisputeText() {
|
protected String getOpenForDisputeText() {
|
||||||
return "The trading peer has not finalized the payout transaction!\n" +
|
return "The trading peer has not finalized the payout transaction!\n" +
|
||||||
"The max. period for the trade has elapsed (" +
|
"The max. period for the trade has elapsed.\n" +
|
||||||
model.getOpenDisputeTimeAsFormattedDate() + ").\n" +
|
"Please contact the arbitrator for opening a dispute.";
|
||||||
"Please contact now the arbitrator for opening a dispute.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
package io.bitsquare.gui.popups;
|
package io.bitsquare.gui.popups;
|
||||||
|
|
||||||
|
import io.bitsquare.common.crypto.KeyRing;
|
||||||
import io.bitsquare.common.util.Tuple2;
|
import io.bitsquare.common.util.Tuple2;
|
||||||
import io.bitsquare.gui.Navigation;
|
import io.bitsquare.gui.Navigation;
|
||||||
import io.bitsquare.gui.main.MainView;
|
import io.bitsquare.gui.main.MainView;
|
||||||
|
@ -52,6 +53,7 @@ public class OfferDetailsPopup extends Popup {
|
||||||
private final BSFormatter formatter;
|
private final BSFormatter formatter;
|
||||||
private final Preferences preferences;
|
private final Preferences preferences;
|
||||||
private final User user;
|
private final User user;
|
||||||
|
private KeyRing keyRing;
|
||||||
private final Navigation navigation;
|
private final Navigation navigation;
|
||||||
private Offer offer;
|
private Offer offer;
|
||||||
private Coin tradeAmount;
|
private Coin tradeAmount;
|
||||||
|
@ -64,10 +66,11 @@ public class OfferDetailsPopup extends Popup {
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public OfferDetailsPopup(BSFormatter formatter, Preferences preferences, User user, Navigation navigation) {
|
public OfferDetailsPopup(BSFormatter formatter, Preferences preferences, User user, KeyRing keyRing, Navigation navigation) {
|
||||||
this.formatter = formatter;
|
this.formatter = formatter;
|
||||||
this.preferences = preferences;
|
this.preferences = preferences;
|
||||||
this.user = user;
|
this.user = user;
|
||||||
|
this.keyRing = keyRing;
|
||||||
this.navigation = navigation;
|
this.navigation = navigation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,6 +142,9 @@ public class OfferDetailsPopup extends Popup {
|
||||||
addLabelTextField(gridPane, ++rowIndex, "Amount:", formatter.formatCoinWithCode(offer.getAmount()));
|
addLabelTextField(gridPane, ++rowIndex, "Amount:", formatter.formatCoinWithCode(offer.getAmount()));
|
||||||
addLabelTextField(gridPane, ++rowIndex, "Min. amount:", formatter.formatCoinWithCode(offer.getMinAmount()));
|
addLabelTextField(gridPane, ++rowIndex, "Min. amount:", formatter.formatCoinWithCode(offer.getMinAmount()));
|
||||||
}
|
}
|
||||||
|
if (offer.isMyOffer(keyRing) && user.getPaymentAccount(offer.getOffererPaymentAccountId()) != null)
|
||||||
|
addLabelTextField(gridPane, ++rowIndex, "Payment account:", user.getPaymentAccount(offer.getOffererPaymentAccountId()).getAccountName());
|
||||||
|
else
|
||||||
addLabelTextField(gridPane, ++rowIndex, "Payment method:", BSResources.get(offer.getPaymentMethod().getId()));
|
addLabelTextField(gridPane, ++rowIndex, "Payment method:", BSResources.get(offer.getPaymentMethod().getId()));
|
||||||
|
|
||||||
rows = 3;
|
rows = 3;
|
||||||
|
|
|
@ -118,6 +118,14 @@ public class Popup {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Popup notification(String message) {
|
||||||
|
// TODO use icons
|
||||||
|
this.headLine = "Notification";
|
||||||
|
this.message = message;
|
||||||
|
setTruncatedMessage();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Popup information(String message) {
|
public Popup information(String message) {
|
||||||
this.headLine = "Information";
|
this.headLine = "Information";
|
||||||
this.message = message;
|
this.message = message;
|
||||||
|
@ -219,7 +227,7 @@ public class Popup {
|
||||||
scene.getStylesheets().setAll(owner.getScene().getStylesheets());
|
scene.getStylesheets().setAll(owner.getScene().getStylesheets());
|
||||||
scene.setFill(Color.TRANSPARENT);
|
scene.setFill(Color.TRANSPARENT);
|
||||||
stage.setScene(scene);
|
stage.setScene(scene);
|
||||||
stage.initModality(Modality.APPLICATION_MODAL);
|
stage.initModality(Modality.WINDOW_MODAL);
|
||||||
stage.initStyle(StageStyle.TRANSPARENT);
|
stage.initStyle(StageStyle.TRANSPARENT);
|
||||||
stage.initOwner(owner.getScene().getWindow());
|
stage.initOwner(owner.getScene().getWindow());
|
||||||
stage.show();
|
stage.show();
|
||||||
|
@ -317,10 +325,11 @@ public class Popup {
|
||||||
|
|
||||||
private void addDontShowAgainCheckBox() {
|
private void addDontShowAgainCheckBox() {
|
||||||
if (dontShowAgainId != null && preferences != null) {
|
if (dontShowAgainId != null && preferences != null) {
|
||||||
CheckBox dontShowAgain = addCheckBox(gridPane, ++rowIndex, "Don't show again", 10);
|
CheckBox dontShowAgainCheckBox = addCheckBox(gridPane, rowIndex, "Don't show again", 30);
|
||||||
GridPane.setHalignment(dontShowAgain, HPos.RIGHT);
|
GridPane.setColumnIndex(dontShowAgainCheckBox, 0);
|
||||||
dontShowAgain.setOnAction(e -> {
|
GridPane.setHalignment(dontShowAgainCheckBox, HPos.LEFT);
|
||||||
if (dontShowAgain.isSelected())
|
dontShowAgainCheckBox.setOnAction(e -> {
|
||||||
|
if (dontShowAgainCheckBox.isSelected())
|
||||||
preferences.dontShowAgain(dontShowAgainId);
|
preferences.dontShowAgain(dontShowAgainId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -352,7 +361,7 @@ public class Popup {
|
||||||
GridPane.setHalignment(hBox, HPos.RIGHT);
|
GridPane.setHalignment(hBox, HPos.RIGHT);
|
||||||
GridPane.setRowIndex(hBox, ++rowIndex);
|
GridPane.setRowIndex(hBox, ++rowIndex);
|
||||||
GridPane.setColumnSpan(hBox, 2);
|
GridPane.setColumnSpan(hBox, 2);
|
||||||
GridPane.setMargin(hBox, new Insets(20, 0, 0, 0));
|
GridPane.setMargin(hBox, new Insets(30, 0, 0, 0));
|
||||||
gridPane.getChildren().add(hBox);
|
gridPane.getChildren().add(hBox);
|
||||||
} else {
|
} else {
|
||||||
closeButton.setDefaultButton(true);
|
closeButton.setDefaultButton(true);
|
||||||
|
@ -366,8 +375,8 @@ public class Popup {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setTruncatedMessage() {
|
protected void setTruncatedMessage() {
|
||||||
if (message != null && message.length() > 800)
|
if (message != null && message.length() > 900)
|
||||||
truncatedMessage = StringUtils.abbreviate(message, 800);
|
truncatedMessage = StringUtils.abbreviate(message, 900);
|
||||||
else
|
else
|
||||||
truncatedMessage = message;
|
truncatedMessage = message;
|
||||||
}
|
}
|
||||||
|
|
|
@ -577,23 +577,20 @@ public class FormBuilder {
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public static Button addButton(GridPane gridPane, int rowIndex, String title) {
|
public static Button addButton(GridPane gridPane, int rowIndex, String title) {
|
||||||
Button button = new Button(title);
|
return addButton(gridPane, rowIndex, title, 0);
|
||||||
button.setDefaultButton(true);
|
|
||||||
GridPane.setRowIndex(button, rowIndex);
|
|
||||||
GridPane.setColumnIndex(button, 1);
|
|
||||||
gridPane.getChildren().add(button);
|
|
||||||
return button;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Button addButtonAfterGroup(GridPane gridPane,
|
public static Button addButtonAfterGroup(GridPane gridPane, int rowIndex, String title) {
|
||||||
int rowIndex,
|
return addButton(gridPane, rowIndex, title, 15);
|
||||||
String title) {
|
}
|
||||||
|
|
||||||
|
public static Button addButton(GridPane gridPane, int rowIndex, String title, double top) {
|
||||||
Button button = new Button(title);
|
Button button = new Button(title);
|
||||||
button.setDefaultButton(true);
|
button.setDefaultButton(true);
|
||||||
GridPane.setRowIndex(button, rowIndex);
|
GridPane.setRowIndex(button, rowIndex);
|
||||||
GridPane.setColumnIndex(button, 1);
|
GridPane.setColumnIndex(button, 1);
|
||||||
GridPane.setMargin(button, new Insets(15, 0, 0, 0));
|
|
||||||
gridPane.getChildren().add(button);
|
gridPane.getChildren().add(button);
|
||||||
|
GridPane.setMargin(button, new Insets(top, 0, 0, 0));
|
||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue