diff --git a/common/src/main/java/io/bitsquare/common/util/Tuple3.java b/common/src/main/java/io/bitsquare/common/util/Tuple3.java index be08d6aa63..aca55aee37 100644 --- a/common/src/main/java/io/bitsquare/common/util/Tuple3.java +++ b/common/src/main/java/io/bitsquare/common/util/Tuple3.java @@ -50,4 +50,6 @@ public class Tuple3 implements Serializable { result = 31 * result + (third != null ? third.hashCode() : 0); return result; } + + } diff --git a/core/pom.xml b/core/pom.xml index 3a91d8bcac..75de5cddb0 100755 --- a/core/pom.xml +++ b/core/pom.xml @@ -52,5 +52,6 @@ 4.8 + diff --git a/core/src/main/java/io/bitsquare/btc/FeePolicy.java b/core/src/main/java/io/bitsquare/btc/FeePolicy.java index e09920a2cd..c84eeb3a67 100644 --- a/core/src/main/java/io/bitsquare/btc/FeePolicy.java +++ b/core/src/main/java/io/bitsquare/btc/FeePolicy.java @@ -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() { diff --git a/core/src/main/java/io/bitsquare/btc/WalletService.java b/core/src/main/java/io/bitsquare/btc/WalletService.java index 7ef9b8b38f..b294a68db8 100644 --- a/core/src/main/java/io/bitsquare/btc/WalletService.java +++ b/core/src/main/java/io/bitsquare/btc/WalletService.java @@ -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> 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 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 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 resultHandler; - private final Set transactionOutPoints; - - public ArbitraryTransactionBloomFilter(Transaction transaction, Consumer 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()); - } - } } diff --git a/core/src/main/java/io/bitsquare/btc/http/BlockchainApiProvider.java b/core/src/main/java/io/bitsquare/btc/http/BlockchainApiProvider.java new file mode 100644 index 0000000000..e0f01c0155 --- /dev/null +++ b/core/src/main/java/io/bitsquare/btc/http/BlockchainApiProvider.java @@ -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; +} diff --git a/core/src/main/java/io/bitsquare/btc/http/BlockrIOProvider.java b/core/src/main/java/io/bitsquare/btc/http/BlockrIOProvider.java new file mode 100644 index 0000000000..159f1ef0b2 --- /dev/null +++ b/core/src/main/java/io/bitsquare/btc/http/BlockrIOProvider.java @@ -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; + } + } +} diff --git a/core/src/main/java/io/bitsquare/btc/http/HttpClient.java b/core/src/main/java/io/bitsquare/btc/http/HttpClient.java new file mode 100644 index 0000000000..a8b3b99bfc --- /dev/null +++ b/core/src/main/java/io/bitsquare/btc/http/HttpClient.java @@ -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 + '\'' + + '}'; + } +} diff --git a/core/src/main/java/io/bitsquare/btc/http/HttpException.java b/core/src/main/java/io/bitsquare/btc/http/HttpException.java new file mode 100644 index 0000000000..541e515cc6 --- /dev/null +++ b/core/src/main/java/io/bitsquare/btc/http/HttpException.java @@ -0,0 +1,7 @@ +package io.bitsquare.btc.http; + +public class HttpException extends Exception { + public HttpException(String message) { + super(message); + } +} diff --git a/core/src/main/java/io/bitsquare/payment/PaymentMethod.java b/core/src/main/java/io/bitsquare/payment/PaymentMethod.java index 0a461a70eb..6bc8ebb555 100644 --- a/core/src/main/java/io/bitsquare/payment/PaymentMethod.java +++ b/core/src/main/java/io/bitsquare/payment/PaymentMethod.java @@ -61,7 +61,7 @@ public class PaymentMethod implements Serializable, Comparable { public static final List 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),*/ diff --git a/core/src/main/java/io/bitsquare/trade/Trade.java b/core/src/main/java/io/bitsquare/trade/Trade.java index c344f75007..cbfe9304aa 100644 --- a/core/src/main/java/io/bitsquare/trade/Trade.java +++ b/core/src/main/java/io/bitsquare/trade/Trade.java @@ -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 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 + '\'' + '}'; } diff --git a/core/src/main/java/io/bitsquare/trade/TradeManager.java b/core/src/main/java/io/bitsquare/trade/TradeManager.java index ea6fed29f1..af3e0c05ad 100644 --- a/core/src/main/java/io/bitsquare/trade/TradeManager.java +++ b/core/src/main/java/io/bitsquare/trade/TradeManager.java @@ -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 getTradeById(String tradeId) { return trades.stream().filter(e -> e.getId().equals(tradeId)).findFirst(); } - } \ No newline at end of file diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/BuyerAsOffererProtocol.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/BuyerAsOffererProtocol.java index 1ea72fb790..b34bed7578 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/BuyerAsOffererProtocol.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/BuyerAsOffererProtocol.java @@ -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(); } diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/SellerAsOffererProtocol.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/SellerAsOffererProtocol.java index 59e1bae286..912ef3e689 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/SellerAsOffererProtocol.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/SellerAsOffererProtocol.java @@ -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(); } diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/SignAndPublishDepositTxAsBuyer.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/SignAndPublishDepositTxAsBuyer.java index 8dbcd39e17..d62e445d33 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/SignAndPublishDepositTxAsBuyer.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/SignAndPublishDepositTxAsBuyer.java @@ -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(); diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/offerer/AddDepositTxToWallet.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/offerer/AddDepositTxToWallet.java deleted file mode 100644 index f370021985..0000000000 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/offerer/AddDepositTxToWallet.java +++ /dev/null @@ -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 . - */ - -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); - } - } -} diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/offerer/ProcessDepositTxPublishedMessage.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/offerer/ProcessDepositTxPublishedMessage.java index 0cb85ec2ff..efa8e0cbd9 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/offerer/ProcessDepositTxPublishedMessage.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/offerer/ProcessDepositTxPublishedMessage.java @@ -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()); diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/seller/SignAndPublishDepositTxAsSeller.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/seller/SignAndPublishDepositTxAsSeller.java index 4ddb6d8bea..1a7413b96f 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/seller/SignAndPublishDepositTxAsSeller.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/seller/SignAndPublishDepositTxAsSeller.java @@ -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(); diff --git a/core/src/main/java/io/bitsquare/user/Preferences.java b/core/src/main/java/io/bitsquare/user/Preferences.java index a8b1fa821c..33d435f222 100644 --- a/core/src/main/java/io/bitsquare/user/Preferences.java +++ b/core/src/main/java/io/bitsquare/user/Preferences.java @@ -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 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 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; + } + } diff --git a/gui/src/main/java/io/bitsquare/app/BitsquareApp.java b/gui/src/main/java/io/bitsquare/app/BitsquareApp.java index 0a25bcce6a..e39cf050cd 100644 --- a/gui/src/main/java/io/bitsquare/app/BitsquareApp.java +++ b/gui/src/main/java/io/bitsquare/app/BitsquareApp.java @@ -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; diff --git a/gui/src/main/java/io/bitsquare/gui/bitsquare.css b/gui/src/main/java/io/bitsquare/gui/bitsquare.css index 28f5107421..297987a992 100644 --- a/gui/src/main/java/io/bitsquare/gui/bitsquare.css +++ b/gui/src/main/java/io/bitsquare/gui/bitsquare.css @@ -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 { diff --git a/gui/src/main/java/io/bitsquare/gui/components/HyperlinkWithIcon.java b/gui/src/main/java/io/bitsquare/gui/components/HyperlinkWithIcon.java index 44c5d38642..414fb26a53 100644 --- a/gui/src/main/java/io/bitsquare/gui/components/HyperlinkWithIcon.java +++ b/gui/src/main/java/io/bitsquare/gui/components/HyperlinkWithIcon.java @@ -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); diff --git a/gui/src/main/java/io/bitsquare/gui/main/MainView.java b/gui/src/main/java/io/bitsquare/gui/main/MainView.java index 7d81c47cee..8bafd0a9ed 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/MainView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/MainView.java @@ -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 { 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 { 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 { diff --git a/gui/src/main/java/io/bitsquare/gui/main/MainViewModel.java b/gui/src/main/java/io/bitsquare/gui/main/MainViewModel.java index a759b36ae5..21a2c9849a 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/MainViewModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/MainViewModel.java @@ -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) 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 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 addedTrades) { addedTrades.stream().forEach(trade -> trade.disputeStateProperty().addListener((observable, oldValue, newValue) -> { switch (newValue) { diff --git a/gui/src/main/java/io/bitsquare/gui/main/funds/FundsView.java b/gui/src/main/java/io/bitsquare/gui/main/funds/FundsView.java index 86be68a2d7..d3917e5367 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/funds/FundsView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/funds/FundsView.java @@ -89,7 +89,7 @@ public class FundsView extends ActivatableViewAndModel { 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) diff --git a/gui/src/main/java/io/bitsquare/gui/main/funds/withdrawal/WithdrawalView.java b/gui/src/main/java/io/bitsquare/gui/main/funds/withdrawal/WithdrawalView.java index 8603bcd1bf..7b1e67057a 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/funds/withdrawal/WithdrawalView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/funds/withdrawal/WithdrawalView.java @@ -346,7 +346,7 @@ public class WithdrawalView extends ActivatableView { withdrawToTextField.setPromptText("Fill in your destination address"); if (BitsquareApp.DEV_MODE) - withdrawToTextField.setText("mxAkWWaQBqwqcYstKzqLku3kzR6pbu2zHq"); + withdrawToTextField.setText("mhpVDvMjJT1Gn7da44dkq1HXd3wXdFZpXu"); } private Optional getTradable(WithdrawalListItem item) { diff --git a/gui/src/main/java/io/bitsquare/gui/main/offer/BuyOfferView.java b/gui/src/main/java/io/bitsquare/gui/main/offer/BuyOfferView.java index 529c5a0ee7..b676c6afa4 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/offer/BuyOfferView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/offer/BuyOfferView.java @@ -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"; } } diff --git a/gui/src/main/java/io/bitsquare/gui/main/offer/SellOfferView.java b/gui/src/main/java/io/bitsquare/gui/main/offer/SellOfferView.java index cad5d5b149..420e2d0b07 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/offer/SellOfferView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/offer/SellOfferView.java @@ -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"; } } diff --git a/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferDataModel.java b/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferDataModel.java index b44ebe181e..b6eefa144d 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferDataModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferDataModel.java @@ -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; } diff --git a/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferView.java b/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferView.java index 6821168941..aaa4ddf14c 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferView.java @@ -229,16 +229,24 @@ public class CreateOfferView extends ActivatableViewAndModel 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 { 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 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 im dataModel.onPaymentAccountSelected(paymentAccount); } - void onSecurityDepositInfoDisplayed() { - dataModel.onSecurityDepositInfoDisplayed(); - } - /////////////////////////////////////////////////////////////////////////////////////////// // Handle focus @@ -471,10 +467,6 @@ class TakeOfferViewModel extends ActivatableWithDataModel im return formatter; } - boolean getDisplaySecurityDepositInfo() { - return dataModel.getDisplaySecurityDepositInfo(); - } - boolean isSeller() { return dataModel.getDirection() == Offer.Direction.BUY; } diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/BuyerSubView.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/BuyerSubView.java index 25f5ad0f60..02c36d9f88 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/BuyerSubView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/BuyerSubView.java @@ -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); + } } diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesDataModel.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesDataModel.java index c49d6b977a..bf7de4c585 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesDataModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesDataModel.java @@ -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); } } diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesViewModel.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesViewModel.java index bf7f28b8f5..4468573ae3 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesViewModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesViewModel.java @@ -135,6 +135,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel { + log.debug("tradeStateSubscription " + newValue); if (newValue != null) { applyState(newValue); } @@ -191,10 +192,6 @@ public class PendingTradesViewModel extends ActivatableWithDataModel 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); + } } diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/TradeSubView.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/TradeSubView.java index c1b70208ad..1a915e5d48 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/TradeSubView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/TradeSubView.java @@ -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 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 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(); } diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/TradeStepView.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/TradeStepView.java index 86003f643c..8cc6a5158f 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/TradeStepView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/TradeStepView.java @@ -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 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 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: diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/TradeWizardItem.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/TradeWizardItem.java index a0860b6667..65b1faf06f 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/TradeWizardItem.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/TradeWizardItem.java @@ -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(); } diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java index 4ff332e292..5efb83dbe4 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java @@ -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" + diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep3View.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep3View.java index bfc63bf4b0..2172029ea2 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep3View.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep3View.java @@ -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 diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep4View.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep4View.java index 0d6a588a8d..e87249afb9 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep4View.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep4View.java @@ -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() + diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep5View.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep5View.java index 23fad8af68..8f8ddf8b88 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep5View.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep5View.java @@ -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"); } diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep2View.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep2View.java index b82996b78a..4b464a3c2c 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep2View.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep2View.java @@ -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() + diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java index f4a3410686..c7df7b4807 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java @@ -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 diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep4bView.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep4bView.java index 33e58ed87a..8b8b58ae12 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep4bView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/seller/SellerStep4bView.java @@ -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 diff --git a/gui/src/main/java/io/bitsquare/gui/popups/OfferDetailsPopup.java b/gui/src/main/java/io/bitsquare/gui/popups/OfferDetailsPopup.java index faa4bbb724..0e563831c6 100644 --- a/gui/src/main/java/io/bitsquare/gui/popups/OfferDetailsPopup.java +++ b/gui/src/main/java/io/bitsquare/gui/popups/OfferDetailsPopup.java @@ -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) diff --git a/gui/src/main/java/io/bitsquare/gui/popups/Popup.java b/gui/src/main/java/io/bitsquare/gui/popups/Popup.java index 97a78f9d61..7b65021acf 100644 --- a/gui/src/main/java/io/bitsquare/gui/popups/Popup.java +++ b/gui/src/main/java/io/bitsquare/gui/popups/Popup.java @@ -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; } diff --git a/gui/src/main/java/io/bitsquare/gui/util/FormBuilder.java b/gui/src/main/java/io/bitsquare/gui/util/FormBuilder.java index 93688250f1..4907bba9f3 100644 --- a/gui/src/main/java/io/bitsquare/gui/util/FormBuilder.java +++ b/gui/src/main/java/io/bitsquare/gui/util/FormBuilder.java @@ -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 add2Buttons(GridPane gridPane, - int rowIndex, - String title1, - String title2) { + int rowIndex, + String title1, + String title2) { return add2Buttons(gridPane, rowIndex, title1, title2, 0); }