From 24d29eaa833ba79f55e4c5388178152fca442e6e Mon Sep 17 00:00:00 2001 From: Manfred Karrer Date: Thu, 16 Apr 2015 17:53:03 +0200 Subject: [PATCH] Add footer with status info --- core/pom.xml | 18 -- .../java/io/bitsquare/btc/WalletService.java | 25 ++- .../java/io/bitsquare/p2p/BootstrapState.java | 47 ---- .../java/io/bitsquare/p2p/ClientNode.java | 6 +- .../java/io/bitsquare/p2p/ConnectionType.java | 22 -- .../p2p/tomp2p/BootstrappedPeerBuilder.java | 104 ++++++--- .../io/bitsquare/p2p/tomp2p/TomP2PNode.java | 24 +- .../java/io/bitsquare/msg/TomP2PTests.java | 39 ++-- gui/pom.xml | 7 - .../java/io/bitsquare/app/BitsquareApp.java | 2 +- .../main/java/io/bitsquare/gui/bitsquare.css | 15 ++ .../java/io/bitsquare/gui/main/MainView.java | 208 +++++++++++++++++- .../io/bitsquare/gui/main/MainViewModel.java | 47 ++-- .../settings/network/NetworkSettingsView.java | 9 +- .../io/bitsquare/gui/util/BSFormatter.java | 14 ++ 15 files changed, 380 insertions(+), 207 deletions(-) delete mode 100644 core/src/main/java/io/bitsquare/p2p/BootstrapState.java delete mode 100644 core/src/main/java/io/bitsquare/p2p/ConnectionType.java diff --git a/core/pom.xml b/core/pom.xml index 930cd2cde0..967e18d3df 100755 --- a/core/pom.xml +++ b/core/pom.xml @@ -13,24 +13,6 @@ - - - false - ${basedir}/src/main/java - - **/*.fxml - **/*.css - - - - false - ${basedir}/src/main/resources - - **/*.* - - - - org.apache.maven.plugins diff --git a/core/src/main/java/io/bitsquare/btc/WalletService.java b/core/src/main/java/io/bitsquare/btc/WalletService.java index df3eab5086..a88da2850d 100644 --- a/core/src/main/java/io/bitsquare/btc/WalletService.java +++ b/core/src/main/java/io/bitsquare/btc/WalletService.java @@ -66,6 +66,10 @@ import java.util.stream.Collectors; import javax.inject.Inject; import javax.inject.Named; +import javafx.beans.property.DoubleProperty; +import javafx.beans.property.ReadOnlyDoubleProperty; +import javafx.beans.property.SimpleDoubleProperty; + import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; @@ -87,8 +91,7 @@ public class WalletService { private final List txConfidenceListeners = new CopyOnWriteArrayList<>(); private final List balanceListeners = new CopyOnWriteArrayList<>(); - private final ObservableDownloadListener downloadListener = new ObservableDownloadListener(); - private final Observable downloadProgress = downloadListener.getObservable(); + private final DownloadListener downloadListener = new DownloadListener(); private final WalletEventListener walletEventListener = new BitsquareWalletEventListener(); private RegTestHost regTestHost; @@ -209,7 +212,6 @@ public class WalletService { walletAppKit.startAsync(); return status.timeout(30, TimeUnit.SECONDS); - //return status.mergeWith(downloadProgress).timeout(30, TimeUnit.SECONDS); } private void initWallet() { @@ -227,8 +229,8 @@ public class WalletService { walletAppKit.stopAsync(); } - public Observable getDownloadProgress() { - return downloadProgress; + public ReadOnlyDoubleProperty downloadPercentageProperty() { + return downloadListener.percentageProperty(); } public Wallet getWallet() { @@ -536,24 +538,23 @@ public class WalletService { // Inner classes /////////////////////////////////////////////////////////////////////////////////////////// - private static class ObservableDownloadListener extends DownloadProgressTracker { - - private final Subject subject = BehaviorSubject.create(0d); + private static class DownloadListener extends DownloadProgressTracker { + private final DoubleProperty percentage = new SimpleDoubleProperty(-1); @Override protected void progress(double percentage, int blocksLeft, Date date) { super.progress(percentage, blocksLeft, date); - subject.onNext(percentage); + Threading.USER_THREAD.execute(() -> this.percentage.set(percentage / 100d)); } @Override protected void doneDownload() { super.doneDownload(); - subject.onCompleted(); + Threading.USER_THREAD.execute(() -> this.percentage.set(1)); } - public Observable getObservable() { - return subject.asObservable(); + public ReadOnlyDoubleProperty percentageProperty() { + return percentage; } } diff --git a/core/src/main/java/io/bitsquare/p2p/BootstrapState.java b/core/src/main/java/io/bitsquare/p2p/BootstrapState.java deleted file mode 100644 index e9ca1f5d86..0000000000 --- a/core/src/main/java/io/bitsquare/p2p/BootstrapState.java +++ /dev/null @@ -1,47 +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.p2p; - -public enum BootstrapState { - PEER_CREATION_FAILED, - DISCOVERY_STARTED, - DISCOVERY_DIRECT_SUCCEEDED, - DISCOVERY_MANUAL_PORT_FORWARDING_SUCCEEDED, - DISCOVERY_FAILED, - DISCOVERY_AUTO_PORT_FORWARDING_STARTED, - DISCOVERY_AUTO_PORT_FORWARDING_SUCCEEDED, - DISCOVERY_AUTO_PORT_FORWARDING_FAILED, - RELAY_STARTED, - RELAY_SUCCEEDED, - RELAY_FAILED, - BOOT_STRAP_SUCCEEDED, - BOOT_STRAP_FAILED; - - private String message; - - BootstrapState() { - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } -} diff --git a/core/src/main/java/io/bitsquare/p2p/ClientNode.java b/core/src/main/java/io/bitsquare/p2p/ClientNode.java index d3d96e25c4..4f6e4a5b4f 100644 --- a/core/src/main/java/io/bitsquare/p2p/ClientNode.java +++ b/core/src/main/java/io/bitsquare/p2p/ClientNode.java @@ -17,16 +17,18 @@ package io.bitsquare.p2p; +import io.bitsquare.p2p.tomp2p.BootstrappedPeerBuilder; + import java.security.KeyPair; import rx.Observable; public interface ClientNode { - ConnectionType getConnectionType(); + BootstrappedPeerBuilder.ConnectionType getConnectionType(); Node getAddress(); Node getBootstrapNodeAddress(); - Observable bootstrap(KeyPair keyPair); + Observable bootstrap(KeyPair keyPair); } diff --git a/core/src/main/java/io/bitsquare/p2p/ConnectionType.java b/core/src/main/java/io/bitsquare/p2p/ConnectionType.java deleted file mode 100644 index acfa2da464..0000000000 --- a/core/src/main/java/io/bitsquare/p2p/ConnectionType.java +++ /dev/null @@ -1,22 +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.p2p; - -public enum ConnectionType { - UNKNOWN, DIRECT, MANUAL_PORT_FORWARDING, AUTO_PORT_FORWARDING, RELAY -} diff --git a/core/src/main/java/io/bitsquare/p2p/tomp2p/BootstrappedPeerBuilder.java b/core/src/main/java/io/bitsquare/p2p/tomp2p/BootstrappedPeerBuilder.java index 5089f6b3fc..f43c216dd3 100644 --- a/core/src/main/java/io/bitsquare/p2p/tomp2p/BootstrappedPeerBuilder.java +++ b/core/src/main/java/io/bitsquare/p2p/tomp2p/BootstrappedPeerBuilder.java @@ -17,7 +17,6 @@ package io.bitsquare.p2p.tomp2p; -import io.bitsquare.p2p.BootstrapState; import io.bitsquare.p2p.Node; import com.google.common.util.concurrent.SettableFuture; @@ -34,6 +33,7 @@ import java.security.KeyPair; import javax.inject.Inject; import javafx.beans.property.ObjectProperty; +import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.SimpleObjectProperty; import net.tomp2p.connection.Bindings; @@ -76,6 +76,40 @@ public class BootstrappedPeerBuilder { static final String NETWORK_INTERFACE_UNSPECIFIED = ""; static final String USE_MANUAL_PORT_FORWARDING_KEY = "node.useManualPortForwarding"; + public enum ConnectionType { + UNDEFINED, DIRECT, MANUAL_PORT_FORWARDING, AUTO_PORT_FORWARDING, RELAY + } + + public enum State { + UNDEFINED, + PEER_CREATION_FAILED, + DISCOVERY_STARTED, + DISCOVERY_DIRECT_SUCCEEDED, + DISCOVERY_MANUAL_PORT_FORWARDING_SUCCEEDED, + DISCOVERY_FAILED, + DISCOVERY_AUTO_PORT_FORWARDING_STARTED, + DISCOVERY_AUTO_PORT_FORWARDING_SUCCEEDED, + DISCOVERY_AUTO_PORT_FORWARDING_FAILED, + RELAY_STARTED, + RELAY_SUCCEEDED, + RELAY_FAILED, + BOOT_STRAP_SUCCEEDED, + BOOT_STRAP_FAILED; + + private String message; + + State() { + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + } + private KeyPair keyPair; private final int port; private final boolean useManualPortForwarding; @@ -84,7 +118,8 @@ public class BootstrappedPeerBuilder { private final SettableFuture settableFuture = SettableFuture.create(); - private final ObjectProperty bootstrapState = new SimpleObjectProperty<>(); + private final ObjectProperty state = new SimpleObjectProperty<>(State.UNDEFINED); + private final ObjectProperty connectionType = new SimpleObjectProperty<>(ConnectionType.UNDEFINED); private Peer peer; private PeerDHT peerDHT; @@ -175,7 +210,7 @@ public class BootstrappedPeerBuilder { discoverExternalAddress(); } catch (IOException e) { - handleError(BootstrapState.PEER_CREATION_FAILED, "Cannot create a peer with port: " + + handleError(State.PEER_CREATION_FAILED, "Cannot create a peer with port: " + port + ". Exception: " + e); } @@ -202,7 +237,7 @@ public class BootstrappedPeerBuilder { private void discoverExternalAddress() { FutureDiscover futureDiscover = peer.discover().peerAddress(getBootstrapAddress()).start(); - setState(BootstrapState.DISCOVERY_STARTED, "Starting discovery..."); + setState(State.DISCOVERY_STARTED); PeerNAT peerNAT = new PeerBuilderNAT(peer).start(); FutureNAT futureNAT = peerNAT.startSetupPortforwarding(futureDiscover); FutureRelayNAT futureRelayNAT = peerNAT.startRelay(new TCPRelayClientConfig(), futureDiscover, futureNAT); @@ -212,32 +247,35 @@ public class BootstrappedPeerBuilder { public void operationComplete(BaseFuture futureRelayNAT) throws Exception { if (futureDiscover.isSuccess()) { if (useManualPortForwarding) { - setState(BootstrapState.DISCOVERY_MANUAL_PORT_FORWARDING_SUCCEEDED, - "Now visible to the Bitsquare network (with manual port forwarding)."); + setState(State.DISCOVERY_MANUAL_PORT_FORWARDING_SUCCEEDED, + "NAT traversal successful with manual port forwarding."); + setConnectionType(ConnectionType.MANUAL_PORT_FORWARDING); bootstrap(); } else { - setState(BootstrapState.DISCOVERY_DIRECT_SUCCEEDED, "Now visible to the Bitsquare network."); + setState(State.DISCOVERY_DIRECT_SUCCEEDED, "Visible to the network. No NAT traversal needed."); + setConnectionType(ConnectionType.DIRECT); bootstrap(); } } else { - setState(BootstrapState.DISCOVERY_AUTO_PORT_FORWARDING_STARTED, - "Configuring automatic port forwarding"); + setState(State.DISCOVERY_AUTO_PORT_FORWARDING_STARTED); if (futureNAT.isSuccess()) { - setState(BootstrapState.DISCOVERY_AUTO_PORT_FORWARDING_SUCCEEDED, - "Now visible to the Bitsquare network (with automatic port forwarding)."); + setState(State.DISCOVERY_AUTO_PORT_FORWARDING_SUCCEEDED, + "NAT traversal successful with automatic port forwarding."); + setConnectionType(ConnectionType.AUTO_PORT_FORWARDING); bootstrap(); } else { if (futureRelayNAT.isSuccess()) { // relay mode succeeded - setState(BootstrapState.RELAY_SUCCEEDED, "Bootstrap using relay was successful."); + setState(State.RELAY_SUCCEEDED, "NAT traversal not successful. Using relay mode."); + setConnectionType(ConnectionType.RELAY); bootstrap(); } else { // All attempts failed. Give up... - handleError(BootstrapState.RELAY_FAILED, "Bootstrap using relay has failed " + + handleError(State.RELAY_FAILED, "NAT traversal using relay mode failed " + futureRelayNAT.failedReason()); } } @@ -246,7 +284,7 @@ public class BootstrappedPeerBuilder { @Override public void exceptionCaught(Throwable t) throws Exception { - handleError(BootstrapState.RELAY_FAILED, "Exception at bootstrap: " + t.getMessage()); + handleError(State.RELAY_FAILED, "Exception at bootstrap: " + t.getMessage()); } }); } @@ -263,18 +301,18 @@ public class BootstrappedPeerBuilder { public void operationComplete(BaseFuture future) throws Exception { if (futureBootstrap.isSuccess()) { log.trace("bootstrap complete"); - setState(BootstrapState.BOOT_STRAP_SUCCEEDED, "Bootstrap using relay was successful."); + setState(State.BOOT_STRAP_SUCCEEDED, "Bootstrap was successful."); settableFuture.set(peerDHT); } else { - handleError(BootstrapState.BOOT_STRAP_FAILED, "Bootstrapping failed. " + + handleError(State.BOOT_STRAP_FAILED, "Bootstrap failed. " + futureBootstrap.failedReason()); } } @Override public void exceptionCaught(Throwable t) throws Exception { - handleError(BootstrapState.BOOT_STRAP_FAILED, "Exception at bootstrap: " + t.getMessage()); + handleError(State.BOOT_STRAP_FAILED, "Exception at bootstrap: " + t.getMessage()); } }); } @@ -295,25 +333,41 @@ public class BootstrappedPeerBuilder { return bootstrapNode; } - public ObjectProperty getBootstrapState() { - return bootstrapState; + public ConnectionType getConnectionType() { + return connectionType.get(); } - private void setState(BootstrapState bootstrapState, String message) { - setState(bootstrapState, message, true); + public ReadOnlyObjectProperty connectionTypeProperty() { + return connectionType; } - private void setState(BootstrapState bootstrapState, String message, boolean isSuccess) { + private void setConnectionType(ConnectionType discoveryState) { + this.connectionType.set(discoveryState); + } + + public ObjectProperty getState() { + return state; + } + + private void setState(State state) { + setState(state, "", true); + } + + private void setState(State state, String message) { + setState(state, message, true); + } + + private void setState(State state, String message, boolean isSuccess) { if (isSuccess) log.info(message); else log.error(message); - bootstrapState.setMessage(message); - this.bootstrapState.set(bootstrapState); + state.setMessage(message); + this.state.set(state); } - private void handleError(BootstrapState state, String errorMessage) { + private void handleError(State state, String errorMessage) { setState(state, errorMessage, false); peerDHT.shutdown(); settableFuture.setException(new Exception(errorMessage)); diff --git a/core/src/main/java/io/bitsquare/p2p/tomp2p/TomP2PNode.java b/core/src/main/java/io/bitsquare/p2p/tomp2p/TomP2PNode.java index 9478563480..a8dc512a67 100644 --- a/core/src/main/java/io/bitsquare/p2p/tomp2p/TomP2PNode.java +++ b/core/src/main/java/io/bitsquare/p2p/tomp2p/TomP2PNode.java @@ -19,9 +19,7 @@ package io.bitsquare.p2p.tomp2p; import io.bitsquare.BitsquareException; import io.bitsquare.common.handlers.ResultHandler; -import io.bitsquare.p2p.BootstrapState; import io.bitsquare.p2p.ClientNode; -import io.bitsquare.p2p.ConnectionType; import io.bitsquare.p2p.Node; import com.google.common.util.concurrent.FutureCallback; @@ -54,7 +52,7 @@ public class TomP2PNode implements ClientNode { private PeerDHT peerDHT; private BootstrappedPeerBuilder bootstrappedPeerBuilder; - private final Subject bootstrapStateSubject; + private final Subject bootstrapStateSubject; private final List resultHandlers = new CopyOnWriteArrayList<>(); @@ -80,10 +78,10 @@ public class TomP2PNode implements ClientNode { // Public methods /////////////////////////////////////////////////////////////////////////////////////////// - public Observable bootstrap(KeyPair keyPair) { + public Observable bootstrap(KeyPair keyPair) { bootstrappedPeerBuilder.setKeyPair(keyPair); - bootstrappedPeerBuilder.getBootstrapState().addListener((ov, oldValue, newValue) -> { + bootstrappedPeerBuilder.getState().addListener((ov, oldValue, newValue) -> { log.debug("BootstrapState changed " + newValue); bootstrapStateSubject.onNext(newValue); }); @@ -118,20 +116,8 @@ public class TomP2PNode implements ClientNode { } @Override - public ConnectionType getConnectionType() { - BootstrapState bootstrapState = bootstrappedPeerBuilder.getBootstrapState().get(); - switch (bootstrapState) { - case DISCOVERY_DIRECT_SUCCEEDED: - return ConnectionType.DIRECT; - case DISCOVERY_MANUAL_PORT_FORWARDING_SUCCEEDED: - return ConnectionType.MANUAL_PORT_FORWARDING; - case DISCOVERY_AUTO_PORT_FORWARDING_SUCCEEDED: - return ConnectionType.AUTO_PORT_FORWARDING; - case RELAY_SUCCEEDED: - return ConnectionType.RELAY; - default: - throw new BitsquareException("Invalid bootstrap state: %s", bootstrapState); - } + public BootstrappedPeerBuilder.ConnectionType getConnectionType() { + return bootstrappedPeerBuilder.getConnectionType(); } @Override diff --git a/core/src/test/java/io/bitsquare/msg/TomP2PTests.java b/core/src/test/java/io/bitsquare/msg/TomP2PTests.java index e2241fbdb9..249fc07e12 100644 --- a/core/src/test/java/io/bitsquare/msg/TomP2PTests.java +++ b/core/src/test/java/io/bitsquare/msg/TomP2PTests.java @@ -18,8 +18,8 @@ package io.bitsquare.msg; import io.bitsquare.p2p.BootstrapNodes; -import io.bitsquare.p2p.ConnectionType; import io.bitsquare.p2p.Node; +import io.bitsquare.p2p.tomp2p.BootstrappedPeerBuilder; import io.bitsquare.util.Repeat; import io.bitsquare.util.RepeatRule; @@ -84,11 +84,11 @@ public class TomP2PTests { private static final Logger log = LoggerFactory.getLogger(TomP2PTests.class); // If you want to test in one specific connection mode define it directly, otherwise use UNKNOWN - private static final ConnectionType FORCED_CONNECTION_TYPE = ConnectionType.RELAY; + private static final BootstrappedPeerBuilder.ConnectionType FORCED_CONNECTION_TYPE = BootstrappedPeerBuilder.ConnectionType.RELAY; // Typically you run the bootstrap node in localhost to test direct connection. // If you have a setup where you are not behind a router you can also use a WAN bootstrap node. - private static final Node BOOTSTRAP_NODE = (FORCED_CONNECTION_TYPE == ConnectionType.DIRECT) ? + private static final Node BOOTSTRAP_NODE = (FORCED_CONNECTION_TYPE == BootstrappedPeerBuilder.ConnectionType.DIRECT) ? BootstrapNodes.LOCALHOST : Node.at("digitalocean1.dev.bitsquare.io", "188.226.179.109", 7367); private static final PeerAddress BOOTSTRAP_NODE_ADDRESS; @@ -111,7 +111,7 @@ public class TomP2PTests { private PeerDHT peer2DHT; private int client1Port; private int client2Port; - private ConnectionType resolvedConnectionType; + private BootstrappedPeerBuilder.ConnectionType resolvedConnectionType; public @Rule RepeatRule repeatRule = new RepeatRule(); @Before @@ -135,7 +135,7 @@ public class TomP2PTests { @Test @Repeat(STRESS_TEST_COUNT) public void bootstrapInUnknownMode() throws Exception { - if (FORCED_CONNECTION_TYPE == ConnectionType.UNKNOWN) { + if (FORCED_CONNECTION_TYPE == BootstrappedPeerBuilder.ConnectionType.UNDEFINED) { peer = bootstrapInUnknownMode(client1Port); assertNotNull(peer); } @@ -144,7 +144,7 @@ public class TomP2PTests { @Test @Repeat(STRESS_TEST_COUNT) public void testBootstrapDirectConnection() throws Exception { - if (FORCED_CONNECTION_TYPE == ConnectionType.DIRECT) { + if (FORCED_CONNECTION_TYPE == BootstrappedPeerBuilder.ConnectionType.DIRECT) { peer = bootstrapDirectConnection(client1Port); assertNotNull(peer); } @@ -153,8 +153,8 @@ public class TomP2PTests { @Test @Repeat(STRESS_TEST_COUNT) public void testBootstrapWithPortForwarding() throws Exception { - if (FORCED_CONNECTION_TYPE == ConnectionType.AUTO_PORT_FORWARDING || - FORCED_CONNECTION_TYPE == ConnectionType.MANUAL_PORT_FORWARDING) { + if (FORCED_CONNECTION_TYPE == BootstrappedPeerBuilder.ConnectionType.AUTO_PORT_FORWARDING || + FORCED_CONNECTION_TYPE == BootstrappedPeerBuilder.ConnectionType.MANUAL_PORT_FORWARDING) { peer = bootstrapWithPortForwarding(client2Port); assertNotNull(peer); } @@ -163,7 +163,7 @@ public class TomP2PTests { @Test @Repeat(STRESS_TEST_COUNT) public void testBootstrapInRelayMode() throws Exception { - if (FORCED_CONNECTION_TYPE == ConnectionType.RELAY) { + if (FORCED_CONNECTION_TYPE == BootstrappedPeerBuilder.ConnectionType.RELAY) { peer = bootstrapInRelayMode(client1Port); assertNotNull(peer); } @@ -498,7 +498,8 @@ public class TomP2PTests { @Test @Repeat(STRESS_TEST_COUNT) public void testSendDirectBetweenLocalPeers() throws Exception { - if (FORCED_CONNECTION_TYPE == ConnectionType.DIRECT || resolvedConnectionType == ConnectionType.DIRECT) { + if (FORCED_CONNECTION_TYPE == BootstrappedPeerBuilder.ConnectionType.DIRECT || resolvedConnectionType == BootstrappedPeerBuilder.ConnectionType + .DIRECT) { peer1DHT = getDHTPeer(client1Port); peer2DHT = getDHTPeer(client2Port); @@ -594,8 +595,8 @@ public class TomP2PTests { Number160 peerId = Number160.createHash(UUID.randomUUID().toString()); Peer peer = null; try { - if (FORCED_CONNECTION_TYPE == ConnectionType.MANUAL_PORT_FORWARDING || - resolvedConnectionType == ConnectionType.MANUAL_PORT_FORWARDING) { + if (FORCED_CONNECTION_TYPE == BootstrappedPeerBuilder.ConnectionType.MANUAL_PORT_FORWARDING || + resolvedConnectionType == BootstrappedPeerBuilder.ConnectionType.MANUAL_PORT_FORWARDING) { peer = new PeerBuilder(peerId).bindings(getBindings()) .behindFirewall() .tcpPortForwarding(clientPort) @@ -700,22 +701,22 @@ public class TomP2PTests { } private Peer bootstrapInUnknownMode(int clientPort) { - resolvedConnectionType = ConnectionType.DIRECT; + resolvedConnectionType = BootstrappedPeerBuilder.ConnectionType.DIRECT; Peer peer = bootstrapDirectConnection(clientPort); if (peer != null) return peer; - resolvedConnectionType = ConnectionType.MANUAL_PORT_FORWARDING; + resolvedConnectionType = BootstrappedPeerBuilder.ConnectionType.MANUAL_PORT_FORWARDING; peer = bootstrapWithPortForwarding(clientPort); if (peer != null) return peer; - resolvedConnectionType = ConnectionType.AUTO_PORT_FORWARDING; + resolvedConnectionType = BootstrappedPeerBuilder.ConnectionType.AUTO_PORT_FORWARDING; peer = bootstrapWithPortForwarding(clientPort); if (peer != null) return peer; - resolvedConnectionType = ConnectionType.RELAY; + resolvedConnectionType = BootstrappedPeerBuilder.ConnectionType.RELAY; peer = bootstrapInRelayMode(clientPort); if (peer != null) return peer; @@ -728,13 +729,13 @@ public class TomP2PTests { private PeerDHT getDHTPeer(int clientPort) { Peer peer; - if (FORCED_CONNECTION_TYPE == ConnectionType.DIRECT) { + if (FORCED_CONNECTION_TYPE == BootstrappedPeerBuilder.ConnectionType.DIRECT) { peer = bootstrapDirectConnection(clientPort); } - else if (FORCED_CONNECTION_TYPE == ConnectionType.AUTO_PORT_FORWARDING) { + else if (FORCED_CONNECTION_TYPE == BootstrappedPeerBuilder.ConnectionType.AUTO_PORT_FORWARDING) { peer = bootstrapWithPortForwarding(clientPort); } - else if (FORCED_CONNECTION_TYPE == ConnectionType.RELAY) { + else if (FORCED_CONNECTION_TYPE == BootstrappedPeerBuilder.ConnectionType.RELAY) { peer = bootstrapInRelayMode(clientPort); } else { diff --git a/gui/pom.xml b/gui/pom.xml index 121aada48e..578f3a48d2 100644 --- a/gui/pom.xml +++ b/gui/pom.xml @@ -39,13 +39,6 @@ **/*.css - - false - ${basedir}/src/main/resources - - **/*.* - - diff --git a/gui/src/main/java/io/bitsquare/app/BitsquareApp.java b/gui/src/main/java/io/bitsquare/app/BitsquareApp.java index c266930ea3..8f4c66a64b 100644 --- a/gui/src/main/java/io/bitsquare/app/BitsquareApp.java +++ b/gui/src/main/java/io/bitsquare/app/BitsquareApp.java @@ -91,7 +91,7 @@ public class BitsquareApp extends Application { CachingViewLoader viewLoader = injector.getInstance(CachingViewLoader.class); View view = viewLoader.load(MainView.class); - scene = new Scene((Parent) view.getRoot(), 1000, 620); + scene = new Scene((Parent) view.getRoot(), 1000, 650); scene.getStylesheets().setAll( "/io/bitsquare/gui/bitsquare.css", "/io/bitsquare/gui/images.css"); diff --git a/gui/src/main/java/io/bitsquare/gui/bitsquare.css b/gui/src/main/java/io/bitsquare/gui/bitsquare.css index 92bb5af08b..5129531397 100644 --- a/gui/src/main/java/io/bitsquare/gui/bitsquare.css +++ b/gui/src/main/java/io/bitsquare/gui/bitsquare.css @@ -56,6 +56,21 @@ lower gradient color on tab: dddddd -fx-background-color: #f4f4f4; } +#footer-pane { + -fx-background-color: #ddd; + -fx-font-size: 12; + -fx-text-fill: #333; +} + +#footer-pane-line { + -fx-background: #bbb; +} + +#footer-bitcoin-network-label { + -fx-text-fill: -fx-accent; + -fx-font-size: 12; +} + #headline-label { -fx-font-weight: bold; -fx-font-size: 18; 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 c36f8c0645..4b277447cd 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/MainView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/MainView.java @@ -114,7 +114,7 @@ public class MainView extends InitializableView { setLeftAnchor(this, 0d); setRightAnchor(this, 0d); setTopAnchor(this, 60d); - setBottomAnchor(this, 25d); + setBottomAnchor(this, 10d); }}; AnchorPane applicationContainer = new AnchorPane(leftNavPane, rightNavPane, contentContainer) {{ @@ -124,6 +124,7 @@ public class MainView extends InitializableView { BorderPane baseApplicationContainer = new BorderPane(applicationContainer) {{ setId("base-content-container"); }}; + baseApplicationContainer.setBottom(createFooter()); setupNotificationIcon(portfolioButtonHolder); @@ -187,15 +188,84 @@ public class MainView extends InitializableView { }); } - private VBox createSplashScreen() { - VBox vBox = new VBox(); - vBox.setAlignment(Pos.CENTER); - vBox.setSpacing(0); - vBox.setId("splash"); + private AnchorPane createFooter() { + // BTC + Label blockchainSyncLabel = new Label(); + blockchainSyncLabel.setId("footer-pane"); + blockchainSyncLabel.textProperty().bind(model.blockchainSyncInfoFooter); + model.walletServiceErrorMsg.addListener((ov, oldValue, newValue) -> { + blockchainSyncLabel.setId("splash-error-state-msg"); + Popups.openErrorPopup("Error", "Connecting to the bitcoin network failed. \n\nReason: " + + newValue); + }); - ImageView logo = new ImageView(); - logo.setId("image-splash-logo"); + ProgressBar blockchainSyncIndicator = new ProgressBar(-1); + blockchainSyncIndicator.setPrefWidth(120); + blockchainSyncIndicator.setMaxHeight(10); + blockchainSyncIndicator.progressProperty().bind(model.blockchainSyncProgress); + Label bitcoinNetworkLabel = new Label(); + bitcoinNetworkLabel.setId("footer-bitcoin-network-label"); + bitcoinNetworkLabel.setText(model.bitcoinNetworkAsString); + + model.blockchainSyncProgress.addListener((ov, oldValue, newValue) -> { + if ((double) newValue >= 1) { + blockchainSyncIndicator.setVisible(false); + blockchainSyncIndicator.setManaged(false); + blockchainSyncLabel.setVisible(false); + blockchainSyncLabel.setManaged(false); + } + }); + + HBox blockchainSyncBox = new HBox(); + blockchainSyncBox.setSpacing(10); + blockchainSyncBox.setAlignment(Pos.CENTER); + blockchainSyncBox.getChildren().addAll(blockchainSyncLabel, blockchainSyncIndicator, bitcoinNetworkLabel); + setLeftAnchor(blockchainSyncBox, 20d); + setBottomAnchor(blockchainSyncBox, 7d); + + // version + Label versionLabel = new Label(); + versionLabel.setId("footer-pane"); + versionLabel.setTextAlignment(TextAlignment.CENTER); + versionLabel.setAlignment(Pos.BASELINE_CENTER); + versionLabel.setText(model.version); + root.widthProperty().addListener((ov, oldValue, newValue) -> { + versionLabel.setLayoutX(((double) newValue - versionLabel.getWidth()) / 2); + }); + setBottomAnchor(versionLabel, 7d); + + + // P2P + Label bootstrapLabel = new Label(); + bootstrapLabel.setId("footer-pane"); + setRightAnchor(bootstrapLabel, 60d); + setBottomAnchor(bootstrapLabel, 7d); + bootstrapLabel.textProperty().bind(model.bootstrapInfoFooter); + + ImageView bootstrapIcon = new ImageView(); + setRightAnchor(bootstrapIcon, 20d); + setBottomAnchor(bootstrapIcon, 9d); + bootstrapIcon.idProperty().bind(model.bootstrapIconId); + + // line + Separator separator = new Separator(); + separator.setId("footer-pane-line"); + separator.setPrefHeight(1); + setLeftAnchor(separator, 0d); + setRightAnchor(separator, 0d); + setTopAnchor(separator, 0d); + + AnchorPane footerContainer = new AnchorPane(separator, blockchainSyncBox, versionLabel, bootstrapLabel, bootstrapIcon) {{ + setId("footer-pane"); + setMinHeight(30); + setMaxHeight(30); + }}; + + return footerContainer; + } + + private HBox createBitcoinInfoBox() { Label blockchainSyncLabel = new Label(); blockchainSyncLabel.textProperty().bind(model.blockchainSyncInfo); model.walletServiceErrorMsg.addListener((ov, oldValue, newValue) -> { @@ -232,7 +302,10 @@ public class MainView extends InitializableView { blockchainSyncBox.setPrefHeight(50); blockchainSyncBox.getChildren().addAll(blockchainSyncLabel, blockchainSyncIndicator, blockchainSyncIcon, bitcoinNetworkLabel); + return blockchainSyncBox; + } + private HBox createP2PNetworkBox() { Label bootstrapStateLabel = new Label(); bootstrapStateLabel.setWrapText(true); bootstrapStateLabel.setMaxWidth(500); @@ -272,8 +345,10 @@ public class MainView extends InitializableView { bootstrapBox.setAlignment(Pos.CENTER); bootstrapBox.setPrefHeight(50); bootstrapBox.getChildren().addAll(bootstrapStateLabel, bootstrapIndicator, bootstrapIcon); + return bootstrapBox; + } - // software update + private HBox createUpdateBox() { Label updateInfoLabel = new Label(); updateInfoLabel.setTextAlignment(TextAlignment.RIGHT); updateInfoLabel.textProperty().bind(model.updateInfo); @@ -297,8 +372,121 @@ public class MainView extends InitializableView { updateBox.setAlignment(Pos.CENTER); updateBox.setPrefHeight(20); updateBox.getChildren().addAll(updateInfoLabel, restartButton, updateIcon); + return updateBox; + } - vBox.getChildren().addAll(logo, blockchainSyncBox, bootstrapBox, updateBox); + private VBox createSplashScreen() { + VBox vBox = new VBox(); + vBox.setAlignment(Pos.CENTER); + vBox.setSpacing(0); + vBox.setId("splash"); + + ImageView logo = new ImageView(); + logo.setId("image-splash-logo"); + + /*Label blockchainSyncLabel = new Label(); + blockchainSyncLabel.textProperty().bind(model.blockchainSyncInfo); + model.walletServiceErrorMsg.addListener((ov, oldValue, newValue) -> { + blockchainSyncLabel.setId("splash-error-state-msg"); + Popups.openErrorPopup("Error", "Connecting to the bitcoin network failed. \n\nReason: " + + newValue); + }); + + ProgressBar blockchainSyncIndicator = new ProgressBar(-1); + blockchainSyncIndicator.setPrefWidth(120); + blockchainSyncIndicator.progressProperty().bind(model.blockchainSyncProgress); + + ImageView blockchainSyncIcon = new ImageView(); + blockchainSyncIcon.setVisible(false); + blockchainSyncIcon.setManaged(false); + + model.blockchainSyncIconId.addListener((ov, oldValue, newValue) -> { + blockchainSyncIcon.setId(newValue); + blockchainSyncIcon.setVisible(true); + blockchainSyncIcon.setManaged(true); + + blockchainSyncIndicator.setVisible(false); + blockchainSyncIndicator.setManaged(false); + }); + + Label bitcoinNetworkLabel = new Label(); + bitcoinNetworkLabel.setText(model.bitcoinNetworkAsString); + bitcoinNetworkLabel.setId("splash-bitcoin-network-label"); + + HBox blockchainSyncBox = new HBox(); + blockchainSyncBox.setSpacing(10); + blockchainSyncBox.setAlignment(Pos.CENTER); + blockchainSyncBox.setPadding(new Insets(40, 0, 0, 0)); + blockchainSyncBox.setPrefHeight(50); + blockchainSyncBox.getChildren().addAll(blockchainSyncLabel, blockchainSyncIndicator, + blockchainSyncIcon, bitcoinNetworkLabel);*/ + + /* Label bootstrapStateLabel = new Label(); + bootstrapStateLabel.setWrapText(true); + bootstrapStateLabel.setMaxWidth(500); + bootstrapStateLabel.setTextAlignment(TextAlignment.CENTER); + bootstrapStateLabel.textProperty().bind(model.bootstrapInfo); + + ProgressIndicator bootstrapIndicator = new ProgressIndicator(); + bootstrapIndicator.setMaxSize(24, 24); + bootstrapIndicator.progressProperty().bind(model.bootstrapProgress); + + model.bootstrapErrorMsg.addListener((ov, oldValue, newValue) -> { + bootstrapStateLabel.setId("splash-error-state-msg"); + bootstrapIndicator.setVisible(false); + + Popups.openErrorPopup("Error", "Connecting to the Bitsquare network failed. \n\nReason: " + + model.bootstrapErrorMsg.get()); + }); + + ImageView bootstrapIcon = new ImageView(); + bootstrapIcon.setVisible(false); + bootstrapIcon.setManaged(false); + + model.bootstrapIconId.addListener((ov, oldValue, newValue) -> { + bootstrapIcon.setId(newValue); + bootstrapIcon.setVisible(true); + bootstrapIcon.setManaged(true); + }); + model.bootstrapProgress.addListener((ov, oldValue, newValue) -> { + if ((double) newValue >= 1) { + bootstrapIndicator.setVisible(false); + bootstrapIndicator.setManaged(false); + } + }); + + HBox bootstrapBox = new HBox(); + bootstrapBox.setSpacing(10); + bootstrapBox.setAlignment(Pos.CENTER); + bootstrapBox.setPrefHeight(50); + bootstrapBox.getChildren().addAll(bootstrapStateLabel, bootstrapIndicator, bootstrapIcon);*/ + + // software update + /* Label updateInfoLabel = new Label(); + updateInfoLabel.setTextAlignment(TextAlignment.RIGHT); + updateInfoLabel.textProperty().bind(model.updateInfo); + + Button restartButton = new Button("Restart"); + restartButton.setDefaultButton(true); + restartButton.visibleProperty().bind(model.showRestartButton); + restartButton.managedProperty().bind(model.showRestartButton); + restartButton.setOnAction(e -> model.restart()); + + ImageView updateIcon = new ImageView(); + updateIcon.setId(model.updateIconId.get()); + model.updateIconId.addListener((ov, oldValue, newValue) -> { + updateIcon.setId(newValue); + updateIcon.setVisible(true); + updateIcon.setManaged(true); + }); + + HBox updateBox = new HBox(); + updateBox.setSpacing(10); + updateBox.setAlignment(Pos.CENTER); + updateBox.setPrefHeight(20); + updateBox.getChildren().addAll(updateInfoLabel, restartButton, updateIcon);*/ + + vBox.getChildren().addAll(logo, createBitcoinInfoBox(), createP2PNetworkBox(), createUpdateBox()); return vBox; } 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 ad09850974..aec2bd639c 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/MainViewModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/MainViewModel.java @@ -18,6 +18,7 @@ package io.bitsquare.gui.main; import io.bitsquare.app.UpdateProcess; +import io.bitsquare.app.Version; import io.bitsquare.arbitration.ArbitrationRepository; import io.bitsquare.btc.BitcoinNetwork; import io.bitsquare.btc.WalletService; @@ -27,8 +28,8 @@ import io.bitsquare.gui.common.model.ViewModel; import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.locale.CountryUtil; import io.bitsquare.p2p.BaseP2PService; -import io.bitsquare.p2p.BootstrapState; import io.bitsquare.p2p.ClientNode; +import io.bitsquare.p2p.tomp2p.BootstrappedPeerBuilder; import io.bitsquare.trade.Trade; import io.bitsquare.trade.TradeManager; import io.bitsquare.trade.offer.OpenOfferManager; @@ -61,18 +62,22 @@ class MainViewModel implements ViewModel { // BTC network final StringProperty blockchainSyncInfo = new SimpleStringProperty("Initializing"); + final StringProperty blockchainSyncInfoFooter = new SimpleStringProperty("Initializing"); final DoubleProperty blockchainSyncProgress = new SimpleDoubleProperty(-1); final StringProperty walletServiceErrorMsg = new SimpleStringProperty(); final StringProperty blockchainSyncIconId = new SimpleStringProperty(); // P2P network - final StringProperty bootstrapInfo = new SimpleStringProperty(); + final StringProperty bootstrapInfo = new SimpleStringProperty("Connecting to P2P network..."); + final StringProperty bootstrapInfoFooter = new SimpleStringProperty(); final DoubleProperty bootstrapProgress = new SimpleDoubleProperty(-1); final StringProperty bootstrapErrorMsg = new SimpleStringProperty(); final StringProperty bootstrapIconId = new SimpleStringProperty(); // software update final StringProperty updateInfo = new SimpleStringProperty(); + String version = "v." + Version.VERSION; + final BooleanProperty showRestartButton = new SimpleBooleanProperty(false); final StringProperty updateIconId = new SimpleStringProperty(); @@ -110,7 +115,7 @@ class MainViewModel implements ViewModel { this.updateProcess = updateProcess; this.formatter = formatter; - bitcoinNetworkAsString = bitcoinNetwork.toString(); + bitcoinNetworkAsString = formatter.formatBitcoinNetwork(bitcoinNetwork); updateProcess.state.addListener((observableValue, oldValue, newValue) -> applyUpdateState(newValue)); applyUpdateState(updateProcess.state.get()); @@ -131,26 +136,22 @@ class MainViewModel implements ViewModel { public void initBackend() { Platform.runLater(updateProcess::init); - setBitcoinNetworkSyncProgress(-1); - walletService.getDownloadProgress().subscribe( - percentage -> Platform.runLater(() -> { - if (percentage > 0) - setBitcoinNetworkSyncProgress(percentage / 100.0); - }), - error -> log.error(error.toString()), - () -> Platform.runLater(() -> setBitcoinNetworkSyncProgress(1.0))); + walletService.downloadPercentageProperty().addListener((ov, oldValue, newValue) -> { + setBitcoinNetworkSyncProgress((double) newValue); + }); + setBitcoinNetworkSyncProgress(walletService.downloadPercentageProperty().get()); // Set executor for all P2PServices BaseP2PService.setUserThread(Platform::runLater); - Observable bootstrapStateAsObservable = clientNode.bootstrap(keyRing.getDhtSignatureKeyPair()); + Observable bootstrapStateAsObservable = clientNode.bootstrap(keyRing.getDhtSignatureKeyPair()); bootstrapStateAsObservable.publish(); bootstrapStateAsObservable.subscribe( state -> Platform.runLater(() -> setBootstrapState(state)), error -> Platform.runLater(() -> { log.error(error.toString()); bootstrapErrorMsg.set(error.getMessage()); - bootstrapInfo.set("Connecting to the Bitsquare network failed."); + bootstrapInfo.set("Connecting to the P2P network failed."); bootstrapProgress.set(0); }), @@ -220,7 +221,7 @@ class MainViewModel implements ViewModel { private void applyUpdateState(UpdateProcess.State state) { switch (state) { case CHECK_FOR_UPDATES: - updateInfo.set("Checking for updates..."); + updateInfo.set("Check for updates..."); updateIconId.set("image-update-in-progress"); break; case UPDATE_AVAILABLE: @@ -229,30 +230,33 @@ class MainViewModel implements ViewModel { showRestartButton.set(true); break; case UP_TO_DATE: - updateInfo.set("Software is up to date."); + updateInfo.set("Software is up to date. Version: " + Version.VERSION); updateIconId.set("image-update-up-to-date"); break; case FAILURE: - updateInfo.set(updateProcess.getErrorMessage()); + log.error(updateProcess.getErrorMessage()); + updateInfo.set("Check for updates failed. "); updateIconId.set("image-update-failed"); break; } } - private void setBootstrapState(BootstrapState state) { + private void setBootstrapState(BootstrappedPeerBuilder.State state) { switch (state) { case DISCOVERY_DIRECT_SUCCEEDED: bootstrapIconId.set("image-connection-direct"); + bootstrapInfoFooter.set("Direct connection"); break; case DISCOVERY_MANUAL_PORT_FORWARDING_SUCCEEDED: case DISCOVERY_AUTO_PORT_FORWARDING_SUCCEEDED: bootstrapIconId.set("image-connection-nat"); + bootstrapInfoFooter.set("Connected with port forwarding"); break; case RELAY_SUCCEEDED: bootstrapIconId.set("image-connection-relay"); + bootstrapInfoFooter.set("Connected with relay node"); break; default: - bootstrapIconId.set(null); break; } @@ -261,15 +265,13 @@ class MainViewModel implements ViewModel { case DISCOVERY_MANUAL_PORT_FORWARDING_SUCCEEDED: case DISCOVERY_AUTO_PORT_FORWARDING_SUCCEEDED: case RELAY_SUCCEEDED: - bootstrapInfo.set("Bootstrapping to P2P network: " + state.getMessage()); + bootstrapInfo.set(state.getMessage()); bootstrapProgress.set(-1); break; case BOOT_STRAP_SUCCEEDED: - bootstrapInfo.set("Successfully connected to P2P network: " + state.getMessage()); bootstrapProgress.set(1); break; default: - bootstrapInfo.set("Connecting to P2P network: " + state.getMessage()); bootstrapProgress.set(-1); break; } @@ -278,6 +280,7 @@ class MainViewModel implements ViewModel { private void setWalletServiceException(Throwable error) { setBitcoinNetworkSyncProgress(0); blockchainSyncInfo.set("Connecting to the bitcoin network failed."); + blockchainSyncInfoFooter.set("Connection failed."); if (error instanceof TimeoutException) { walletServiceErrorMsg.set("Please check your network connection.\n\n" + "You must allow outgoing TCP connections to port 18333 for the bitcoin testnet.\n\n" + @@ -332,9 +335,11 @@ class MainViewModel implements ViewModel { } else if (value > 0.0) { blockchainSyncInfo.set("Synchronizing blockchain: " + formatter.formatToPercent(value)); + blockchainSyncInfoFooter.set("Synchronizing: " + formatter.formatToPercent(value)); } else { blockchainSyncInfo.set("Connecting to the bitcoin network..."); + blockchainSyncInfoFooter.set("Connecting..."); } } diff --git a/gui/src/main/java/io/bitsquare/gui/main/settings/network/NetworkSettingsView.java b/gui/src/main/java/io/bitsquare/gui/main/settings/network/NetworkSettingsView.java index 962b6f2c32..c579ac1c3c 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/settings/network/NetworkSettingsView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/settings/network/NetworkSettingsView.java @@ -20,6 +20,7 @@ package io.bitsquare.gui.main.settings.network; import io.bitsquare.btc.BitcoinNetwork; import io.bitsquare.gui.common.view.FxmlView; import io.bitsquare.gui.common.view.InitializableView; +import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.p2p.ClientNode; import javax.inject.Inject; @@ -30,19 +31,19 @@ import javafx.scene.control.*; @FxmlView public class NetworkSettingsView extends InitializableView { - private final String bitcoinNetworkValue; + private final String bitcoinNetworkString; private final ClientNode clientNode; @FXML TextField bitcoinNetwork, connectionType, nodeAddress, bootstrapNodeAddress; @Inject - public NetworkSettingsView(BitcoinNetwork bitcoinNetwork, ClientNode clientNode) { - this.bitcoinNetworkValue = bitcoinNetwork.toString(); + public NetworkSettingsView(BitcoinNetwork bitcoinNetwork, ClientNode clientNode, BSFormatter formatter) { + this.bitcoinNetworkString = formatter.formatBitcoinNetwork(bitcoinNetwork); this.clientNode = clientNode; } public void initialize() { - bitcoinNetwork.setText(bitcoinNetworkValue); + bitcoinNetwork.setText(bitcoinNetworkString); connectionType.setText(clientNode.getConnectionType().toString()); nodeAddress.setText(clientNode.getAddress().toString()); bootstrapNodeAddress.setText(clientNode.getBootstrapNodeAddress().toString()); diff --git a/gui/src/main/java/io/bitsquare/gui/util/BSFormatter.java b/gui/src/main/java/io/bitsquare/gui/util/BSFormatter.java index 7bad50c980..94ae3d533d 100644 --- a/gui/src/main/java/io/bitsquare/gui/util/BSFormatter.java +++ b/gui/src/main/java/io/bitsquare/gui/util/BSFormatter.java @@ -19,6 +19,7 @@ package io.bitsquare.gui.util; import io.bitsquare.arbitration.ArbitrationRepository; import io.bitsquare.arbitration.Arbitrator; +import io.bitsquare.btc.BitcoinNetwork; import io.bitsquare.locale.BSResources; import io.bitsquare.locale.Country; import io.bitsquare.locale.CurrencyUtil; @@ -363,4 +364,17 @@ public class BSFormatter { Date unlockDate = new Date(new Date().getTime() + missingBlocks * 10 * 60 * 1000); return dateFormatter.format(unlockDate) + " " + timeFormatter.format(unlockDate); } + + public String formatBitcoinNetwork(BitcoinNetwork bitcoinNetwork) { + switch (bitcoinNetwork) { + case MAINNET: + return "Mainnet"; + case TESTNET: + return "Testnet"; + case REGTEST: + return "Regtest"; + default: + return ""; + } + } }