mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-23 23:06:39 +01: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);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -52,5 +52,6 @@
|
|||
<version>4.8</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -60,6 +60,11 @@ public class FeePolicy {
|
|||
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
|
||||
public static Coin getCreateOfferFee() {
|
||||
|
|
|
@ -53,7 +53,6 @@ import java.util.*;
|
|||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
@ -90,7 +89,6 @@ public class WalletService {
|
|||
private final IntegerProperty numPeers = new SimpleIntegerProperty(0);
|
||||
private final ObjectProperty<List<Peer>> connectedPeers = new SimpleObjectProperty<>();
|
||||
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(
|
||||
OK_PAY = new PaymentMethod(OK_PAY_ID, 0, DAY), // tx instant so min. wait time
|
||||
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),
|
||||
ALI_PAY = new PaymentMethod(ALI_PAY_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
|
||||
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 int takeOfferDateAsBlockHeight;
|
||||
private Coin tradeAmount;
|
||||
private NodeAddress tradingPeerNodeAddress;
|
||||
protected State state;
|
||||
|
@ -164,8 +165,6 @@ abstract public class Trade implements Tradable, Model, Serializable {
|
|||
private int checkPaymentTimeAsBlockHeight;
|
||||
private NodeAddress arbitratorNodeAddress;
|
||||
private String takerPaymentAccountId;
|
||||
private boolean halfTradePeriodReachedWarningDisplayed;
|
||||
private boolean tradePeriodOverWarningDisplayed;
|
||||
private String errorMessage;
|
||||
transient private StringProperty errorMessageProperty;
|
||||
transient private ObjectProperty<Coin> tradeAmountProperty;
|
||||
|
@ -418,6 +417,14 @@ abstract public class Trade implements Tradable, Model, Serializable {
|
|||
this.takeOfferDate = takeOfferDate;
|
||||
}
|
||||
|
||||
public int getTakeOfferDateAsBlockHeight() {
|
||||
return takeOfferDateAsBlockHeight;
|
||||
}
|
||||
|
||||
public void setTakeOfferDateAsBlockHeight(int blockHeight) {
|
||||
takeOfferDateAsBlockHeight = blockHeight;
|
||||
}
|
||||
|
||||
public void setTradingPeerNodeAddress(NodeAddress tradingPeerNodeAddress) {
|
||||
if (tradingPeerNodeAddress == null)
|
||||
log.error("tradingPeerAddress=null");
|
||||
|
@ -536,24 +543,6 @@ abstract public class Trade implements Tradable, Model, Serializable {
|
|||
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) {
|
||||
this.contractHash = contractHash;
|
||||
}
|
||||
|
@ -638,8 +627,6 @@ abstract public class Trade implements Tradable, Model, Serializable {
|
|||
"\n\tcheckPaymentTimeAsBlockHeight=" + checkPaymentTimeAsBlockHeight +
|
||||
"\n\tarbitratorNodeAddress=" + arbitratorNodeAddress +
|
||||
"\n\ttakerPaymentAccountId='" + takerPaymentAccountId + '\'' +
|
||||
"\n\thalfTradePeriodReachedWarningDisplayed=" + halfTradePeriodReachedWarningDisplayed +
|
||||
"\n\ttradePeriodOverWarningDisplayed=" + tradePeriodOverWarningDisplayed +
|
||||
"\n\terrorMessage='" + errorMessage + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
|
|
@ -281,6 +281,7 @@ public class TradeManager {
|
|||
trade = new BuyerAsTakerTrade(offer, amount, model.getPeerNodeAddress(), tradableListStorage);
|
||||
|
||||
trade.setTakeOfferDate(new Date());
|
||||
trade.setTakeOfferDateAsBlockHeight(tradeWalletService.getBestChainHeight());
|
||||
trade.setTakerPaymentAccountId(paymentAccountId);
|
||||
|
||||
initTrade(trade);
|
||||
|
@ -382,8 +383,11 @@ public class TradeManager {
|
|||
return offer.isMyOffer(keyRing);
|
||||
}
|
||||
|
||||
public boolean isMyOfferInBtcBuyerRole(Offer offer) {
|
||||
return !(isMyOffer(offer) ^ offer.getDirection() == Offer.Direction.BUY);
|
||||
}
|
||||
|
||||
public Optional<Trade> getTradeById(String tradeId) {
|
||||
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,
|
||||
() -> handleTaskRunnerSuccess("handle DepositTxPublishedMessage"),
|
||||
this::handleTaskRunnerFault);
|
||||
taskRunner.addTasks(
|
||||
ProcessDepositTxPublishedMessage.class,
|
||||
AddDepositTxToWallet.class
|
||||
);
|
||||
taskRunner.addTasks(ProcessDepositTxPublishedMessage.class);
|
||||
taskRunner.run();
|
||||
}
|
||||
|
||||
|
|
|
@ -132,10 +132,7 @@ public class SellerAsOffererProtocol extends TradeProtocol implements SellerProt
|
|||
() -> handleTaskRunnerSuccess("DepositTxPublishedMessage"),
|
||||
this::handleTaskRunnerFault);
|
||||
|
||||
taskRunner.addTasks(
|
||||
ProcessDepositTxPublishedMessage.class,
|
||||
AddDepositTxToWallet.class
|
||||
);
|
||||
taskRunner.addTasks(ProcessDepositTxPublishedMessage.class);
|
||||
taskRunner.run();
|
||||
}
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@ public class SignAndPublishDepositTxAsBuyer extends TradeTask {
|
|||
|
||||
trade.setDepositTx(transaction);
|
||||
trade.setTakeOfferDate(new Date());
|
||||
trade.setTakeOfferDateAsBlockHeight(processModel.getTradeWalletService().getBestChainHeight());
|
||||
trade.setState(Trade.State.DEPOSIT_PUBLISHED);
|
||||
|
||||
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.protocol.trade.messages.DepositTxPublishedMessage;
|
||||
import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -47,9 +48,15 @@ public class ProcessDepositTxPublishedMessage extends TradeTask {
|
|||
checkTradeId(processModel.getId(), message);
|
||||
checkNotNull(message);
|
||||
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.setTakeOfferDate(new Date());
|
||||
trade.setTakeOfferDateAsBlockHeight(processModel.getTradeWalletService().getBestChainHeight());
|
||||
|
||||
if (trade instanceof OffererTrade)
|
||||
processModel.getOpenOfferManager().closeOpenOffer(trade.getOffer());
|
||||
|
|
|
@ -63,6 +63,7 @@ public class SignAndPublishDepositTxAsSeller extends TradeTask {
|
|||
|
||||
trade.setDepositTx(transaction);
|
||||
trade.setTakeOfferDate(new Date());
|
||||
trade.setTakeOfferDateAsBlockHeight(processModel.getTradeWalletService().getBestChainHeight());
|
||||
trade.setState(Trade.State.DEPOSIT_PUBLISHED);
|
||||
|
||||
complete();
|
||||
|
|
|
@ -21,6 +21,8 @@ import io.bitsquare.app.BitsquareEnvironment;
|
|||
import io.bitsquare.app.Version;
|
||||
import io.bitsquare.btc.BitcoinNetwork;
|
||||
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.CurrencyUtil;
|
||||
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("Biteasy", "https://www.biteasy.com/transactions/", "https://www.biteasy.com/addresses/")
|
||||
));
|
||||
private BlockchainApiProvider blockchainApiProvider;
|
||||
|
||||
public static List<String> getBtcDenominations() {
|
||||
return BTC_DENOMINATIONS;
|
||||
}
|
||||
|
||||
private static Locale defaultLocale = Locale.getDefault();
|
||||
//TODO test with other locales
|
||||
//private static Locale defaultLocale = Locale.US;
|
||||
|
||||
public static Locale getDefaultLocale() {
|
||||
return defaultLocale;
|
||||
|
@ -91,7 +96,6 @@ public class Preferences implements Serializable {
|
|||
private String btcDenomination = MonetaryFormat.CODE_BTC;
|
||||
private boolean useAnimations = true;
|
||||
private boolean useEffects = true;
|
||||
private boolean displaySecurityDepositInfo = true;
|
||||
private final ArrayList<TradeCurrency> tradeCurrencies;
|
||||
private BlockChainExplorer blockChainExplorerMainNet;
|
||||
private BlockChainExplorer blockChainExplorerTestNet;
|
||||
|
@ -130,7 +134,6 @@ public class Preferences implements Serializable {
|
|||
setUseEffects(persisted.useEffects);
|
||||
setTradeCurrencies(persisted.tradeCurrencies);
|
||||
tradeCurrencies = new ArrayList<>(tradeCurrenciesAsObservable);
|
||||
displaySecurityDepositInfo = persisted.getDisplaySecurityDepositInfo();
|
||||
|
||||
setBlockChainExplorerTestNet(persisted.getBlockChainExplorerTestNet());
|
||||
setBlockChainExplorerMainNet(persisted.getBlockChainExplorerMainNet());
|
||||
|
@ -152,6 +155,8 @@ public class Preferences implements Serializable {
|
|||
preferredTradeCurrency = persisted.getPreferredTradeCurrency();
|
||||
defaultTradeCurrency = preferredTradeCurrency;
|
||||
useTorForBitcoinJ = persisted.getUseTorForBitcoinJ();
|
||||
|
||||
blockchainApiProvider = persisted.getBlockchainApiProvider();
|
||||
|
||||
try {
|
||||
setTxFeePerKB(persisted.getTxFeePerKB());
|
||||
|
@ -175,6 +180,8 @@ public class Preferences implements Serializable {
|
|||
preferredLocale = getDefaultLocale();
|
||||
preferredTradeCurrency = getDefaultTradeCurrency();
|
||||
|
||||
blockchainApiProvider = new BlockrIOProvider();
|
||||
|
||||
storage.queueUpForSave();
|
||||
}
|
||||
|
||||
|
@ -223,11 +230,6 @@ public class Preferences implements Serializable {
|
|||
this.useEffectsProperty.set(useEffectsProperty);
|
||||
}
|
||||
|
||||
public void setDisplaySecurityDepositInfo(boolean displaySecurityDepositInfo) {
|
||||
this.displaySecurityDepositInfo = displaySecurityDepositInfo;
|
||||
storage.queueUpForSave(2000);
|
||||
}
|
||||
|
||||
public void setBitcoinNetwork(BitcoinNetwork bitcoinNetwork) {
|
||||
if (this.bitcoinNetwork != bitcoinNetwork)
|
||||
bitsquareEnvironment.saveBitcoinNetwork(bitcoinNetwork);
|
||||
|
@ -302,6 +304,10 @@ public class Preferences implements Serializable {
|
|||
storage.queueUpForSave();
|
||||
}
|
||||
|
||||
public void setBlockchainApiProvider(BlockchainApiProvider blockchainApiProvider) {
|
||||
this.blockchainApiProvider = blockchainApiProvider;
|
||||
storage.queueUpForSave();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Getter
|
||||
|
@ -319,10 +325,6 @@ public class Preferences implements Serializable {
|
|||
return useAnimationsProperty.get();
|
||||
}
|
||||
|
||||
public boolean getDisplaySecurityDepositInfo() {
|
||||
return displaySecurityDepositInfo;
|
||||
}
|
||||
|
||||
public StringProperty btcDenominationProperty() {
|
||||
return btcDenominationProperty;
|
||||
}
|
||||
|
@ -425,4 +427,9 @@ public class Preferences implements Serializable {
|
|||
public boolean getUseTorForBitcoinJ() {
|
||||
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 {
|
||||
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;
|
||||
|
||||
private static Environment env;
|
||||
|
|
|
@ -585,12 +585,14 @@ textfield */
|
|||
-fx-text-fill: -bs-grey;
|
||||
-fx-body-color: linear-gradient(to bottom, -bs-content-bg-grey, #F0F0F0);
|
||||
-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-outer-border,
|
||||
-fx-inner-border,
|
||||
-fx-body-color;
|
||||
-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 {
|
||||
|
@ -598,23 +600,27 @@ textfield */
|
|||
-fx-font-size: 14;
|
||||
-fx-body-color: linear-gradient(to bottom, #f1f6f7, #e7f5f9);
|
||||
-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-outer-border,
|
||||
-fx-inner-border,
|
||||
-fx-body-color;
|
||||
-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 {
|
||||
-fx-body-color: linear-gradient(to bottom, -bs-content-bg-grey, #E1E9E1);
|
||||
-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-outer-border,
|
||||
-fx-inner-border,
|
||||
-fx-body-color;
|
||||
-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 {
|
||||
|
|
|
@ -30,7 +30,6 @@ public class HyperlinkWithIcon extends HBox {
|
|||
|
||||
icon = new Label();
|
||||
icon.getStyleClass().add("external-link-icon");
|
||||
|
||||
AwesomeDude.setIcon(icon, awesomeIcon);
|
||||
icon.setMinWidth(20);
|
||||
icon.setOpacity(0.7);
|
||||
|
|
|
@ -23,7 +23,6 @@ import io.bitsquare.common.UserThread;
|
|||
import io.bitsquare.common.util.Tuple2;
|
||||
import io.bitsquare.gui.Navigation;
|
||||
import io.bitsquare.gui.common.view.*;
|
||||
import io.bitsquare.gui.components.SystemNotification;
|
||||
import io.bitsquare.gui.main.account.AccountView;
|
||||
import io.bitsquare.gui.main.disputes.DisputesView;
|
||||
import io.bitsquare.gui.main.funds.FundsView;
|
||||
|
@ -454,10 +453,10 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
|||
notification.visibleProperty().bind(model.showPendingTradesNotification);
|
||||
buttonHolder.getChildren().add(notification);
|
||||
|
||||
model.showPendingTradesNotification.addListener((ov, oldValue, newValue) -> {
|
||||
/* model.showPendingTradesNotification.addListener((ov, oldValue, newValue) -> {
|
||||
if (newValue)
|
||||
SystemNotification.openInfoNotification(title, "You received a new trade message.");
|
||||
});
|
||||
});*/
|
||||
}
|
||||
|
||||
private void setupDisputesIcon(Pane buttonHolder) {
|
||||
|
@ -478,10 +477,10 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
|||
notification.visibleProperty().bind(model.showOpenDisputesNotification);
|
||||
buttonHolder.getChildren().add(notification);
|
||||
|
||||
model.showOpenDisputesNotification.addListener((ov, oldValue, newValue) -> {
|
||||
/* model.showOpenDisputesNotification.addListener((ov, oldValue, newValue) -> {
|
||||
if (newValue)
|
||||
SystemNotification.openInfoNotification(title, "You received a dispute message.");
|
||||
});
|
||||
});*/
|
||||
}
|
||||
|
||||
private class NavButton extends ToggleButton {
|
||||
|
|
|
@ -29,10 +29,14 @@ import io.bitsquare.arbitration.DisputeManager;
|
|||
import io.bitsquare.btc.*;
|
||||
import io.bitsquare.btc.listeners.BalanceListener;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.gui.Navigation;
|
||||
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.BalanceWithConfirmationTextField;
|
||||
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.Popup;
|
||||
import io.bitsquare.gui.popups.WalletPasswordPopup;
|
||||
|
@ -57,6 +61,7 @@ import javafx.collections.ListChangeListener;
|
|||
import org.bitcoinj.core.*;
|
||||
import org.bitcoinj.store.BlockStoreException;
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
import org.fxmisc.easybind.Subscription;
|
||||
import org.fxmisc.easybind.monadic.MonadicBinding;
|
||||
import org.reactfx.util.FxTimer;
|
||||
import org.reactfx.util.Timer;
|
||||
|
@ -85,6 +90,7 @@ public class MainViewModel implements ViewModel {
|
|||
private final Preferences preferences;
|
||||
private final AlertManager alertManager;
|
||||
private final WalletPasswordPopup walletPasswordPopup;
|
||||
private Navigation navigation;
|
||||
private final BSFormatter formatter;
|
||||
|
||||
// BTC network
|
||||
|
@ -135,7 +141,7 @@ public class MainViewModel implements ViewModel {
|
|||
ArbitratorManager arbitratorManager, P2PService p2PService, TradeManager tradeManager,
|
||||
OpenOfferManager openOfferManager, DisputeManager disputeManager, Preferences preferences,
|
||||
User user, AlertManager alertManager, WalletPasswordPopup walletPasswordPopup,
|
||||
BSFormatter formatter) {
|
||||
Navigation navigation, BSFormatter formatter) {
|
||||
this.user = user;
|
||||
this.walletService = walletService;
|
||||
this.tradeWalletService = tradeWalletService;
|
||||
|
@ -147,6 +153,7 @@ public class MainViewModel implements ViewModel {
|
|||
this.preferences = preferences;
|
||||
this.alertManager = alertManager;
|
||||
this.walletPasswordPopup = walletPasswordPopup;
|
||||
this.navigation = navigation;
|
||||
this.formatter = formatter;
|
||||
|
||||
btcNetworkAsString = formatter.formatBitcoinNetwork(preferences.getBitcoinNetwork()) +
|
||||
|
@ -362,10 +369,12 @@ public class MainViewModel implements ViewModel {
|
|||
tradeManager.getTrades().addListener((ListChangeListener<Trade>) change -> {
|
||||
change.next();
|
||||
addDisputeStateListeners(change.getAddedSubList());
|
||||
addTradeStateListeners(change.getAddedSubList());
|
||||
pendingTradesChanged();
|
||||
});
|
||||
pendingTradesChanged();
|
||||
addDisputeStateListeners(tradeManager.getTrades());
|
||||
addTradeStateListeners(tradeManager.getTrades());
|
||||
|
||||
|
||||
// arbitratorManager
|
||||
|
@ -653,25 +662,25 @@ public class MainViewModel implements ViewModel {
|
|||
case HALF_REACHED:
|
||||
id = "displayHalfTradePeriodOver" + trade.getId();
|
||||
if (preferences.showAgain(id)) {
|
||||
preferences.dontShowAgain(id);
|
||||
new Popup().warning("Your trade with ID " + trade.getShortId() +
|
||||
" has reached the half of the max. allowed trading period and " +
|
||||
"is still not completed.\n\n" +
|
||||
"The trade period ends on " + limitDate + "\n\n" +
|
||||
"Please check your trade state at \"Portfolio/Open trades\" for further information.")
|
||||
.onClose(() -> preferences.dontShowAgain(id))
|
||||
.show();
|
||||
}
|
||||
break;
|
||||
case TRADE_PERIOD_OVER:
|
||||
id = "displayTradePeriodOver" + trade.getId();
|
||||
if (preferences.showAgain(id)) {
|
||||
preferences.dontShowAgain(id);
|
||||
new Popup().warning("Your trade with ID " + trade.getShortId() +
|
||||
" has reached the max. allowed trading period and is " +
|
||||
"not completed.\n\n" +
|
||||
"The trade period ended on " + limitDate + "\n\n" +
|
||||
"Please check your trade at \"Portfolio/Open trades\" for contacting " +
|
||||
"the arbitrator.")
|
||||
.onClose(() -> preferences.dontShowAgain(id))
|
||||
.show();
|
||||
}
|
||||
break;
|
||||
|
@ -706,6 +715,142 @@ public class MainViewModel implements ViewModel {
|
|||
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) {
|
||||
addedTrades.stream().forEach(trade -> trade.disputeStateProperty().addListener((observable, oldValue, 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" +
|
||||
"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" +
|
||||
"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" +
|
||||
"For more background information please see the Bitsquare FAQ on our web page.";
|
||||
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");
|
||||
|
||||
if (BitsquareApp.DEV_MODE)
|
||||
withdrawToTextField.setText("mxAkWWaQBqwqcYstKzqLku3kzR6pbu2zHq");
|
||||
withdrawToTextField.setText("mhpVDvMjJT1Gn7da44dkq1HXd3wXdFZpXu");
|
||||
}
|
||||
|
||||
private Optional<Tradable> getTradable(WithdrawalListItem item) {
|
||||
|
|
|
@ -33,12 +33,12 @@ public class BuyOfferView extends OfferView {
|
|||
|
||||
@Override
|
||||
protected String getCreateOfferTabName() {
|
||||
return "Create offer for buying bitcoin";
|
||||
return "Create offer";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTakeOfferTabName() {
|
||||
return "Take offer for buying bitcoin";
|
||||
return "Take offer";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,12 +33,12 @@ public class SellOfferView extends OfferView {
|
|||
|
||||
@Override
|
||||
protected String getCreateOfferTabName() {
|
||||
return "Create offer for selling bitcoin";
|
||||
return "Create offer";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTakeOfferTabName() {
|
||||
return "Take offer for selling bitcoin";
|
||||
return "Take offer";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -165,11 +165,8 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
|||
|
||||
boolean isFeeFromFundingTxSufficient() {
|
||||
// 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) ||
|
||||
feeFromFundingTxProperty.get().compareTo(FeePolicy.getFeePerKb()) >= 0;
|
||||
feeFromFundingTxProperty.get().compareTo(FeePolicy.getMinFundingFee()) >= 0;
|
||||
}
|
||||
|
||||
private void addListeners() {
|
||||
|
@ -177,7 +174,7 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
|||
walletService.getWallet().addEventListener(new WalletEventListener() {
|
||||
@Override
|
||||
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
||||
requestFee(tx.getHashAsString());
|
||||
requestFeeFromBlockchain(tx.getHashAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -207,7 +204,7 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
|||
user.getPaymentAccountsAsObservable().addListener(paymentAccountsChangeListener);
|
||||
}
|
||||
|
||||
private void requestFee(String transactionId) {
|
||||
private void requestFeeFromBlockchain(String transactionId) {
|
||||
try {
|
||||
feeFromFundingTxProperty.set(preferences.getBlockchainApiProvider().getFee(transactionId));
|
||||
} catch (IOException | HttpException e) {
|
||||
|
@ -216,7 +213,7 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
|||
retryRequestFeeCounter++;
|
||||
log.warn("We try again after 5 seconds");
|
||||
// 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) {
|
||||
if (paymentAccount != null)
|
||||
this.paymentAccount = paymentAccount;
|
||||
|
@ -336,10 +328,6 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
|||
return addressEntry;
|
||||
}
|
||||
|
||||
boolean getDisplaySecurityDepositInfo() {
|
||||
return preferences.getDisplaySecurityDepositInfo();
|
||||
}
|
||||
|
||||
public TradeCurrency getTradeCurrency() {
|
||||
return tradeCurrency;
|
||||
}
|
||||
|
|
|
@ -229,16 +229,24 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
|
|||
|
||||
private void onShowFundsScreen() {
|
||||
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" +
|
||||
"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" +
|
||||
"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" +
|
||||
"You can see the details when you move the mouse over the question mark.").show();
|
||||
|
||||
model.onSecurityDepositInfoDisplayed();
|
||||
"You can see the details when you move the mouse over the question mark.\n\n" +
|
||||
"Important notice!\n" +
|
||||
"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()) {
|
||||
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 " +
|
||||
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 trade transactions might take too much time to be included in " +
|
||||
"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 {
|
||||
private final BtcValidator btcValidator;
|
||||
private final P2PService p2PService;
|
||||
private final BSFormatter formatter;
|
||||
final BSFormatter formatter;
|
||||
private final FiatValidator fiatValidator;
|
||||
|
||||
private String amountDescription;
|
||||
|
@ -322,10 +322,6 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
|
|||
isPlaceOfferButtonVisible.set(true);
|
||||
}
|
||||
|
||||
void onSecurityDepositInfoDisplayed() {
|
||||
dataModel.onSecurityDepositInfoDisplayed();
|
||||
}
|
||||
|
||||
public void onPaymentAccountSelected(PaymentAccount paymentAccount) {
|
||||
dataModel.onPaymentAccountSelected(paymentAccount);
|
||||
}
|
||||
|
@ -431,10 +427,6 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
|
|||
return formatter;
|
||||
}
|
||||
|
||||
boolean getDisplaySecurityDepositInfo() {
|
||||
return dataModel.getDisplaySecurityDepositInfo();
|
||||
}
|
||||
|
||||
boolean isSellOffer() {
|
||||
return dataModel.getDirection() == Offer.Direction.SELL;
|
||||
}
|
||||
|
|
|
@ -184,10 +184,6 @@ class TakeOfferDataModel extends ActivatableDataModel {
|
|||
);
|
||||
}
|
||||
|
||||
void onSecurityDepositInfoDisplayed() {
|
||||
preferences.setDisplaySecurityDepositInfo(false);
|
||||
}
|
||||
|
||||
public void onPaymentAccountSelected(PaymentAccount paymentAccount) {
|
||||
if (paymentAccount != null)
|
||||
this.paymentAccount = paymentAccount;
|
||||
|
@ -202,10 +198,6 @@ class TakeOfferDataModel extends ActivatableDataModel {
|
|||
return offer.getDirection();
|
||||
}
|
||||
|
||||
boolean getDisplaySecurityDepositInfo() {
|
||||
return preferences.getDisplaySecurityDepositInfo();
|
||||
}
|
||||
|
||||
public Offer getOffer() {
|
||||
return offer;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ package io.bitsquare.gui.main.offer.takeoffer;
|
|||
import de.jensd.fx.fontawesome.AwesomeDude;
|
||||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||
import io.bitsquare.app.BitsquareApp;
|
||||
import io.bitsquare.btc.FeePolicy;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.common.util.Tuple2;
|
||||
import io.bitsquare.common.util.Tuple3;
|
||||
|
@ -214,7 +215,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
|||
FxTimer.runLater(Duration.ofMillis(100),
|
||||
() -> {
|
||||
new Popup().information(BSResources.get("takeOffer.success.info"))
|
||||
.actionButtonText("Go to \"Open trades\"")
|
||||
.actionButtonText("Go to \"Portfolio/Open trades\"")
|
||||
.onAction(() -> {
|
||||
close();
|
||||
FxTimer.runLater(Duration.ofMillis(100),
|
||||
|
@ -335,17 +336,23 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
|||
|
||||
private void onShowPayFundsScreen() {
|
||||
if (!BitsquareApp.DEV_MODE) {
|
||||
if (model.getDisplaySecurityDepositInfo()) {
|
||||
MainView.blur();
|
||||
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" +
|
||||
"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 " +
|
||||
"Bitsquare trade wallet. In case you over pay, you will get it refunded after the trade.\n\n" +
|
||||
"The amount needed for funding is the sum of the trade amount, the security deposit, " +
|
||||
"the trading fee and the bitcoin mining fee.\n" +
|
||||
"You can see the details when you move the mouse over the question mark.").show();
|
||||
|
||||
model.onSecurityDepositInfoDisplayed();
|
||||
"Bitsquare trade wallet.\n" +
|
||||
"The amount is the sum of the trade amount, the security deposit, the trading fee and " +
|
||||
"the bitcoin mining fee.\n" +
|
||||
"You can see the details when you move the mouse over the question mark.\n\n" +
|
||||
"Important notice!\n" +
|
||||
"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 {
|
||||
private final BtcValidator btcValidator;
|
||||
private P2PService p2PService;
|
||||
private final BSFormatter formatter;
|
||||
final BSFormatter formatter;
|
||||
|
||||
private String amountRange;
|
||||
private String addressAsString;
|
||||
|
@ -194,10 +194,6 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
|||
dataModel.onPaymentAccountSelected(paymentAccount);
|
||||
}
|
||||
|
||||
void onSecurityDepositInfoDisplayed() {
|
||||
dataModel.onSecurityDepositInfoDisplayed();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Handle focus
|
||||
|
@ -471,10 +467,6 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
|||
return formatter;
|
||||
}
|
||||
|
||||
boolean getDisplaySecurityDepositInfo() {
|
||||
return dataModel.getDisplaySecurityDepositInfo();
|
||||
}
|
||||
|
||||
boolean isSeller() {
|
||||
return dataModel.getDirection() == Offer.Direction.BUY;
|
||||
}
|
||||
|
|
|
@ -61,10 +61,19 @@ public class BuyerSubView extends TradeSubView {
|
|||
step4 = new TradeWizardItem(BuyerStep4View.class, "Wait for payout unlock");
|
||||
step5 = new TradeWizardItem(BuyerStep5View.class, "Completed");
|
||||
|
||||
if (model.getLockTime() > 0)
|
||||
leftVBox.getChildren().setAll(step1, step2, step3, step4, step5);
|
||||
else
|
||||
leftVBox.getChildren().setAll(step1, step2, step3, step5);
|
||||
if (model.getLockTime() > 0) {
|
||||
addWizardsToGridPane(step1);
|
||||
addWizardsToGridPane(step2);
|
||||
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.TradeWalletService;
|
||||
import io.bitsquare.btc.WalletService;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.common.crypto.KeyRing;
|
||||
import io.bitsquare.common.handlers.ErrorMessageHandler;
|
||||
import io.bitsquare.common.handlers.FaultHandler;
|
||||
import io.bitsquare.common.handlers.ResultHandler;
|
||||
import io.bitsquare.gui.Navigation;
|
||||
import io.bitsquare.gui.common.model.ActivatableDataModel;
|
||||
import io.bitsquare.gui.main.MainView;
|
||||
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.WalletPasswordPopup;
|
||||
import io.bitsquare.payment.PaymentAccountContractData;
|
||||
|
@ -167,25 +164,29 @@ public class PendingTradesDataModel extends ActivatableDataModel {
|
|||
((SellerTrade) trade).onFiatPaymentReceived();
|
||||
}
|
||||
|
||||
void onWithdrawRequest(String toAddress) {
|
||||
public void onWithdrawRequest(String toAddress, ResultHandler resultHandler, FaultHandler faultHandler) {
|
||||
checkNotNull(trade, "trade must not be null");
|
||||
if (walletService.getWallet().isEncrypted()) {
|
||||
walletPasswordPopup.onAesKey(aesKey -> doWithdrawRequest(toAddress, aesKey)).show();
|
||||
walletPasswordPopup.onAesKey(aesKey -> doWithdrawRequest(toAddress, aesKey, resultHandler, faultHandler)).show();
|
||||
} 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) {
|
||||
tradeManager.onWithdrawRequest(
|
||||
toAddress,
|
||||
aesKey,
|
||||
trade,
|
||||
() -> UserThread.execute(() -> navigation.navigateTo(MainView.class, PortfolioView.class, ClosedTradesView.class)),
|
||||
() -> {
|
||||
resultHandler.handleResult();
|
||||
},
|
||||
(errorMessage, throwable) -> {
|
||||
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) {
|
||||
tradeStateSubscription = EasyBind.subscribe(dataModel.getTrade().stateProperty(), newValue -> {
|
||||
log.debug("tradeStateSubscription " + newValue);
|
||||
if (newValue != null) {
|
||||
applyState(newValue);
|
||||
}
|
||||
|
@ -191,10 +192,6 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
|||
dataModel.onFiatPaymentReceived();
|
||||
}
|
||||
|
||||
public void onWithdrawRequest(String withdrawToAddress) {
|
||||
dataModel.onWithdrawRequest(withdrawToAddress);
|
||||
}
|
||||
|
||||
public void withdrawAddressFocusOut(String text) {
|
||||
withdrawalButtonDisable.set(!btcAddressValidator.validate(text).isValid);
|
||||
}
|
||||
|
@ -324,7 +321,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
|||
}
|
||||
|
||||
public String getOpenDisputeTimeAsFormattedDate() {
|
||||
return formatter.addBlocksToNowDateFormatted(getOpenDisputeTimeAsBlockHeight() - getBestChainHeight());
|
||||
return formatter.addBlocksToNowDateFormatted(getOpenDisputeTimeAsBlockHeight() - getBestChainHeight() + (getLockTime() - getBestChainHeight()));
|
||||
}
|
||||
|
||||
public String getReference() {
|
||||
|
@ -448,9 +445,13 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
|||
break;
|
||||
|
||||
case WITHDRAW_COMPLETED:
|
||||
sellerState.set(UNDEFINED);
|
||||
buyerState.set(PendingTradesViewModel.BuyerState.UNDEFINED);
|
||||
break;
|
||||
|
||||
default:
|
||||
sellerState.set(UNDEFINED);
|
||||
buyerState.set(PendingTradesViewModel.BuyerState.UNDEFINED);
|
||||
log.warn("unhandled processState " + tradeState);
|
||||
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.seller.*;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.scene.layout.GridPane;
|
||||
|
||||
public class SellerSubView extends TradeSubView {
|
||||
private TradeWizardItem step1;
|
||||
|
@ -61,10 +62,20 @@ public class SellerSubView extends TradeSubView {
|
|||
step4 = new TradeWizardItem(SellerStep4aView.class, "Wait for payout unlock");
|
||||
step5 = new TradeWizardItem(SellerStep5View.class, "Completed");
|
||||
|
||||
if (model.getLockTime() > 0)
|
||||
leftVBox.getChildren().setAll(step1, step2, step3, step4, step5);
|
||||
else
|
||||
leftVBox.getChildren().setAll(step1, step2, step3, step5);
|
||||
if (model.getLockTime() > 0) {
|
||||
addWizardsToGridPane(step1);
|
||||
addWizardsToGridPane(step2);
|
||||
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;
|
||||
|
||||
import io.bitsquare.common.util.Tuple3;
|
||||
import io.bitsquare.gui.components.TitledGroupBg;
|
||||
import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeStepView;
|
||||
import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeWizardItem;
|
||||
import io.bitsquare.gui.util.Layout;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static io.bitsquare.gui.util.FormBuilder.addMultilineLabel;
|
||||
import static io.bitsquare.gui.util.FormBuilder.addTitledGroupBg;
|
||||
import static io.bitsquare.gui.util.FormBuilder.*;
|
||||
|
||||
public abstract class TradeSubView extends HBox {
|
||||
protected final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
@ -41,7 +38,10 @@ public abstract class TradeSubView extends HBox {
|
|||
protected AnchorPane contentPane;
|
||||
protected TradeStepView tradeStepView;
|
||||
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();
|
||||
|
||||
if (openDisputeButton != null)
|
||||
leftVBox.getChildren().remove(openDisputeButton);
|
||||
if (notificationTuple != null)
|
||||
leftVBox.getChildren().remove(notificationTuple.first);
|
||||
leftGridPane.getChildren().remove(openDisputeButton);
|
||||
if (notificationGroup != null)
|
||||
notificationGroup.removeItselfFrom(leftGridPane);
|
||||
}
|
||||
|
||||
private void buildViews() {
|
||||
addLeftBox();
|
||||
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();
|
||||
|
||||
openDisputeButton = new Button("Open Dispute");
|
||||
openDisputeButton.setPrefHeight(40);
|
||||
openDisputeButton.setPrefWidth(360);
|
||||
openDisputeButton.setPadding(new Insets(0, 20, 0, 10));
|
||||
openDisputeButton.setAlignment(Pos.CENTER);
|
||||
openDisputeButton.setDefaultButton(true);
|
||||
TitledGroupBg noticeTitledGroupBg = addTitledGroupBg(leftGridPane, leftGridPaneRowIndex, 1, "", Layout.GROUP_DISTANCE);
|
||||
Label label = addMultilineLabel(leftGridPane, leftGridPaneRowIndex, "", Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
||||
openDisputeButton = addButtonAfterGroup(leftGridPane, ++leftGridPaneRowIndex, "Open Dispute");
|
||||
GridPane.setColumnIndex(openDisputeButton, 0);
|
||||
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
|
||||
GridPane gridPane = new GridPane();
|
||||
gridPane.setPrefWidth(340);
|
||||
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);
|
||||
notificationGroup = new NotificationGroup(noticeTitledGroupBg, label, openDisputeButton);
|
||||
notificationGroup.setLabelAndHeadlineVisible(false);
|
||||
notificationGroup.setButtonVisible(false);
|
||||
}
|
||||
|
||||
TitledGroupBg titledGroupBg = addTitledGroupBg(gridPane, 0, 4, "Important notice", 20);
|
||||
Label label = addMultilineLabel(gridPane, 0, Layout.FIRST_ROW_DISTANCE + 20);
|
||||
notificationTuple = new Tuple3<>(gridPane, titledGroupBg, label);
|
||||
public static class NotificationGroup {
|
||||
public final TitledGroupBg titledGroupBg;
|
||||
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) {
|
||||
|
@ -107,13 +132,22 @@ public abstract class TradeSubView extends HBox {
|
|||
|
||||
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) {
|
||||
try {
|
||||
tradeStepView = viewClass.getDeclaredConstructor(PendingTradesViewModel.class).newInstance(model);
|
||||
contentPane.getChildren().setAll(tradeStepView);
|
||||
|
||||
tradeStepView.setNotificationFields(notificationTuple);
|
||||
tradeStepView.setOpenDisputeButton(openDisputeButton);
|
||||
tradeStepView.setNotificationGroup(notificationGroup);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
|
|
@ -18,18 +18,16 @@
|
|||
package io.bitsquare.gui.main.portfolio.pendingtrades.steps;
|
||||
|
||||
import io.bitsquare.arbitration.Dispute;
|
||||
import io.bitsquare.common.util.Tuple3;
|
||||
import io.bitsquare.gui.components.TitledGroupBg;
|
||||
import io.bitsquare.gui.components.TxIdTextField;
|
||||
import io.bitsquare.gui.components.paymentmethods.PaymentMethodForm;
|
||||
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.util.Layout;
|
||||
import io.bitsquare.trade.Trade;
|
||||
import io.bitsquare.user.Preferences;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ProgressBar;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
|
@ -63,11 +61,8 @@ public abstract class TradeStepView extends AnchorPane {
|
|||
protected TitledGroupBg tradeInfoTitledGroupBg;
|
||||
private TextField timeLeftTextField;
|
||||
private ProgressBar timeLeftProgressBar;
|
||||
private GridPane notificationGridPane;
|
||||
private Label notificationLabel;
|
||||
private TitledGroupBg notificationTitledGroupBg;
|
||||
protected Button openDisputeButton;
|
||||
private TxIdTextField txIdTextField;
|
||||
protected TradeSubView.NotificationGroup notificationGroup;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -135,8 +130,8 @@ public abstract class TradeStepView extends AnchorPane {
|
|||
if (tradePeriodStateSubscription != null)
|
||||
tradePeriodStateSubscription.unsubscribe();
|
||||
|
||||
if (openDisputeButton != null)
|
||||
openDisputeButton.setOnAction(null);
|
||||
if (notificationGroup != null)
|
||||
notificationGroup.button.setOnAction(null);
|
||||
|
||||
if (timer != null)
|
||||
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
|
||||
// is trade state specific
|
||||
public void setNotificationFields(Tuple3<GridPane, TitledGroupBg, Label> notificationTuple) {
|
||||
this.notificationGridPane = notificationTuple.first;
|
||||
this.notificationTitledGroupBg = notificationTuple.second;
|
||||
this.notificationLabel = notificationTuple.third;
|
||||
}
|
||||
|
||||
public void setOpenDisputeButton(Button openDisputeButton) {
|
||||
this.openDisputeButton = openDisputeButton;
|
||||
public void setNotificationGroup(TradeSubView.NotificationGroup notificationGroup) {
|
||||
this.notificationGroup = notificationGroup;
|
||||
}
|
||||
|
||||
private void showDisputeInfoLabel() {
|
||||
if (notificationGridPane != null) {
|
||||
notificationGridPane.setVisible(true);
|
||||
notificationGridPane.setManaged(true);
|
||||
if (notificationGroup != null) {
|
||||
notificationGroup.setLabelAndHeadlineVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void showOpenDisputeButton() {
|
||||
if (openDisputeButton != null) {
|
||||
openDisputeButton.setVisible(true);
|
||||
openDisputeButton.setManaged(true);
|
||||
openDisputeButton.setOnAction(e -> {
|
||||
openDisputeButton.setDisable(true);
|
||||
if (notificationGroup != null) {
|
||||
notificationGroup.setButtonVisible(true);
|
||||
notificationGroup.button.setOnAction(e -> {
|
||||
notificationGroup.button.setDisable(true);
|
||||
onDisputeOpened();
|
||||
setDisputeState();
|
||||
model.dataModel.onOpenDispute();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected void setWarningState() {
|
||||
if (notificationGridPane != null) {
|
||||
notificationTitledGroupBg.setText("Warning");
|
||||
//notificationGridPane.setId("trade-notification-warning");
|
||||
protected void setWarningHeadline() {
|
||||
if (notificationGroup != null) {
|
||||
notificationGroup.titledGroupBg.setText("Warning");
|
||||
//notificationGroup.setId("trade-notification-warning");
|
||||
}
|
||||
}
|
||||
|
||||
protected void setInformationState() {
|
||||
if (notificationGridPane != null) {
|
||||
notificationTitledGroupBg.setText("Notification");
|
||||
notificationTitledGroupBg.setId("titled-group-bg-warn");
|
||||
notificationTitledGroupBg.getLabel().setId("titled-group-bg-label-warn");
|
||||
protected void setInformationHeadline() {
|
||||
if (notificationGroup != null) {
|
||||
notificationGroup.titledGroupBg.setText("Notification");
|
||||
//notificationGroup.titledGroupBg.setId("titled-group-bg-warn");
|
||||
//notificationGroup.label.setId("titled-group-bg-label-warn");
|
||||
//notificationLabel.setId("titled-group-bg-label-warn");
|
||||
}
|
||||
}
|
||||
|
||||
protected void setDisputeState() {
|
||||
if (notificationGridPane != null) {
|
||||
notificationTitledGroupBg.setText("Dispute opened");
|
||||
//notificationGridPane.setId("trade-notification-dispute");
|
||||
protected void setOpenDisputeHeadline() {
|
||||
if (notificationGroup != null) {
|
||||
notificationGroup.titledGroupBg.setText("Open a dispute");
|
||||
//notificationGroup.setId("trade-notification-dispute");
|
||||
}
|
||||
}
|
||||
|
||||
protected void setSupportState() {
|
||||
if (notificationGridPane != null) {
|
||||
notificationTitledGroupBg.setText("Support ticket opened");
|
||||
//notificationGridPane.setId("trade-notification-support");
|
||||
protected void setDisputeOpenedHeadline() {
|
||||
if (notificationGroup != null) {
|
||||
notificationGroup.titledGroupBg.setText("Dispute opened");
|
||||
//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() {
|
||||
if (openDisputeButton != null) {
|
||||
openDisputeButton.setText("Request support");
|
||||
openDisputeButton.setId("open-support-button");
|
||||
openDisputeButton.setOnAction(e -> model.dataModel.onOpenSupportTicket());
|
||||
if (notificationGroup != null) {
|
||||
notificationGroup.button.setText("Request support");
|
||||
notificationGroup.button.setId("open-support-button");
|
||||
notificationGroup.button.setOnAction(e -> model.dataModel.onOpenSupportTicket());
|
||||
}
|
||||
new Popup().warning(trade.errorMessageProperty().getValue()
|
||||
+ "\n\nPlease report the problem to your arbitrator.\n\n" +
|
||||
|
@ -299,8 +299,8 @@ public abstract class TradeStepView extends AnchorPane {
|
|||
private void showWarning() {
|
||||
showDisputeInfoLabel();
|
||||
|
||||
if (notificationLabel != null)
|
||||
notificationLabel.setText(getWarningText());
|
||||
if (notificationGroup != null)
|
||||
notificationGroup.label.setText(getWarningText());
|
||||
}
|
||||
|
||||
protected String getWarningText() {
|
||||
|
@ -315,19 +315,20 @@ public abstract class TradeStepView extends AnchorPane {
|
|||
private void onOpenForDispute() {
|
||||
showDisputeInfoLabel();
|
||||
showOpenDisputeButton();
|
||||
setOpenDisputeHeadline();
|
||||
|
||||
if (notificationLabel != null)
|
||||
notificationLabel.setText(getOpenForDisputeText());
|
||||
if (notificationGroup != null)
|
||||
notificationGroup.label.setText(getOpenForDisputeText());
|
||||
}
|
||||
|
||||
private void onDisputeOpened() {
|
||||
showDisputeInfoLabel();
|
||||
showOpenDisputeButton();
|
||||
applyOnDisputeOpened();
|
||||
setDisputeOpenedHeadline();
|
||||
|
||||
|
||||
if (openDisputeButton != null)
|
||||
openDisputeButton.setDisable(true);
|
||||
if (notificationGroup != null)
|
||||
notificationGroup.button.setDisable(true);
|
||||
}
|
||||
|
||||
protected String getOpenForDisputeText() {
|
||||
|
@ -337,6 +338,11 @@ public abstract class TradeStepView extends AnchorPane {
|
|||
protected void applyOnDisputeOpened() {
|
||||
}
|
||||
|
||||
protected void hideNotificationGroup() {
|
||||
notificationGroup.setLabelAndHeadlineVisible(false);
|
||||
notificationGroup.setButtonVisible(false);
|
||||
}
|
||||
|
||||
private void updateDisputeState(Trade.DisputeState disputeState) {
|
||||
Optional<Dispute> ownDispute;
|
||||
switch (disputeState) {
|
||||
|
@ -348,16 +354,16 @@ public abstract class TradeStepView extends AnchorPane {
|
|||
ownDispute.ifPresent(dispute -> {
|
||||
String msg;
|
||||
if (dispute.isSupportTicket()) {
|
||||
setSupportState();
|
||||
setSupportOpenedHeadline();
|
||||
msg = "You opened already a support ticket.\n" +
|
||||
"Please communicate in the support section with the arbitrator.";
|
||||
} else {
|
||||
setDisputeState();
|
||||
setDisputeOpenedHeadline();
|
||||
msg = "You opened already a dispute.\n" +
|
||||
"Please communicate in the support section with the arbitrator.";
|
||||
}
|
||||
if (notificationLabel != null)
|
||||
notificationLabel.setText(msg);
|
||||
if (notificationGroup != null)
|
||||
notificationGroup.label.setText(msg);
|
||||
});
|
||||
|
||||
break;
|
||||
|
@ -367,16 +373,16 @@ public abstract class TradeStepView extends AnchorPane {
|
|||
ownDispute.ifPresent(dispute -> {
|
||||
String msg;
|
||||
if (dispute.isSupportTicket()) {
|
||||
setSupportState();
|
||||
setSupportOpenedHeadline();
|
||||
msg = "Your trading peer opened a support ticket due technical problems.\n" +
|
||||
"Please communicate in the support section with the arbitrator.";
|
||||
} else {
|
||||
setDisputeState();
|
||||
setDisputeOpenedHeadline();
|
||||
msg = "Your trading peer opened a dispute.\n" +
|
||||
"Please communicate in the support section with the arbitrator.";
|
||||
}
|
||||
if (notificationLabel != null)
|
||||
notificationLabel.setText(msg);
|
||||
if (notificationGroup != null)
|
||||
notificationGroup.label.setText(msg);
|
||||
});
|
||||
break;
|
||||
case DISPUTE_CLOSED:
|
||||
|
|
|
@ -39,7 +39,6 @@ public class TradeWizardItem extends Button {
|
|||
setText(title);
|
||||
setPrefHeight(40);
|
||||
setPrefWidth(360);
|
||||
setPadding(new Insets(0, 20, 0, 10));
|
||||
setAlignment(Pos.CENTER_LEFT);
|
||||
setDisabled();
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ public class BuyerStep2View extends TradeStepView {
|
|||
public void doActivate() {
|
||||
super.doActivate();
|
||||
|
||||
String id = PopupId.SEND_PAYMENT_INFO;
|
||||
/* String id = PopupId.SEND_PAYMENT_INFO;
|
||||
if (preferences.showAgain(id) && !BitsquareApp.DEV_MODE) {
|
||||
//TODO use payment method and trade values
|
||||
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.")
|
||||
.onClose(() -> preferences.dontShowAgain(id))
|
||||
.show();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -135,9 +135,9 @@ public class BuyerStep2View extends TradeStepView {
|
|||
|
||||
@Override
|
||||
protected String getWarningText() {
|
||||
setWarningState();
|
||||
setWarningHeadline();
|
||||
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() +
|
||||
" otherwise the trade will be investigated by the arbitrator.";
|
||||
}
|
||||
|
@ -150,9 +150,8 @@ public class BuyerStep2View extends TradeStepView {
|
|||
@Override
|
||||
protected String getOpenForDisputeText() {
|
||||
return "You have not completed your payment!\n" +
|
||||
"The max. period for the trade has elapsed (" +
|
||||
model.getOpenDisputeTimeAsFormattedDate() + ")." +
|
||||
"\nPlease contact now the arbitrator for opening a dispute.";
|
||||
"The max. period for the trade has elapsed.\n" +
|
||||
"\nPlease contact the arbitrator for opening a dispute.";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -205,10 +204,10 @@ public class BuyerStep2View extends TradeStepView {
|
|||
|
||||
// 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 (openDisputeButton != null) {
|
||||
openDisputeButton.setVisible(false);
|
||||
openDisputeButton.setManaged(false);
|
||||
}
|
||||
//TODO check for support. in case of a dispute we dont want to hid ethe button
|
||||
/*if (notificationGroup != null) {
|
||||
notificationGroup.setButtonVisible(false);
|
||||
}*/
|
||||
}, errorMessage -> {
|
||||
removeStatusProgressIndicator();
|
||||
statusLabel.setText("Sending message to your trading partner failed.\n" +
|
||||
|
|
|
@ -55,7 +55,7 @@ public class BuyerStep3View extends TradeStepView {
|
|||
|
||||
@Override
|
||||
protected String getWarningText() {
|
||||
setInformationState();
|
||||
setInformationHeadline();
|
||||
String substitute = model.isBlockChainMethod() ?
|
||||
"on the " + model.getCurrencyCode() + "blockchain" :
|
||||
"at your payment provider (e.g. bank)";
|
||||
|
@ -74,9 +74,8 @@ public class BuyerStep3View extends TradeStepView {
|
|||
@Override
|
||||
protected String getOpenForDisputeText() {
|
||||
return "The seller has not confirmed your payment!\n" +
|
||||
"The max. period for the trade has elapsed (" +
|
||||
model.getOpenDisputeTimeAsFormattedDate() +
|
||||
") and you need to contact now the arbitrator to investigate the problem.";
|
||||
"The max. period for the trade has elapsed.\n" +
|
||||
"Please contact the arbitrator for opening a dispute.";
|
||||
}
|
||||
|
||||
@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.steps.TradeStepView;
|
||||
import io.bitsquare.gui.util.Layout;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import org.bitcoinj.core.*;
|
||||
|
@ -76,6 +75,7 @@ public class BuyerStep4View extends TradeStepView {
|
|||
super.doActivate();
|
||||
|
||||
model.addBlockChainListener(blockChainListener);
|
||||
updateDateFromBlockHeight(model.getBestChainHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -93,9 +93,9 @@ public class BuyerStep4View extends TradeStepView {
|
|||
@Override
|
||||
protected void addContent() {
|
||||
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;
|
||||
GridPane.setRowSpan(tradeInfoTitledGroupBg, 4);
|
||||
GridPane.setRowSpan(tradeInfoTitledGroupBg, 5);
|
||||
|
||||
addInfoBlock();
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ public class BuyerStep4View extends TradeStepView {
|
|||
|
||||
@Override
|
||||
protected String getWarningText() {
|
||||
setInformationState();
|
||||
setInformationHeadline();
|
||||
return "The payout transaction is still blocked by the lock time!\n" +
|
||||
"If the trade has not been completed on " +
|
||||
model.getOpenDisputeTimeAsFormattedDate() +
|
||||
|
|
|
@ -23,6 +23,7 @@ import io.bitsquare.common.util.Tuple2;
|
|||
import io.bitsquare.gui.components.InputTextField;
|
||||
import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel;
|
||||
import io.bitsquare.gui.main.portfolio.pendingtrades.steps.TradeStepView;
|
||||
import io.bitsquare.gui.popups.Popup;
|
||||
import io.bitsquare.gui.util.Layout;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.scene.control.Button;
|
||||
|
@ -77,6 +78,8 @@ public class BuyerStep5View extends TradeStepView {
|
|||
UserThread.execute(() -> withdrawAddressTextField.requestFocus());
|
||||
});*/
|
||||
});
|
||||
|
||||
hideNotificationGroup();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -113,22 +116,31 @@ public class BuyerStep5View extends TradeStepView {
|
|||
withdrawAddressTextField = addLabelInputTextField(gridPane, ++gridRow, "Withdraw to address:").second;
|
||||
withdrawButton = addButtonAfterGroup(gridPane, ++gridRow, "Withdraw to external wallet");
|
||||
withdrawButton.setOnAction(e -> {
|
||||
model.onWithdrawRequest(withdrawAddressTextField.getText());
|
||||
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)
|
||||
withdrawAddressTextField.setText("mxAkWWaQBqwqcYstKzqLku3kzR6pbu2zHq");
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 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.";
|
||||
withdrawAddressTextField.setText("mhpVDvMjJT1Gn7da44dkq1HXd3wXdFZpXu");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -56,8 +56,8 @@ public class SellerStep2View extends TradeStepView {
|
|||
|
||||
@Override
|
||||
protected String getWarningText() {
|
||||
setInformationState();
|
||||
return "The buyer still has not done the " + model.getCurrencyCode() + " payment!\n" +
|
||||
setInformationHeadline();
|
||||
return "The buyer still has not done the " + model.getCurrencyCode() + " payment.\n" +
|
||||
"You need to wait until he starts the payment.\n" +
|
||||
"If the trade has not been completed on " +
|
||||
model.getOpenDisputeTimeAsFormattedDate() +
|
||||
|
|
|
@ -122,7 +122,7 @@ public class SellerStep3View extends TradeStepView {
|
|||
|
||||
@Override
|
||||
protected String getWarningText() {
|
||||
setWarningState();
|
||||
setWarningHeadline();
|
||||
String substitute = model.isBlockChainMethod() ?
|
||||
"on the " + model.getCurrencyCode() + "blockchain" :
|
||||
"at your payment provider (e.g. bank)";
|
||||
|
@ -141,9 +141,8 @@ public class SellerStep3View extends TradeStepView {
|
|||
@Override
|
||||
protected String getOpenForDisputeText() {
|
||||
return "You have not confirmed the receipt of the payment!\n" +
|
||||
"The max. period for the trade has elapsed (" +
|
||||
model.getOpenDisputeTimeAsFormattedDate() + ")." +
|
||||
"\nPlease contact now the arbitrator for opening a dispute.";
|
||||
"The max. period for the trade has elapsed.\n" +
|
||||
"Please contact the arbitrator for opening a dispute.";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -54,7 +54,7 @@ public class SellerStep4bView extends TradeStepView {
|
|||
|
||||
@Override
|
||||
protected String getWarningText() {
|
||||
setInformationState();
|
||||
setInformationHeadline();
|
||||
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" +
|
||||
"If the trade has not been completed on " +
|
||||
|
@ -70,9 +70,8 @@ public class SellerStep4bView extends TradeStepView {
|
|||
@Override
|
||||
protected String getOpenForDisputeText() {
|
||||
return "The trading peer has not finalized the payout transaction!\n" +
|
||||
"The max. period for the trade has elapsed (" +
|
||||
model.getOpenDisputeTimeAsFormattedDate() + ").\n" +
|
||||
"Please contact now the arbitrator for opening a dispute.";
|
||||
"The max. period for the trade has elapsed.\n" +
|
||||
"Please contact the arbitrator for opening a dispute.";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package io.bitsquare.gui.popups;
|
||||
|
||||
import io.bitsquare.common.crypto.KeyRing;
|
||||
import io.bitsquare.common.util.Tuple2;
|
||||
import io.bitsquare.gui.Navigation;
|
||||
import io.bitsquare.gui.main.MainView;
|
||||
|
@ -52,6 +53,7 @@ public class OfferDetailsPopup extends Popup {
|
|||
private final BSFormatter formatter;
|
||||
private final Preferences preferences;
|
||||
private final User user;
|
||||
private KeyRing keyRing;
|
||||
private final Navigation navigation;
|
||||
private Offer offer;
|
||||
private Coin tradeAmount;
|
||||
|
@ -64,10 +66,11 @@ public class OfferDetailsPopup extends Popup {
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@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.preferences = preferences;
|
||||
this.user = user;
|
||||
this.keyRing = keyRing;
|
||||
this.navigation = navigation;
|
||||
}
|
||||
|
||||
|
@ -139,7 +142,10 @@ public class OfferDetailsPopup extends Popup {
|
|||
addLabelTextField(gridPane, ++rowIndex, "Amount:", formatter.formatCoinWithCode(offer.getAmount()));
|
||||
addLabelTextField(gridPane, ++rowIndex, "Min. amount:", formatter.formatCoinWithCode(offer.getMinAmount()));
|
||||
}
|
||||
addLabelTextField(gridPane, ++rowIndex, "Payment method:", BSResources.get(offer.getPaymentMethod().getId()));
|
||||
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()));
|
||||
|
||||
rows = 3;
|
||||
if (offer.getPaymentMethodCountryCode() != null)
|
||||
|
|
|
@ -118,6 +118,14 @@ public class Popup {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Popup notification(String message) {
|
||||
// TODO use icons
|
||||
this.headLine = "Notification";
|
||||
this.message = message;
|
||||
setTruncatedMessage();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Popup information(String message) {
|
||||
this.headLine = "Information";
|
||||
this.message = message;
|
||||
|
@ -219,7 +227,7 @@ public class Popup {
|
|||
scene.getStylesheets().setAll(owner.getScene().getStylesheets());
|
||||
scene.setFill(Color.TRANSPARENT);
|
||||
stage.setScene(scene);
|
||||
stage.initModality(Modality.APPLICATION_MODAL);
|
||||
stage.initModality(Modality.WINDOW_MODAL);
|
||||
stage.initStyle(StageStyle.TRANSPARENT);
|
||||
stage.initOwner(owner.getScene().getWindow());
|
||||
stage.show();
|
||||
|
@ -317,10 +325,11 @@ public class Popup {
|
|||
|
||||
private void addDontShowAgainCheckBox() {
|
||||
if (dontShowAgainId != null && preferences != null) {
|
||||
CheckBox dontShowAgain = addCheckBox(gridPane, ++rowIndex, "Don't show again", 10);
|
||||
GridPane.setHalignment(dontShowAgain, HPos.RIGHT);
|
||||
dontShowAgain.setOnAction(e -> {
|
||||
if (dontShowAgain.isSelected())
|
||||
CheckBox dontShowAgainCheckBox = addCheckBox(gridPane, rowIndex, "Don't show again", 30);
|
||||
GridPane.setColumnIndex(dontShowAgainCheckBox, 0);
|
||||
GridPane.setHalignment(dontShowAgainCheckBox, HPos.LEFT);
|
||||
dontShowAgainCheckBox.setOnAction(e -> {
|
||||
if (dontShowAgainCheckBox.isSelected())
|
||||
preferences.dontShowAgain(dontShowAgainId);
|
||||
});
|
||||
}
|
||||
|
@ -352,7 +361,7 @@ public class Popup {
|
|||
GridPane.setHalignment(hBox, HPos.RIGHT);
|
||||
GridPane.setRowIndex(hBox, ++rowIndex);
|
||||
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);
|
||||
} else {
|
||||
closeButton.setDefaultButton(true);
|
||||
|
@ -366,8 +375,8 @@ public class Popup {
|
|||
}
|
||||
|
||||
protected void setTruncatedMessage() {
|
||||
if (message != null && message.length() > 800)
|
||||
truncatedMessage = StringUtils.abbreviate(message, 800);
|
||||
if (message != null && message.length() > 900)
|
||||
truncatedMessage = StringUtils.abbreviate(message, 900);
|
||||
else
|
||||
truncatedMessage = message;
|
||||
}
|
||||
|
|
|
@ -577,23 +577,20 @@ public class FormBuilder {
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static Button addButton(GridPane gridPane, int rowIndex, String title) {
|
||||
Button button = new Button(title);
|
||||
button.setDefaultButton(true);
|
||||
GridPane.setRowIndex(button, rowIndex);
|
||||
GridPane.setColumnIndex(button, 1);
|
||||
gridPane.getChildren().add(button);
|
||||
return button;
|
||||
return addButton(gridPane, rowIndex, title, 0);
|
||||
}
|
||||
|
||||
public static Button addButtonAfterGroup(GridPane gridPane,
|
||||
int rowIndex,
|
||||
String title) {
|
||||
public static Button addButtonAfterGroup(GridPane gridPane, int rowIndex, String title) {
|
||||
return addButton(gridPane, rowIndex, title, 15);
|
||||
}
|
||||
|
||||
public static Button addButton(GridPane gridPane, int rowIndex, String title, double top) {
|
||||
Button button = new Button(title);
|
||||
button.setDefaultButton(true);
|
||||
GridPane.setRowIndex(button, rowIndex);
|
||||
GridPane.setColumnIndex(button, 1);
|
||||
GridPane.setMargin(button, new Insets(15, 0, 0, 0));
|
||||
gridPane.getChildren().add(button);
|
||||
GridPane.setMargin(button, new Insets(top, 0, 0, 0));
|
||||
return button;
|
||||
}
|
||||
|
||||
|
@ -603,9 +600,9 @@ public class FormBuilder {
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static Tuple2<Button, Button> add2Buttons(GridPane gridPane,
|
||||
int rowIndex,
|
||||
String title1,
|
||||
String title2) {
|
||||
int rowIndex,
|
||||
String title1,
|
||||
String title2) {
|
||||
return add2Buttons(gridPane, rowIndex, title1, title2, 0);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue