From 009a4daff3c1f3ed31731a3e2d2cec6723c7dd7b Mon Sep 17 00:00:00 2001
From: Manfred Karrer
Date: Mon, 6 Oct 2014 11:54:13 +0200
Subject: [PATCH 01/12] Change min app size
---
src/main/java/io/bitsquare/BitSquare.java | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/main/java/io/bitsquare/BitSquare.java b/src/main/java/io/bitsquare/BitSquare.java
index fcbb7f0115..fef69e3335 100644
--- a/src/main/java/io/bitsquare/BitSquare.java
+++ b/src/main/java/io/bitsquare/BitSquare.java
@@ -166,11 +166,11 @@ public class BitSquare extends Application {
// TODO resizing not fully supported yet
- primaryStage.setMinWidth(75);
- primaryStage.setMinHeight(50);
+ /* primaryStage.setMinWidth(75);
+ primaryStage.setMinHeight(50);*/
- /* primaryStage.setMinWidth(1000);
- primaryStage.setMinHeight(750);*/
+ primaryStage.setMinWidth(1000);
+ primaryStage.setMinHeight(750);
Profiler.initScene(primaryStage.getScene());
From aa66d591ab38af77786ec35ab7236c46e8705c38 Mon Sep 17 00:00:00 2001
From: Manfred Karrer
Date: Mon, 6 Oct 2014 11:57:17 +0200
Subject: [PATCH 02/12] Add info popup for first time user at take offer screen
---
.../main/trade/takeoffer/TakeOfferModel.java | 12 +++++++++++-
.../gui/main/trade/takeoffer/TakeOfferPM.java | 4 ++++
.../main/trade/takeoffer/TakeOfferViewCB.java | 17 +++++++++++++++++
3 files changed, 32 insertions(+), 1 deletion(-)
diff --git a/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferModel.java b/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferModel.java
index c374bfd724..40100c252b 100644
--- a/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferModel.java
+++ b/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferModel.java
@@ -22,6 +22,7 @@ import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.gui.UIModel;
+import io.bitsquare.persistence.Persistence;
import io.bitsquare.settings.Settings;
import io.bitsquare.trade.Offer;
import io.bitsquare.trade.Trade;
@@ -56,6 +57,7 @@ class TakeOfferModel extends UIModel {
private final TradeManager tradeManager;
private final WalletFacade walletFacade;
private final Settings settings;
+ private Persistence persistence;
private Offer offer;
private AddressEntry addressEntry;
@@ -81,10 +83,11 @@ class TakeOfferModel extends UIModel {
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
- TakeOfferModel(TradeManager tradeManager, WalletFacade walletFacade, Settings settings) {
+ TakeOfferModel(TradeManager tradeManager, WalletFacade walletFacade, Settings settings, Persistence persistence) {
this.tradeManager = tradeManager;
this.walletFacade = walletFacade;
this.settings = settings;
+ this.persistence = persistence;
}
@@ -227,6 +230,13 @@ class TakeOfferModel extends UIModel {
return true;
}
+ Boolean displaySecurityDepositInfo() {
+ Object securityDepositInfoDisplayedObject = persistence.read("displaySecurityDepositInfo");
+ if (securityDepositInfoDisplayedObject instanceof Boolean)
+ return (Boolean) securityDepositInfoDisplayedObject;
+ else
+ return true;
+ }
///////////////////////////////////////////////////////////////////////////////////////////
// Setter
diff --git a/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferPM.java b/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferPM.java
index 36602979f6..76ab575f89 100644
--- a/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferPM.java
+++ b/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferPM.java
@@ -303,6 +303,10 @@ class TakeOfferPM extends PresentationModel {
return paymentLabel;
}
+ Boolean displaySecurityDepositInfo() {
+ return model.displaySecurityDepositInfo();
+ }
+
///////////////////////////////////////////////////////////////////////////////////////////
// Private
diff --git a/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferViewCB.java b/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferViewCB.java
index 3f63df824a..bfbe1c8826 100644
--- a/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferViewCB.java
+++ b/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferViewCB.java
@@ -196,6 +196,23 @@ public class TakeOfferViewCB extends CachedViewCB {
@FXML
void onTakeOffer() {
+ if (presentationModel.displaySecurityDepositInfo()) {
+ overlayManager.blurContent();
+ List actions = new ArrayList<>();
+ actions.add(new AbstractAction(BSResources.get("shared.close")) {
+ @Override
+ public void handle(ActionEvent actionEvent) {
+ Dialog.Actions.CLOSE.handle(actionEvent);
+ overlayManager.removeBlurContent();
+ }
+ });
+ Popups.openInfo("To ensure that both traders behave fair they need to pay a security deposit.",
+ "The deposit will stay in your local trading wallet until the offer gets accepted by " +
+ "another trader. " +
+ "\nIt will be refunded to you after the trade has successfully completed.",
+ actions);
+ }
+
presentationModel.takeOffer();
}
From f485afec19a0a02e589fb08d8c52c36a8ec72e0a Mon Sep 17 00:00:00 2001
From: Manfred Karrer
Date: Mon, 6 Oct 2014 11:58:48 +0200
Subject: [PATCH 03/12] Fix bug with add info popup for first time user at take
offer screen
---
.../gui/main/trade/takeoffer/TakeOfferViewCB.java | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferViewCB.java b/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferViewCB.java
index bfbe1c8826..1e5934c3d1 100644
--- a/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferViewCB.java
+++ b/src/main/java/io/bitsquare/gui/main/trade/takeoffer/TakeOfferViewCB.java
@@ -196,6 +196,11 @@ public class TakeOfferViewCB extends CachedViewCB {
@FXML
void onTakeOffer() {
+ presentationModel.takeOffer();
+ }
+
+ @FXML
+ void onShowPayFundsScreen() {
if (presentationModel.displaySecurityDepositInfo()) {
overlayManager.blurContent();
List actions = new ArrayList<>();
@@ -213,11 +218,6 @@ public class TakeOfferViewCB extends CachedViewCB {
actions);
}
- presentationModel.takeOffer();
- }
-
- @FXML
- void onShowPayFundsScreen() {
priceAmountPane.setInactive();
showPaymentInfoScreenButton.setVisible(false);
From e054b2ef3d30444ca9346e03f9d38f7cbc959c09 Mon Sep 17 00:00:00 2001
From: Manfred Karrer
Date: Mon, 6 Oct 2014 14:45:49 +0200
Subject: [PATCH 04/12] Use local seed node
---
src/main/java/io/bitsquare/gui/main/MainModel.java | 11 ++++++-----
.../java/io/bitsquare/gui/main/funds/FundsView.fxml | 2 +-
.../gui/main/orders/pending/PendingTradesPM.java | 3 +--
.../gui/main/trade/createoffer/CreateOfferViewCB.java | 2 ++
src/main/resources/i18n/displayStrings.properties | 3 ++-
5 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/src/main/java/io/bitsquare/gui/main/MainModel.java b/src/main/java/io/bitsquare/gui/main/MainModel.java
index 2291611195..145835c57e 100644
--- a/src/main/java/io/bitsquare/gui/main/MainModel.java
+++ b/src/main/java/io/bitsquare/gui/main/MainModel.java
@@ -23,6 +23,7 @@ import io.bitsquare.gui.UIModel;
import io.bitsquare.gui.util.Profiler;
import io.bitsquare.msg.DHTSeedService;
import io.bitsquare.msg.MessageFacade;
+import io.bitsquare.msg.actor.event.PeerInitialized;
import io.bitsquare.msg.listeners.BootstrapListener;
import io.bitsquare.persistence.Persistence;
import io.bitsquare.trade.Trade;
@@ -104,8 +105,8 @@ class MainModel extends UIModel {
// For testing with the serverside seednode we need the BootstrappedPeerFactory which gets started form
// messageFacade.init
-
- /*dhtSeedService.setHandler(m -> {
+
+ dhtSeedService.setHandler(m -> {
if (m instanceof PeerInitialized) {
log.debug("dht seed initialized. ");
// init messageFacade after seed node initialized
@@ -124,9 +125,9 @@ class MainModel extends UIModel {
}
});
- dhtSeedService.initializePeer();*/
+ dhtSeedService.initializePeer();
- messageFacade.init(new BootstrapListener() {
+ /* messageFacade.init(new BootstrapListener() {
@Override
public void onCompleted() {
messageFacadeInited = true;
@@ -137,7 +138,7 @@ class MainModel extends UIModel {
public void onFailed(Throwable throwable) {
log.error(throwable.toString());
}
- });
+ });*/
Profiler.printMsgWithTime("MainModel.initFacades");
diff --git a/src/main/java/io/bitsquare/gui/main/funds/FundsView.fxml b/src/main/java/io/bitsquare/gui/main/funds/FundsView.fxml
index 3f58bc1db7..b6abe3ed7b 100644
--- a/src/main/java/io/bitsquare/gui/main/funds/FundsView.fxml
+++ b/src/main/java/io/bitsquare/gui/main/funds/FundsView.fxml
@@ -24,6 +24,6 @@
xmlns:fx="http://javafx.com/fxml">
-
+
\ No newline at end of file
diff --git a/src/main/java/io/bitsquare/gui/main/orders/pending/PendingTradesPM.java b/src/main/java/io/bitsquare/gui/main/orders/pending/PendingTradesPM.java
index 12562bf5d3..757f13f64f 100644
--- a/src/main/java/io/bitsquare/gui/main/orders/pending/PendingTradesPM.java
+++ b/src/main/java/io/bitsquare/gui/main/orders/pending/PendingTradesPM.java
@@ -17,7 +17,6 @@
package io.bitsquare.gui.main.orders.pending;
-import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.WalletFacade;
import io.bitsquare.gui.PresentationModel;
import io.bitsquare.gui.components.Popups;
@@ -151,7 +150,7 @@ public class PendingTradesPM extends PresentationModel {
}
String getAmountToWithdraw() {
- return formatter.formatCoinWithCode(model.getAmountToWithdraw().subtract(FeePolicy.TX_FEE));
+ return formatter.formatCoinWithCode(model.getAmountToWithdraw()); //.subtract(FeePolicy.TX_FEE));
}
///////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/io/bitsquare/gui/main/trade/createoffer/CreateOfferViewCB.java b/src/main/java/io/bitsquare/gui/main/trade/createoffer/CreateOfferViewCB.java
index 4647802ca9..292a431528 100644
--- a/src/main/java/io/bitsquare/gui/main/trade/createoffer/CreateOfferViewCB.java
+++ b/src/main/java/io/bitsquare/gui/main/trade/createoffer/CreateOfferViewCB.java
@@ -285,6 +285,8 @@ public class CreateOfferViewCB extends CachedViewCB {
private void close() {
TabPane tabPane = ((TabPane) (root.getParent().getParent()));
tabPane.getTabs().remove(tabPane.getSelectionModel().getSelectedItem());
+
+ navigation.navigationTo(Navigation.Item.MAIN, Navigation.Item.ORDERS, Navigation.Item.OFFERS);
}
diff --git a/src/main/resources/i18n/displayStrings.properties b/src/main/resources/i18n/displayStrings.properties
index 0851e9af11..510f53fd0b 100644
--- a/src/main/resources/i18n/displayStrings.properties
+++ b/src/main/resources/i18n/displayStrings.properties
@@ -71,7 +71,8 @@ createOffer.advancedBox.county=Payments account country:
createOffer.advancedBox.info=Your trading partners must fulfill your offer restrictions. You can edit the accepted countries, languages and arbitrators in the settings. The payments account details are used from your current selected payments account (if you have multiple payments accounts).
createOffer.success.headline=Your offer has been successfully published to the distributed offerbook.
-createOffer.success.info=The Transaction ID for the offer payment is: {0}
+createOffer.success.info=The Transaction ID for the offer payment is: {0}\n\nIn the Offers screen you can manage your\
+ open offers.
createOffer.error.message=An error occurred when placing the offer.\n{0}
From 2eb5428ed989743083591062d01bba7fa1737aed Mon Sep 17 00:00:00 2001
From: Manfred Karrer
Date: Mon, 6 Oct 2014 17:58:17 +0200
Subject: [PATCH 05/12] Fix wrong type in BSResource, Change wording
---
src/main/java/io/bitsquare/locale/BSResources.java | 2 +-
src/main/resources/i18n/displayStrings.properties | 5 +++--
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/main/java/io/bitsquare/locale/BSResources.java b/src/main/java/io/bitsquare/locale/BSResources.java
index 429c436e91..216b1b61c5 100644
--- a/src/main/java/io/bitsquare/locale/BSResources.java
+++ b/src/main/java/io/bitsquare/locale/BSResources.java
@@ -53,7 +53,7 @@ public class BSResources {
}
}
- public static String get(String key, String... arguments) {
+ public static String get(String key, Object... arguments) {
return MessageFormat.format(BSResources.get(key), arguments);
}
}
diff --git a/src/main/resources/i18n/displayStrings.properties b/src/main/resources/i18n/displayStrings.properties
index 510f53fd0b..9b1f2e866a 100644
--- a/src/main/resources/i18n/displayStrings.properties
+++ b/src/main/resources/i18n/displayStrings.properties
@@ -71,8 +71,9 @@ createOffer.advancedBox.county=Payments account country:
createOffer.advancedBox.info=Your trading partners must fulfill your offer restrictions. You can edit the accepted countries, languages and arbitrators in the settings. The payments account details are used from your current selected payments account (if you have multiple payments accounts).
createOffer.success.headline=Your offer has been successfully published to the distributed offerbook.
-createOffer.success.info=The Transaction ID for the offer payment is: {0}\n\nIn the Offers screen you can manage your\
- open offers.
+createOffer.success.info=In the Offers screen you can manage your open offers.\n\nThe Transaction ID for the offer \
+ payment is: {0}
+
createOffer.error.message=An error occurred when placing the offer.\n{0}
From e2cdc517e404dd9c2631fe3ebefd0def95dc799e Mon Sep 17 00:00:00 2001
From: Manfred Karrer
Date: Tue, 7 Oct 2014 22:56:43 +0200
Subject: [PATCH 06/12] Use BlockdownloadPane from wallettemplate
---
.../btc/AddressBasedCoinSelector.java | 12 +-
.../java/io/bitsquare/btc/WalletFacade.java | 43 +++--
.../java/io/bitsquare/di/BitSquareModule.java | 4 +-
.../java/io/bitsquare/gui/main/MainModel.java | 48 ++---
.../java/io/bitsquare/gui/main/MainPM.java | 14 +-
.../io/bitsquare/gui/main/MainViewCB.java | 66 +++----
.../java/io/bitsquare/locale/BSResources.java | 2 +-
.../controls/NotificationBarPane.java | 142 ++++++++++++++
.../java/wallettemplate/utils/GuiUtils.java | 166 ++++++++++++++++
.../java/wallettemplate/utils/WTUtils.java | 87 +++++++++
.../utils/easing/EasingInterpolator.java | 134 +++++++++++++
.../utils/easing/EasingMode.java | 12 ++
.../utils/easing/ElasticInterpolator.java | 180 ++++++++++++++++++
src/main/resources/logback.xml | 6 +-
src/main/resources/wallet/checkpoints.testnet | Bin 0 -> 12885 bytes
15 files changed, 820 insertions(+), 96 deletions(-)
create mode 100644 src/main/java/wallettemplate/controls/NotificationBarPane.java
create mode 100644 src/main/java/wallettemplate/utils/GuiUtils.java
create mode 100644 src/main/java/wallettemplate/utils/WTUtils.java
create mode 100644 src/main/java/wallettemplate/utils/easing/EasingInterpolator.java
create mode 100644 src/main/java/wallettemplate/utils/easing/EasingMode.java
create mode 100644 src/main/java/wallettemplate/utils/easing/ElasticInterpolator.java
create mode 100644 src/main/resources/wallet/checkpoints.testnet
diff --git a/src/main/java/io/bitsquare/btc/AddressBasedCoinSelector.java b/src/main/java/io/bitsquare/btc/AddressBasedCoinSelector.java
index b1260cd2fc..16313344fb 100644
--- a/src/main/java/io/bitsquare/btc/AddressBasedCoinSelector.java
+++ b/src/main/java/io/bitsquare/btc/AddressBasedCoinSelector.java
@@ -95,14 +95,20 @@ class AddressBasedCoinSelector extends DefaultCoinSelector {
// TODO It might be risky to accept 0 confirmation tx from the network with only > 1 numBroadcastPeers
// Need to be tested in testnet and mainnet
// We need to handle cases when malleability happens or tx get lost and have not been successful propagated
- return type.equals(TransactionConfidence.ConfidenceType.BUILDING) ||
+ /* return type.equals(TransactionConfidence.ConfidenceType.BUILDING) ||
type.equals(TransactionConfidence.ConfidenceType.PENDING) &&
// we accept network tx without confirmations and numBroadcastPeers > 0
- /*confidence.getSource().equals(TransactionConfidence.Source.SELF) &&*/
+ //confidence.getSource().equals(TransactionConfidence.Source.SELF) &&
// In regtest mode we expect to have only one peer, so we won't see transactions propagate.
// TODO: The value 1 below dates from a time when transactions we broadcast *to* were
// counted, set to 0
- (confidence.numBroadcastPeers() > 1 || tx.getParams() == RegTestParams.get());
+ (confidence.numBroadcastPeers() > 1 || tx.getParams() == RegTestParams.get());*/
+
+ log.debug("numBroadcastPeers = " + confidence.numBroadcastPeers());
+ // TODO at testnet we got confidence.numBroadcastPeers()=1
+ return type.equals(TransactionConfidence.ConfidenceType.BUILDING) ||
+ type.equals(TransactionConfidence.ConfidenceType.PENDING) &&
+ (confidence.numBroadcastPeers() > 0 || tx.getParams() == RegTestParams.get());
}
private static boolean isInBlockChain(Transaction tx) {
diff --git a/src/main/java/io/bitsquare/btc/WalletFacade.java b/src/main/java/io/bitsquare/btc/WalletFacade.java
index ef881adc26..32e87e8d5b 100644
--- a/src/main/java/io/bitsquare/btc/WalletFacade.java
+++ b/src/main/java/io/bitsquare/btc/WalletFacade.java
@@ -46,6 +46,7 @@ import org.bitcoinj.crypto.TransactionSignature;
import org.bitcoinj.kits.WalletAppKit;
import org.bitcoinj.params.MainNetParams;
import org.bitcoinj.params.RegTestParams;
+import org.bitcoinj.params.TestNet3Params;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.ScriptBuilder;
import org.bitcoinj.utils.Threading;
@@ -54,13 +55,13 @@ import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.Service;
import java.io.Serializable;
import java.math.BigInteger;
import java.util.ArrayList;
-import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
@@ -102,7 +103,7 @@ public class WalletFacade {
private final FeePolicy feePolicy;
private final CryptoFacade cryptoFacade;
private final Persistence persistence;
- private final List downloadListeners = new CopyOnWriteArrayList<>();
+ // private final List downloadListeners = new CopyOnWriteArrayList<>();
private final List addressConfidenceListeners = new CopyOnWriteArrayList<>();
private final List txConfidenceListeners = new CopyOnWriteArrayList<>();
private final List balanceListeners = new CopyOnWriteArrayList<>();
@@ -132,7 +133,7 @@ public class WalletFacade {
// Public Methods
///////////////////////////////////////////////////////////////////////////////////////////
- public void initialize(StartupListener startupListener) {
+ public void initialize(org.bitcoinj.core.DownloadListener downloadListener, StartupListener startupListener) {
// Tell bitcoinj to execute event handlers on the JavaFX UI thread. This keeps things simple and means
// we cannot forget to switch threads when adding event handlers. Unfortunately, the DownloadListener
// we give to the app kit is currently an exception and runs on a library thread. It'll get fixed in
@@ -164,7 +165,7 @@ public class WalletFacade {
// Checkpoint files are made using the BuildCheckpoints tool and usually we have to download the
// last months worth or more (takes a few seconds).
try {
- walletAppKit.setCheckpoints(getClass().getClassLoader().getResourceAsStream("wallet/checkpoints"));
+ walletAppKit.setCheckpoints(getClass().getResourceAsStream("wallet/checkpoints"));
} catch (Exception e) {
e.printStackTrace();
log.error(e.toString());
@@ -172,24 +173,40 @@ public class WalletFacade {
// As an example!
// walletAppKit.useTor();
}
- walletAppKit.setDownloadListener(new BlockChainDownloadListener())
+ else if (params == TestNet3Params.get()) {
+ walletAppKit.setCheckpoints(getClass().getResourceAsStream("wallet/checkpoints.testnet"));
+ //walletAppKit.useTor();
+ }
+ walletAppKit.setDownloadListener(downloadListener)
.setBlockingStartup(false)
- .restoreWalletFromSeed(null)
.setUserAgent("BitSquare", "0.1");
+
+ /*
+ // TODO restore from DeterministicSeed
+ if (seed != null)
+ walletAppKit.restoreWalletFromSeed(seed);
+ */
+ walletAppKit.addListener(new Service.Listener() {
+ @Override
+ public void failed(Service.State from, Throwable failure) {
+ walletAppKit = null;
+ // TODO show error popup
+ //crashAlert(failure);
+ }
+ }, Threading.SAME_THREAD);
walletAppKit.startAsync();
}
private void initWallet() {
wallet = walletAppKit.wallet();
- wallet.allowSpendingUnconfirmedTransactions();
//walletAppKit.peerGroup().setMaxConnections(11);
- if (params == RegTestParams.get())
+ /* if (params == RegTestParams.get())
walletAppKit.peerGroup().setMinBroadcastConnections(1);
else
- walletAppKit.peerGroup().setMinBroadcastConnections(3);
+ walletAppKit.peerGroup().setMinBroadcastConnections(3);*/
walletEventListener = new WalletEventListener() {
@@ -266,14 +283,14 @@ public class WalletFacade {
// Listener
///////////////////////////////////////////////////////////////////////////////////////////
- public DownloadListener addDownloadListener(DownloadListener listener) {
+ /* public DownloadListener addDownloadListener(DownloadListener listener) {
downloadListeners.add(listener);
return listener;
}
public void removeDownloadListener(DownloadListener listener) {
downloadListeners.remove(listener);
- }
+ }*/
public AddressConfidenceListener addAddressConfidenceListener(AddressConfidenceListener listener) {
addressConfidenceListeners.add(listener);
@@ -1140,7 +1157,7 @@ public class WalletFacade {
void downloadComplete();
}
- private class BlockChainDownloadListener extends org.bitcoinj.core.DownloadListener {
+ /* private class BlockChainDownloadListener extends org.bitcoinj.core.DownloadListener {
@Override
protected void progress(double percent, int blocksSoFar, Date date) {
super.progress(percent, blocksSoFar, date);
@@ -1164,6 +1181,6 @@ public class WalletFacade {
downloadListener.downloadComplete();
}
}
- }
+ }*/
}
diff --git a/src/main/java/io/bitsquare/di/BitSquareModule.java b/src/main/java/io/bitsquare/di/BitSquareModule.java
index 93849519be..8f5bebf79d 100644
--- a/src/main/java/io/bitsquare/di/BitSquareModule.java
+++ b/src/main/java/io/bitsquare/di/BitSquareModule.java
@@ -146,8 +146,8 @@ class NetworkParametersProvider implements Provider {
// Set default
// String networkType= WalletFacade.MAIN_NET;
- // String networkType = WalletFacade.TEST_NET;
- String networkType = WalletFacade.REG_TEST_NET;
+ String networkType = WalletFacade.TEST_NET;
+ // String networkType = WalletFacade.REG_TEST_NET;
if (networkTypeFromConfig != null)
networkType = networkTypeFromConfig;
diff --git a/src/main/java/io/bitsquare/gui/main/MainModel.java b/src/main/java/io/bitsquare/gui/main/MainModel.java
index 145835c57e..27a054dc3f 100644
--- a/src/main/java/io/bitsquare/gui/main/MainModel.java
+++ b/src/main/java/io/bitsquare/gui/main/MainModel.java
@@ -30,8 +30,13 @@ import io.bitsquare.trade.Trade;
import io.bitsquare.trade.TradeManager;
import io.bitsquare.user.User;
+import org.bitcoinj.core.DownloadListener;
+
import com.google.inject.Inject;
+import java.util.Date;
+
+import javafx.application.Platform;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
@@ -60,8 +65,6 @@ class MainModel extends UIModel {
final BooleanProperty backendInited = new SimpleBooleanProperty();
final DoubleProperty networkSyncProgress = new SimpleDoubleProperty();
- final BooleanProperty networkSyncComplete = new SimpleBooleanProperty();
- // final ObjectProperty balance = new SimpleObjectProperty<>();
final IntegerProperty numPendingTrades = new SimpleIntegerProperty(0);
///////////////////////////////////////////////////////////////////////////////////////////
@@ -142,19 +145,24 @@ class MainModel extends UIModel {
Profiler.printMsgWithTime("MainModel.initFacades");
- walletFacade.initialize(() -> {
+ DownloadListener downloadListener = new DownloadListener() {
+ @Override
+ protected void progress(double percent, int blocksLeft, Date date) {
+ super.progress(percent, blocksLeft, date);
+ Platform.runLater(() -> networkSyncProgress.set(percent / 100.0));
+ }
+
+ @Override
+ protected void doneDownload() {
+ super.doneDownload();
+ Platform.runLater(() -> networkSyncProgress.set(1.0));
+ }
+ };
+
+ walletFacade.initialize(downloadListener, () -> {
walletFacadeInited = true;
if (messageFacadeInited)
onFacadesInitialised();
-
-
- /* walletFacade.addBalanceListener(new BalanceListener() {
- @Override
- public void onBalanceChanged(Coin balance) {
- updateBalance(balance);
- }
- });
- updateBalance(walletFacade.getWalletBalance());*/
});
}
@@ -187,19 +195,6 @@ class MainModel extends UIModel {
///////////////////////////////////////////////////////////////////////////////////////////
private void onFacadesInitialised() {
- // TODO Consider to use version sync notification pane from Mike Hearn
- walletFacade.addDownloadListener(new WalletFacade.DownloadListener() {
- @Override
- public void progress(double percent) {
- networkSyncProgress.set(percent);
- }
-
- @Override
- public void downloadComplete() {
- networkSyncComplete.set(true);
- }
- });
-
tradeManager.getPendingTrades().addListener((MapChangeListener) change -> updateNumPendingTrades());
updateNumPendingTrades();
@@ -211,7 +206,4 @@ class MainModel extends UIModel {
numPendingTrades.set(tradeManager.getPendingTrades().size());
}
- /* private void updateBalance(Coin balance) {
- this.balance.set(balance);
- }*/
}
diff --git a/src/main/java/io/bitsquare/gui/main/MainPM.java b/src/main/java/io/bitsquare/gui/main/MainPM.java
index fe4903d49a..cdc3f2c22c 100644
--- a/src/main/java/io/bitsquare/gui/main/MainPM.java
+++ b/src/main/java/io/bitsquare/gui/main/MainPM.java
@@ -24,9 +24,11 @@ import io.bitsquare.gui.util.BSFormatter;
import com.google.inject.Inject;
import javafx.beans.property.BooleanProperty;
+import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
+import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
@@ -40,15 +42,14 @@ import org.slf4j.LoggerFactory;
class MainPM extends PresentationModel {
private static final Logger log = LoggerFactory.getLogger(MainPM.class);
+ private BSFormatter formatter;
+
final BooleanProperty backendInited = new SimpleBooleanProperty();
- // final StringProperty balance = new SimpleStringProperty();
final StringProperty bankAccountsComboBoxPrompt = new SimpleStringProperty();
final BooleanProperty bankAccountsComboBoxDisable = new SimpleBooleanProperty();
final StringProperty splashScreenInfoText = new SimpleStringProperty();
- final BooleanProperty networkSyncComplete = new SimpleBooleanProperty();
final IntegerProperty numPendingTrades = new SimpleIntegerProperty();
- private BSFormatter formatter;
-
+ final DoubleProperty networkSyncProgress = new SimpleDoubleProperty();
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
@@ -71,7 +72,7 @@ class MainPM extends PresentationModel {
super.initialize();
backendInited.bind(model.backendInited);
- networkSyncComplete.bind(model.networkSyncComplete);
+ networkSyncProgress.bind(model.networkSyncProgress);
numPendingTrades.bind(model.numPendingTrades);
model.networkSyncProgress.addListener((ov, oldValue, newValue) -> {
@@ -84,9 +85,6 @@ class MainPM extends PresentationModel {
});
- /*model.balance.addListener((ov, oldValue, newValue) -> balance.set(formatter.formatCoinWithCode
- (newValue)));*/
-
model.getBankAccounts().addListener((ListChangeListener) change -> {
bankAccountsComboBoxDisable.set(change.getList().isEmpty());
bankAccountsComboBoxPrompt.set(change.getList().isEmpty() ? "No accounts" : "");
diff --git a/src/main/java/io/bitsquare/gui/main/MainViewCB.java b/src/main/java/io/bitsquare/gui/main/MainViewCB.java
index bc361d666d..67b863ae55 100644
--- a/src/main/java/io/bitsquare/gui/main/MainViewCB.java
+++ b/src/main/java/io/bitsquare/gui/main/MainViewCB.java
@@ -52,6 +52,8 @@ import javafx.scene.paint.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import wallettemplate.controls.NotificationBarPane;
+
public class MainViewCB extends ViewCB {
private static final Logger log = LoggerFactory.getLogger(MainViewCB.class);
@@ -61,7 +63,7 @@ public class MainViewCB extends ViewCB {
private final ToggleGroup navButtonsGroup = new ToggleGroup();
private BorderPane baseApplicationContainer;
- private VBox baseOverlayContainer;
+ private StackPane baseOverlayContainer;
private AnchorPane contentContainer;
private HBox leftNavPane, rightNavPane;
private NetworkSyncPane networkSyncPane;
@@ -69,6 +71,7 @@ public class MainViewCB extends ViewCB {
accountButton;
private Pane ordersButtonButtonPane;
private Label numPendingTradesLabel;
+ private NotificationBarPane notificationBarPane;
///////////////////////////////////////////////////////////////////////////////////////////
@@ -166,10 +169,24 @@ public class MainViewCB extends ViewCB {
private void startup() {
baseApplicationContainer = getBaseApplicationContainer();
- baseOverlayContainer = getSplashScreen();
- ((StackPane) root).getChildren().addAll(baseApplicationContainer, baseOverlayContainer);
+ baseOverlayContainer = new StackPane();
- onBaseContainersCreated();
+ // TODO remove dependency of NotificationBarPane with getSplashScreen (borderPane content)
+ notificationBarPane = new NotificationBarPane(getSplashScreen());
+ baseOverlayContainer.getChildren().add(notificationBarPane);
+
+ final NotificationBarPane.Item syncItem = notificationBarPane.pushItem("Synchronising with the Bitcoin network",
+ presentationModel.networkSyncProgress);
+
+ presentationModel.networkSyncProgress.addListener((ov, oldValue, newValue) -> {
+ if ((double) newValue >= 1.0) {
+ log.debug("### networkSyncProgress " + newValue);
+ syncItem.cancel();
+ onBaseContainersCreated();
+ }
+ });
+
+ ((StackPane) root).getChildren().addAll(baseApplicationContainer, baseOverlayContainer);
}
private void onBaseContainersCreated() {
@@ -284,7 +301,7 @@ public class MainViewCB extends ViewCB {
return borderPane;
}
- private VBox getSplashScreen() {
+ private BorderPane getSplashScreen() {
VBox vBox = new VBox();
vBox.setAlignment(Pos.CENTER);
vBox.setSpacing(10);
@@ -303,7 +320,9 @@ public class MainViewCB extends ViewCB {
loadingLabel.textProperty().bind(presentationModel.splashScreenInfoText);
vBox.getChildren().addAll(logo, subTitle, loadingLabel);
- return vBox;
+
+ BorderPane borderPane = new BorderPane(vBox);
+ return borderPane;
}
private AnchorPane getApplicationContainer() {
@@ -333,15 +352,6 @@ public class MainViewCB extends ViewCB {
AnchorPane.setLeftAnchor(networkSyncPane, 0d);
AnchorPane.setBottomAnchor(networkSyncPane, 5d);
- // TODO sometimes it keeps running... deactivate ti for the moment and replace it with the notification pane
- // from Mike Hearn later
- networkSyncPane.setVisible(false);
-
- presentationModel.networkSyncComplete.addListener((ov, old, newValue) -> {
- if (newValue)
- networkSyncPane.downloadComplete();
- });
-
anchorPane.getChildren().addAll(leftNavPane, rightNavPane, contentContainer, networkSyncPane);
return anchorPane;
}
@@ -361,8 +371,6 @@ public class MainViewCB extends ViewCB {
msgButton = addNavButton(msgButtonHolder, "Messages", Navigation.Item.MSG);
leftNavPane.getChildren().add(msgButtonHolder);
- //addBalanceInfo(rightNavPane);
-
addBankAccountComboBox(rightNavPane);
settingsButton = addNavButton(rightNavPane, "Preferences", Navigation.Item.SETTINGS);
@@ -408,28 +416,6 @@ public class MainViewCB extends ViewCB {
return toggleButton;
}
- /*private void addBalanceInfo(Pane parent) {
- final TextField balanceTextField = new TextField();
- balanceTextField.setEditable(false);
- balanceTextField.setPrefWidth(110);
- balanceTextField.setId("nav-balance-label");
- balanceTextField.textProperty().bind(presentationModel.balance);
-
-
- final Label titleLabel = new Label("Balance");
- titleLabel.setMouseTransparent(true);
- titleLabel.setId("nav-button-label");
- balanceTextField.widthProperty().addListener((ov, o, n) ->
- titleLabel.setLayoutX(((double) n - titleLabel.getWidth()) / 2));
-
- final VBox vBox = new VBox();
- vBox.setPadding(new Insets(12, 5, 0, 0));
- vBox.setSpacing(2);
- vBox.getChildren().setAll(balanceTextField, titleLabel);
- vBox.setAlignment(Pos.CENTER);
- parent.getChildren().add(vBox);
- }*/
-
private void addBankAccountComboBox(Pane parent) {
final ComboBox comboBox = new ComboBox<>(presentationModel.getBankAccounts());
comboBox.setLayoutY(12);
@@ -460,4 +446,4 @@ public class MainViewCB extends ViewCB {
vBox.getChildren().setAll(comboBox, titleLabel);
parent.getChildren().add(vBox);
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/io/bitsquare/locale/BSResources.java b/src/main/java/io/bitsquare/locale/BSResources.java
index 216b1b61c5..386c02e791 100644
--- a/src/main/java/io/bitsquare/locale/BSResources.java
+++ b/src/main/java/io/bitsquare/locale/BSResources.java
@@ -48,7 +48,7 @@ public class BSResources {
try {
return BSResources.getResourceBundle().getString(key);
} catch (MissingResourceException e) {
- log.warn("MissingResourceException for key: " + key);
+ log.warn("Missing resource for key: " + key);
return key;
}
}
diff --git a/src/main/java/wallettemplate/controls/NotificationBarPane.java b/src/main/java/wallettemplate/controls/NotificationBarPane.java
new file mode 100644
index 0000000000..47024ab892
--- /dev/null
+++ b/src/main/java/wallettemplate/controls/NotificationBarPane.java
@@ -0,0 +1,142 @@
+package wallettemplate.controls;
+
+
+import javax.annotation.Nullable;
+
+import javafx.animation.Interpolator;
+import javafx.animation.KeyFrame;
+import javafx.animation.KeyValue;
+import javafx.animation.Timeline;
+import javafx.beans.property.SimpleStringProperty;
+import javafx.beans.value.ObservableDoubleValue;
+import javafx.collections.FXCollections;
+import javafx.collections.ListChangeListener;
+import javafx.collections.ObservableList;
+import javafx.scene.*;
+import javafx.scene.control.*;
+import javafx.scene.layout.*;
+import javafx.util.Duration;
+
+import wallettemplate.utils.GuiUtils;
+import wallettemplate.utils.easing.EasingMode;
+import wallettemplate.utils.easing.ElasticInterpolator;
+
+/**
+ * Wraps the given Node in a BorderPane and allows a thin bar to slide in from the bottom or top, squeezing the content
+ * node. The API allows different "items" to be added/removed and they will be displayed one at a time, fading between
+ * them when the topmost is removed. Each item is meant to be used for e.g. a background task and can contain a button
+ * and/or a progress bar.
+ */
+public class NotificationBarPane extends BorderPane {
+ public static final Duration ANIM_IN_DURATION = GuiUtils.UI_ANIMATION_TIME.multiply(2);
+ public static final Duration ANIM_OUT_DURATION = GuiUtils.UI_ANIMATION_TIME;
+
+ private HBox bar;
+ private Label label;
+ private double barHeight;
+ private ProgressBar progressBar;
+
+ public class Item {
+ public final SimpleStringProperty label;
+ @Nullable public final ObservableDoubleValue progress;
+
+ public Item(String label, @Nullable ObservableDoubleValue progress) {
+ this.label = new SimpleStringProperty(label);
+ this.progress = progress;
+ }
+
+ public void cancel() {
+ items.remove(this);
+ }
+ }
+
+ public final ObservableList- items;
+
+ public NotificationBarPane(Node content) {
+ super(content);
+ progressBar = new ProgressBar();
+ label = new Label("infobar!");
+ bar = new HBox(label);
+ bar.setMinHeight(0.0);
+ bar.getStyleClass().add("info-bar");
+ bar.setFillHeight(true);
+ setBottom(bar);
+ // Figure out the height of the bar based on the CSS. Must wait until after we've been added to the parent node.
+ sceneProperty().addListener(o -> {
+ if (getParent() == null) return;
+ getParent().applyCss();
+ getParent().layout();
+ barHeight = bar.getHeight();
+ bar.setPrefHeight(0.0);
+ });
+ items = FXCollections.observableArrayList();
+ items.addListener((ListChangeListener super Item>) change -> {
+ config();
+ showOrHide();
+ });
+ }
+
+ private void config() {
+ if (items.isEmpty()) return;
+ Item item = items.get(0);
+
+ bar.getChildren().clear();
+ label.textProperty().bind(item.label);
+ label.setMaxWidth(Double.MAX_VALUE);
+ HBox.setHgrow(label, Priority.ALWAYS);
+ bar.getChildren().add(label);
+ if (item.progress != null) {
+ progressBar.setMinWidth(200);
+ progressBar.progressProperty().bind(item.progress);
+ bar.getChildren().add(progressBar);
+ }
+ }
+
+ private void showOrHide() {
+ if (items.isEmpty())
+ animateOut();
+ else
+ animateIn();
+ }
+
+ public boolean isShowing() {
+ return bar.getPrefHeight() > 0;
+ }
+
+ private void animateIn() {
+ animate(barHeight);
+ }
+
+ private void animateOut() {
+ animate(0.0);
+ }
+
+ private Timeline timeline;
+
+ protected void animate(Number target) {
+ if (timeline != null) {
+ timeline.stop();
+ timeline = null;
+ }
+ Duration duration;
+ Interpolator interpolator;
+ if (target.intValue() > 0) {
+ interpolator = new ElasticInterpolator(EasingMode.EASE_OUT, 1, 2);
+ duration = ANIM_IN_DURATION;
+ }
+ else {
+ interpolator = Interpolator.EASE_OUT;
+ duration = ANIM_OUT_DURATION;
+ }
+ KeyFrame kf = new KeyFrame(duration, new KeyValue(bar.prefHeightProperty(), target, interpolator));
+ timeline = new Timeline(kf);
+ timeline.setOnFinished(x -> timeline = null);
+ timeline.play();
+ }
+
+ public Item pushItem(String string, @Nullable ObservableDoubleValue progress) {
+ Item i = new Item(string, progress);
+ items.add(i);
+ return i;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/wallettemplate/utils/GuiUtils.java b/src/main/java/wallettemplate/utils/GuiUtils.java
new file mode 100644
index 0000000000..1aaed136ff
--- /dev/null
+++ b/src/main/java/wallettemplate/utils/GuiUtils.java
@@ -0,0 +1,166 @@
+package wallettemplate.utils;
+
+import javafx.animation.Animation;
+import javafx.animation.FadeTransition;
+import javafx.animation.KeyFrame;
+import javafx.animation.KeyValue;
+import javafx.animation.ScaleTransition;
+import javafx.animation.Timeline;
+import javafx.application.Platform;
+import javafx.scene.*;
+import javafx.scene.effect.*;
+import javafx.scene.layout.*;
+import javafx.util.Duration;
+
+import static com.google.common.base.Preconditions.checkState;
+
+public class GuiUtils {
+ /*public static void runAlert(BiConsumer setup) {
+ try {
+ // JavaFX2 doesn't actually have a standard alert template. Instead the Scene Builder app will create FXML
+ // files for an alert window for you, and then you customise it as you see fit. I guess it makes sense in
+ // an odd sort of way.
+ Stage dialogStage = new Stage();
+ dialogStage.initModality(Modality.APPLICATION_MODAL);
+ FXMLLoader loader = new FXMLLoader(GuiUtils.class.getResource("alert.fxml"));
+ Pane pane = loader.load();
+ AlertWindowController controller = loader.getController();
+ setup.accept(dialogStage, controller);
+ dialogStage.setScene(new Scene(pane));
+ dialogStage.showAndWait();
+ } catch (IOException e) {
+ // We crashed whilst trying to show the alert dialog (this should never happen). Give up!
+ throw new RuntimeException(e);
+ }
+ }*/
+
+ /* public static void crashAlert(Throwable t) {
+ t.printStackTrace();
+ Throwable rootCause = Throwables.getRootCause(t);
+ Runnable r = () -> {
+ runAlert((stage, controller) -> controller.crashAlert(stage, rootCause.toString()));
+ Platform.exit();
+ };
+ if (Platform.isFxApplicationThread())
+ r.run();
+ else
+ Platform.runLater(r);
+ }*/
+
+ /**
+ * Show a GUI alert box for any unhandled exceptions that propagate out of this thread.
+ */
+ /*public static void handleCrashesOnThisThread() {
+ Thread.currentThread().setUncaughtExceptionHandler((thread, exception) -> {
+ GuiUtils.crashAlert(Throwables.getRootCause(exception));
+ });
+ }
+
+ public static void informationalAlert(String message, String details, Object... args) {
+ String formattedDetails = String.format(details, args);
+ Runnable r = () -> runAlert((stage, controller) -> controller.informational(stage, message, formattedDetails));
+ if (Platform.isFxApplicationThread())
+ r.run();
+ else
+ Platform.runLater(r);
+ }*/
+
+ public static final int UI_ANIMATION_TIME_MSEC = 600;
+ public static final Duration UI_ANIMATION_TIME = Duration.millis(UI_ANIMATION_TIME_MSEC);
+
+ public static Animation fadeIn(Node ui) {
+ return fadeIn(ui, 0);
+ }
+
+ public static Animation fadeIn(Node ui, int delayMillis) {
+ ui.setCache(true);
+ FadeTransition ft = new FadeTransition(Duration.millis(UI_ANIMATION_TIME_MSEC), ui);
+ ft.setFromValue(0.0);
+ ft.setToValue(1.0);
+ ft.setOnFinished(ev -> ui.setCache(false));
+ ft.setDelay(Duration.millis(delayMillis));
+ ft.play();
+ return ft;
+ }
+
+ public static Animation fadeOut(Node ui) {
+ FadeTransition ft = new FadeTransition(Duration.millis(UI_ANIMATION_TIME_MSEC), ui);
+ ft.setFromValue(ui.getOpacity());
+ ft.setToValue(0.0);
+ ft.play();
+ return ft;
+ }
+
+ public static Animation fadeOutAndRemove(Pane parentPane, Node... nodes) {
+ Animation animation = fadeOut(nodes[0]);
+ animation.setOnFinished(actionEvent -> parentPane.getChildren().removeAll(nodes));
+ return animation;
+ }
+
+ public static Animation fadeOutAndRemove(Duration duration, Pane parentPane, Node... nodes) {
+ nodes[0].setCache(true);
+ FadeTransition ft = new FadeTransition(duration, nodes[0]);
+ ft.setFromValue(nodes[0].getOpacity());
+ ft.setToValue(0.0);
+ ft.setOnFinished(actionEvent -> parentPane.getChildren().removeAll(nodes));
+ ft.play();
+ return ft;
+ }
+
+ public static void blurOut(Node node) {
+ GaussianBlur blur = new GaussianBlur(0.0);
+ node.setEffect(blur);
+ Timeline timeline = new Timeline();
+ KeyValue kv = new KeyValue(blur.radiusProperty(), 10.0);
+ KeyFrame kf = new KeyFrame(Duration.millis(UI_ANIMATION_TIME_MSEC), kv);
+ timeline.getKeyFrames().add(kf);
+ timeline.play();
+ }
+
+ public static void blurIn(Node node) {
+ GaussianBlur blur = (GaussianBlur) node.getEffect();
+ Timeline timeline = new Timeline();
+ KeyValue kv = new KeyValue(blur.radiusProperty(), 0.0);
+ KeyFrame kf = new KeyFrame(Duration.millis(UI_ANIMATION_TIME_MSEC), kv);
+ timeline.getKeyFrames().add(kf);
+ timeline.setOnFinished(actionEvent -> node.setEffect(null));
+ timeline.play();
+ }
+
+ public static ScaleTransition zoomIn(Node node) {
+ return zoomIn(node, 0);
+ }
+
+ public static ScaleTransition zoomIn(Node node, int delayMillis) {
+ return scaleFromTo(node, 0.95, 1.0, delayMillis);
+ }
+
+ public static ScaleTransition explodeOut(Node node) {
+ return scaleFromTo(node, 1.0, 1.05, 0);
+ }
+
+ private static ScaleTransition scaleFromTo(Node node, double from, double to, int delayMillis) {
+ ScaleTransition scale = new ScaleTransition(Duration.millis(UI_ANIMATION_TIME_MSEC / 2), node);
+ scale.setFromX(from);
+ scale.setFromY(from);
+ scale.setToX(to);
+ scale.setToY(to);
+ scale.setDelay(Duration.millis(delayMillis));
+ scale.play();
+ return scale;
+ }
+
+ /**
+ * A useful helper for development purposes. Used as a switch for loading files from local disk, allowing live
+ * editing whilst the app runs without rebuilds.
+ */
+ /* public static URL getResource(String name) {
+ if (false)
+ return unchecked(() -> new URL("file:///your/path/here/src/main/wallettemplate/" + name));
+ else
+ return MainController.class.getResource(name);
+ }*/
+ public static void checkGuiThread() {
+ checkState(Platform.isFxApplicationThread());
+ }
+}
diff --git a/src/main/java/wallettemplate/utils/WTUtils.java b/src/main/java/wallettemplate/utils/WTUtils.java
new file mode 100644
index 0000000000..2293f926d8
--- /dev/null
+++ b/src/main/java/wallettemplate/utils/WTUtils.java
@@ -0,0 +1,87 @@
+/*
+ * 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 wallettemplate.utils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Some generic utilities to make Java a bit less annoying.
+ */
+public class WTUtils {
+ private static final Logger log = LoggerFactory.getLogger(WTUtils.class);
+
+ public interface UncheckedRun {
+ public T run() throws Throwable;
+ }
+
+ public interface UncheckedRunnable {
+ public void run() throws Throwable;
+ }
+
+ public static T unchecked(UncheckedRun run) {
+ try {
+ return run.run();
+ } catch (Throwable throwable) {
+ throw new RuntimeException(throwable);
+ }
+ }
+
+ public static void uncheck(UncheckedRunnable run) {
+ try {
+ run.run();
+ } catch (Throwable throwable) {
+ throw new RuntimeException(throwable);
+ }
+ }
+
+ public static void ignoreAndLog(UncheckedRunnable runnable) {
+ try {
+ runnable.run();
+ } catch (Throwable t) {
+ log.error("Ignoring error", t);
+ }
+ }
+
+ public static T ignoredAndLogged(UncheckedRun runnable) {
+ try {
+ return runnable.run();
+ } catch (Throwable t) {
+ log.error("Ignoring error", t);
+ return null;
+ }
+ }
+
+ public static boolean didThrow(UncheckedRun run) {
+ try {
+ run.run();
+ return false;
+ } catch (Throwable throwable) {
+ return true;
+ }
+ }
+
+ public static boolean didThrow(UncheckedRunnable run) {
+ try {
+ run.run();
+ return false;
+ } catch (Throwable throwable) {
+ return true;
+ }
+ }
+}
diff --git a/src/main/java/wallettemplate/utils/easing/EasingInterpolator.java b/src/main/java/wallettemplate/utils/easing/EasingInterpolator.java
new file mode 100644
index 0000000000..5c2adef59c
--- /dev/null
+++ b/src/main/java/wallettemplate/utils/easing/EasingInterpolator.java
@@ -0,0 +1,134 @@
+/*
+ * 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 .
+ */
+
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, Christian Schudt
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package wallettemplate.utils.easing;
+
+import javafx.animation.Interpolator;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleObjectProperty;
+
+/**
+ * The abstract base class for all easing interpolators.
+ *
+ * @author Christian Schudt
+ */
+public abstract class EasingInterpolator extends Interpolator {
+
+ /**
+ * The easing mode.
+ */
+ private ObjectProperty easingMode = new SimpleObjectProperty<>(EasingMode.EASE_OUT);
+
+ /**
+ * Constructs the interpolator with a specific easing mode.
+ *
+ * @param easingMode The easing mode.
+ */
+ public EasingInterpolator(EasingMode easingMode) {
+ this.easingMode.set(easingMode);
+ }
+
+ /**
+ * The easing mode property.
+ *
+ * @return The property.
+ * @see #getEasingMode()
+ * @see #setEasingMode(EasingMode)
+ */
+ public ObjectProperty easingModeProperty() {
+ return easingMode;
+ }
+
+ /**
+ * Gets the easing mode.
+ *
+ * @return The easing mode.
+ * @see #easingModeProperty()
+ */
+ public EasingMode getEasingMode() {
+ return easingMode.get();
+ }
+
+ /**
+ * Sets the easing mode.
+ *
+ * @param easingMode The easing mode.
+ * @see #easingModeProperty()
+ */
+ public void setEasingMode(EasingMode easingMode) {
+ this.easingMode.set(easingMode);
+ }
+
+ /**
+ * Defines the base curve for the interpolator.
+ * The base curve is then transformed into an easing-in, easing-out easing-both curve.
+ *
+ * @param v The normalized value/time/progress of the interpolation (between 0 and 1).
+ * @return The resulting value of the function, should return a value between 0 and 1.
+ * @see javafx.animation.Interpolator#curve(double)
+ */
+ protected abstract double baseCurve(final double v);
+
+ /**
+ * Curves the function depending on the easing mode.
+ *
+ * @param v The normalized value (between 0 and 1).
+ * @return The resulting value of the function.
+ */
+ @Override
+ protected final double curve(final double v) {
+ switch (easingMode.get()) {
+ case EASE_IN:
+ return baseCurve(v);
+ case EASE_OUT:
+ return 1 - baseCurve(1 - v);
+ case EASE_BOTH:
+ if (v <= 0.5) {
+ return baseCurve(2 * v) / 2;
+ }
+ else {
+ return (2 - baseCurve(2 * (1 - v))) / 2;
+ }
+
+ }
+ return baseCurve(v);
+ }
+}
diff --git a/src/main/java/wallettemplate/utils/easing/EasingMode.java b/src/main/java/wallettemplate/utils/easing/EasingMode.java
new file mode 100644
index 0000000000..46b29bbe12
--- /dev/null
+++ b/src/main/java/wallettemplate/utils/easing/EasingMode.java
@@ -0,0 +1,12 @@
+package wallettemplate.utils.easing;
+
+/**
+ * Defines the three easing modes, ease-in, ease-out and ease-both.
+ *
+ * @author Christian Schudt
+ */
+public enum EasingMode {
+ EASE_IN,
+ EASE_OUT,
+ EASE_BOTH
+}
diff --git a/src/main/java/wallettemplate/utils/easing/ElasticInterpolator.java b/src/main/java/wallettemplate/utils/easing/ElasticInterpolator.java
new file mode 100644
index 0000000000..f627f217c0
--- /dev/null
+++ b/src/main/java/wallettemplate/utils/easing/ElasticInterpolator.java
@@ -0,0 +1,180 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, Christian Schudt
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package wallettemplate.utils.easing;
+
+import javafx.beans.property.DoubleProperty;
+import javafx.beans.property.SimpleDoubleProperty;
+
+/**
+ * This interpolator simulates an elastic behavior.
+ *
+ * The following curve illustrates the interpolation.
+ *
+ *
+ *
+ * The math in this class is taken from
+ * http://www.robertpenner.com/easing/.
+ *
+ * @author Christian Schudt
+ */
+public class ElasticInterpolator extends EasingInterpolator {
+
+ /**
+ * The amplitude.
+ */
+ private DoubleProperty amplitude = new SimpleDoubleProperty(this, "amplitude", 1);
+
+ /**
+ * The number of oscillations.
+ */
+ private DoubleProperty oscillations = new SimpleDoubleProperty(this, "oscillations", 3);
+
+ /**
+ * Default constructor. Initializes the interpolator with ease out mode.
+ */
+ public ElasticInterpolator() {
+ this(EasingMode.EASE_OUT);
+ }
+
+ /**
+ * Constructs the interpolator with a specific easing mode.
+ *
+ * @param easingMode The easing mode.
+ */
+ public ElasticInterpolator(EasingMode easingMode) {
+ super(easingMode);
+ }
+
+ /**
+ * Sets the easing mode.
+ *
+ * @param easingMode The easing mode.
+ * @see #easingModeProperty()
+ */
+ public ElasticInterpolator(EasingMode easingMode, double amplitude, double oscillations) {
+ super(easingMode);
+ this.amplitude.set(amplitude);
+ this.oscillations.set(oscillations);
+ }
+
+ /**
+ * The oscillations property. Defines number of oscillations.
+ *
+ * @return The property.
+ * @see #getOscillations()
+ * @see #setOscillations(double)
+ */
+ public DoubleProperty oscillationsProperty() {
+ return oscillations;
+ }
+
+ /**
+ * The amplitude. The minimum value is 1. If this value is < 1 it will be set to 1 during animation.
+ *
+ * @return The property.
+ * @see #getAmplitude()
+ * @see #setAmplitude(double)
+ */
+ public DoubleProperty amplitudeProperty() {
+ return amplitude;
+ }
+
+ /**
+ * Gets the amplitude.
+ *
+ * @return The amplitude.
+ * @see #amplitudeProperty()
+ */
+ public double getAmplitude() {
+ return amplitude.get();
+ }
+
+ /**
+ * Sets the amplitude.
+ *
+ * @param amplitude The amplitude.
+ * @see #amplitudeProperty()
+ */
+ public void setAmplitude(final double amplitude) {
+ this.amplitude.set(amplitude);
+ }
+
+ /**
+ * Gets the number of oscillations.
+ *
+ * @return The oscillations.
+ * @see #oscillationsProperty()
+ */
+ public double getOscillations() {
+ return oscillations.get();
+ }
+
+ /**
+ * Sets the number of oscillations.
+ *
+ * @param oscillations The oscillations.
+ * @see #oscillationsProperty()
+ */
+ public void setOscillations(final double oscillations) {
+ this.oscillations.set(oscillations);
+ }
+
+ @Override
+ protected double baseCurve(double v) {
+ if (v == 0) {
+ return 0;
+ }
+ if (v == 1) {
+ return 1;
+ }
+ double p = 1.0 / oscillations.get();
+ double a = amplitude.get();
+ double s;
+ if (a < Math.abs(1)) {
+ a = 1;
+ s = p / 4;
+ }
+ else {
+ s = p / (2 * Math.PI) * Math.asin(1 / a);
+ }
+ return -(a * Math.pow(2, 10 * (v -= 1)) * Math.sin((v - s) * (2 * Math.PI) / p));
+ }
+}
diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml
index 75ed2bdde6..ddc54c46ec 100644
--- a/src/main/resources/logback.xml
+++ b/src/main/resources/logback.xml
@@ -25,7 +25,7 @@
-
+
@@ -36,6 +36,10 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+