Add connection icons, handleError cases in one method

This commit is contained in:
Manfred Karrer 2014-11-10 15:15:49 +01:00
parent 7ccfd98fb9
commit bdcd60d1fe
14 changed files with 112 additions and 74 deletions

View file

@ -139,10 +139,9 @@ public class Main extends Application {
// For now we exit when closing/quit the app. // For now we exit when closing/quit the app.
// Later we will only hide the window (systemTray.hideStage()) and use the exit item in the system tray for // Later we will only hide the window (systemTray.hideStage()) and use the exit item in the system tray for
// shut down. // shut down.
if (new KeyCodeCombination(KeyCode.W, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) if (new KeyCodeCombination(KeyCode.W, KeyCombination.SHORTCUT_DOWN).match(keyEvent) ||
systemTray.exit(); new KeyCodeCombination(KeyCode.Q, KeyCombination.SHORTCUT_DOWN).match(keyEvent))
if (new KeyCodeCombination(KeyCode.Q, KeyCombination.SHORTCUT_DOWN).match(keyEvent)) stop();
systemTray.exit();
}); });

View file

@ -94,12 +94,7 @@ public class SystemTray {
} }
}); });
exitItem.addActionListener(e -> exit()); exitItem.addActionListener(e -> onExit.run());
}
public void exit() {
java.awt.SystemTray.getSystemTray().remove(trayIcon);
onExit.run();
} }
public void hideStage() { public void hideStage() {

View file

@ -122,3 +122,20 @@
#image-arrow-grey { #image-arrow-grey {
-fx-image: url("../../../images/arrow_grey.png"); -fx-image: url("../../../images/arrow_grey.png");
} }
/* connection state*/
#image-connection-direct {
-fx-image: url("../../../images/connection/direct.png");
}
#image-connection-nat {
-fx-image: url("../../../images/connection/nat.png");
}
#image-connection-relay {
-fx-image: url("../../../images/connection/relay.png");
}
#image-connection-synced {
-fx-image: url("../../../images/connection/synced.png");
}

View file

@ -48,16 +48,19 @@ class MainPM extends PresentationModel<MainModel> {
final BooleanProperty backendReady = new SimpleBooleanProperty(); final BooleanProperty backendReady = new SimpleBooleanProperty();
final StringProperty bankAccountsComboBoxPrompt = new SimpleStringProperty(); final StringProperty bankAccountsComboBoxPrompt = new SimpleStringProperty();
final BooleanProperty bankAccountsComboBoxDisable = new SimpleBooleanProperty(); final BooleanProperty bankAccountsComboBoxDisable = new SimpleBooleanProperty();
final StringProperty blockchainSyncState = new SimpleStringProperty("Initializing");
final IntegerProperty numPendingTrades = new SimpleIntegerProperty(); final IntegerProperty numPendingTrades = new SimpleIntegerProperty();
final StringProperty blockchainSyncState = new SimpleStringProperty("Initializing");
final DoubleProperty blockchainSyncProgress = new SimpleDoubleProperty(); final DoubleProperty blockchainSyncProgress = new SimpleDoubleProperty();
final BooleanProperty blockchainSyncIndicatorVisible = new SimpleBooleanProperty(true); final BooleanProperty blockchainSyncIndicatorVisible = new SimpleBooleanProperty(true);
final StringProperty blockchainSyncIconId = new SimpleStringProperty();
final StringProperty walletFacadeErrorMsg = new SimpleStringProperty();
final DoubleProperty bootstrapProgress = new SimpleDoubleProperty(-1); final DoubleProperty bootstrapProgress = new SimpleDoubleProperty(-1);
final BooleanProperty bootstrapFailed = new SimpleBooleanProperty(); final BooleanProperty bootstrapFailed = new SimpleBooleanProperty();
final BooleanProperty bootstrapIndicatorVisible = new SimpleBooleanProperty(true);
final StringProperty bootstrapState = new SimpleStringProperty(); final StringProperty bootstrapState = new SimpleStringProperty();
final StringProperty bootstrapErrorMsg = new SimpleStringProperty(); final StringProperty bootstrapErrorMsg = new SimpleStringProperty();
final StringProperty walletFacadeErrorMsg = new SimpleStringProperty(); final StringProperty bootstrapIconId = new SimpleStringProperty();
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -88,8 +91,14 @@ class MainPM extends PresentationModel<MainModel> {
newValue == BootstrapState.NAT_SUCCESS || newValue == BootstrapState.NAT_SUCCESS ||
newValue == BootstrapState.RELAY_SUCCESS) { newValue == BootstrapState.RELAY_SUCCESS) {
bootstrapState.set("Successfully connected to P2P network: " + newValue.getMessage()); bootstrapState.set("Successfully connected to P2P network: " + newValue.getMessage());
bootstrapIndicatorVisible.set(false);
bootstrapProgress.set(1); bootstrapProgress.set(1);
if (newValue == BootstrapState.DIRECT_SUCCESS)
bootstrapIconId.set("image-connection-direct");
else if (newValue == BootstrapState.NAT_SUCCESS)
bootstrapIconId.set("image-connection-nat");
else if (newValue == BootstrapState.RELAY_SUCCESS)
bootstrapIconId.set("image-connection-relay");
} }
else if (newValue == BootstrapState.PEER_CREATION_FAILED || else if (newValue == BootstrapState.PEER_CREATION_FAILED ||
newValue == BootstrapState.DIRECT_FAILED || newValue == BootstrapState.DIRECT_FAILED ||
@ -98,7 +107,6 @@ class MainPM extends PresentationModel<MainModel> {
bootstrapErrorMsg.set(newValue.getMessage()); bootstrapErrorMsg.set(newValue.getMessage());
bootstrapState.set("Connection to P2P network failed."); bootstrapState.set("Connection to P2P network failed.");
bootstrapIndicatorVisible.set(false);
bootstrapProgress.set(0); bootstrapProgress.set(0);
bootstrapFailed.set(true); bootstrapFailed.set(true);
} }
@ -115,9 +123,15 @@ class MainPM extends PresentationModel<MainModel> {
walletFacadeErrorMsg.set(((Throwable) newValue).getMessage()); walletFacadeErrorMsg.set(((Throwable) newValue).getMessage());
}); });
model.networkSyncProgress.addListener((ov, oldValue, newValue) -> setNetworkSyncProgress((double) newValue)); model.networkSyncProgress.addListener((ov, oldValue, newValue) -> {
setNetworkSyncProgress((double) newValue);
if ((double) newValue >= 1)
blockchainSyncIconId.set("image-connection-synced");
});
setNetworkSyncProgress(model.networkSyncProgress.get()); setNetworkSyncProgress(model.networkSyncProgress.get());
model.getBankAccounts().addListener((ListChangeListener<BankAccount>) change -> { model.getBankAccounts().addListener((ListChangeListener<BankAccount>) change -> {
bankAccountsComboBoxDisable.set(change.getList().isEmpty()); bankAccountsComboBoxDisable.set(change.getList().isEmpty());
bankAccountsComboBoxPrompt.set(change.getList().isEmpty() ? "No accounts" : ""); bankAccountsComboBoxPrompt.set(change.getList().isEmpty() ? "No accounts" : "");

View file

@ -297,39 +297,64 @@ public class MainViewCB extends ViewCB<MainPM> {
ProgressBar blockchainSyncIndicator = new ProgressBar(-1); ProgressBar blockchainSyncIndicator = new ProgressBar(-1);
blockchainSyncIndicator.setPrefWidth(120); blockchainSyncIndicator.setPrefWidth(120);
blockchainSyncIndicator.progressProperty().bind(presentationModel.blockchainSyncProgress); blockchainSyncIndicator.progressProperty().bind(presentationModel.blockchainSyncProgress);
blockchainSyncIndicator.visibleProperty().bind(presentationModel.blockchainSyncIndicatorVisible);
blockchainSyncIndicator.managedProperty().bind(presentationModel.blockchainSyncIndicatorVisible); ImageView blockchainSyncIcon = new ImageView();
blockchainSyncIcon.setVisible(false);
blockchainSyncIcon.setManaged(false);
presentationModel.blockchainSyncIconId.addListener((ov, oldValue, newValue) -> {
blockchainSyncIcon.setId(newValue);
blockchainSyncIcon.setVisible(true);
blockchainSyncIcon.setManaged(true);
blockchainSyncIndicator.setVisible(false);
blockchainSyncIndicator.setManaged(false);
});
HBox blockchainSyncBox = new HBox(); HBox blockchainSyncBox = new HBox();
blockchainSyncBox.setSpacing(10); blockchainSyncBox.setSpacing(10);
blockchainSyncBox.setAlignment(Pos.CENTER); blockchainSyncBox.setAlignment(Pos.CENTER);
blockchainSyncBox.setPadding(new Insets(60, 0, 0, 0)); blockchainSyncBox.setPadding(new Insets(60, 0, 0, 0));
blockchainSyncBox.getChildren().addAll(blockchainSyncLabel, blockchainSyncIndicator); blockchainSyncBox.getChildren().addAll(blockchainSyncLabel, blockchainSyncIndicator, blockchainSyncIcon);
Label bootstrapStateLabel = new Label(); Label bootstrapStateLabel = new Label();
bootstrapStateLabel.setWrapText(true); bootstrapStateLabel.setWrapText(true);
bootstrapStateLabel.setMaxWidth(500); bootstrapStateLabel.setMaxWidth(500);
bootstrapStateLabel.setTextAlignment(TextAlignment.CENTER); bootstrapStateLabel.setTextAlignment(TextAlignment.CENTER);
bootstrapStateLabel.textProperty().bind(presentationModel.bootstrapState); bootstrapStateLabel.textProperty().bind(presentationModel.bootstrapState);
ProgressIndicator bootstrapIndicator = new ProgressIndicator();
bootstrapIndicator.setMaxSize(24, 24);
bootstrapIndicator.progressProperty().bind(presentationModel.bootstrapProgress);
presentationModel.bootstrapFailed.addListener((ov, oldValue, newValue) -> { presentationModel.bootstrapFailed.addListener((ov, oldValue, newValue) -> {
if (newValue) { if (newValue) {
bootstrapStateLabel.setId("splash-error-state-msg"); bootstrapStateLabel.setId("splash-error-state-msg");
bootstrapIndicator.setVisible(false);
Popups.openErrorPopup("Error", "Cannot connect to P2P network. \n\nError message:\n" + Popups.openErrorPopup("Error", "Cannot connect to P2P network. \n\nError message:\n" +
presentationModel.bootstrapErrorMsg.get()); presentationModel.bootstrapErrorMsg.get());
} }
}); });
ProgressIndicator bootstrapIndicator = new ProgressIndicator(); ImageView bootstrapIcon = new ImageView();
bootstrapIndicator.setMaxSize(24, 24); bootstrapIcon.setVisible(false);
bootstrapIndicator.progressProperty().bind(presentationModel.bootstrapProgress); bootstrapIcon.setManaged(false);
bootstrapIndicator.visibleProperty().bind(presentationModel.bootstrapIndicatorVisible);
bootstrapIndicator.managedProperty().bind(presentationModel.bootstrapIndicatorVisible); presentationModel.bootstrapIconId.addListener((ov, oldValue, newValue) -> {
bootstrapIcon.setId(newValue);
bootstrapIcon.setVisible(true);
bootstrapIcon.setManaged(true);
bootstrapIndicator.setVisible(false);
bootstrapIndicator.setManaged(false);
});
HBox bootstrapBox = new HBox(); HBox bootstrapBox = new HBox();
bootstrapBox.setSpacing(10); bootstrapBox.setSpacing(10);
bootstrapBox.setAlignment(Pos.CENTER); bootstrapBox.setAlignment(Pos.CENTER);
bootstrapBox.setPadding(new Insets(10, 0, 0, 0)); bootstrapBox.setPadding(new Insets(10, 0, 0, 0));
bootstrapBox.getChildren().addAll(bootstrapStateLabel, bootstrapIndicator); bootstrapBox.getChildren().addAll(bootstrapStateLabel, bootstrapIndicator, bootstrapIcon);
vBox.getChildren().addAll(logo, blockchainSyncBox, bootstrapBox); vBox.getChildren().addAll(logo, blockchainSyncBox, bootstrapBox);
return vBox; return vBox;

View file

@ -152,42 +152,44 @@ class BootstrappedPeerFactory {
}); });
// We save last successful bootstrap method. // We save last successful bootstrap method.
// Reset it to "default" after 5 start ups. // Reset it to BootstrapState.DIRECT_SUCCESS after 5 start ups.
Object bootstrapCounterObject = persistence.read(this, "bootstrapCounter"); Object bootstrapCounterObject = persistence.read(this, "bootstrapCounter");
int bootstrapCounter = 0; int bootstrapCounter = 0;
if (bootstrapCounterObject instanceof Integer) if (bootstrapCounterObject instanceof Integer)
bootstrapCounter = (int) bootstrapCounterObject + 1; bootstrapCounter = (int) bootstrapCounterObject + 1;
if (bootstrapCounter > 5) { if (bootstrapCounter > 5) {
persistence.write(this, "lastSuccessfulBootstrap", "default"); persistence.write(this, "lastSuccessfulBootstrap", BootstrapState.DIRECT_SUCCESS);
bootstrapCounter = 0; bootstrapCounter = 0;
} }
persistence.write(this, "bootstrapCounter", bootstrapCounter); persistence.write(this, "bootstrapCounter", bootstrapCounter);
String lastSuccessfulBootstrap = (String) persistence.read(this, "lastSuccessfulBootstrap"); BootstrapState lastSuccessfulBootstrap = BootstrapState.DIRECT_SUCCESS;
if (lastSuccessfulBootstrap == null) Object lastSuccessfulBootstrapObject = persistence.read(this, "lastSuccessfulBootstrap");
lastSuccessfulBootstrap = "default"; if (lastSuccessfulBootstrapObject instanceof BootstrapState)
lastSuccessfulBootstrap = (BootstrapState) lastSuccessfulBootstrapObject;
else
persistence.write(this, "lastSuccessfulBootstrap", lastSuccessfulBootstrap);
log.debug("lastSuccessfulBootstrap = " + lastSuccessfulBootstrap); log.debug("lastSuccessfulBootstrap = " + lastSuccessfulBootstrap);
// just temporary while port forwarding is not working // just temporary always start with trying direct connection
lastSuccessfulBootstrap = "default"; lastSuccessfulBootstrap = BootstrapState.DIRECT_SUCCESS;
switch (lastSuccessfulBootstrap) { switch (lastSuccessfulBootstrap) {
case "relay": case RELAY_SUCCESS:
bootstrapWithRelay(); bootstrapWithRelay();
break; break;
case "portForwarding": case NAT_SUCCESS:
tryPortForwarding(); tryPortForwarding();
break; break;
case "default": case DIRECT_SUCCESS:
default: default:
discover(); discover();
break; break;
} }
} catch (IOException e) { } catch (IOException e) {
setState(BootstrapState.PEER_CREATION, "Cannot create peer with port: " + port + ". Exeption: " + e, false); handleError(BootstrapState.PEER_CREATION, "Cannot create peer with port: " + port + ". Exeption: " + e);
settableFuture.setException(e);
} }
return settableFuture; return settableFuture;
@ -202,7 +204,7 @@ class BootstrappedPeerFactory {
public void operationComplete(BaseFuture future) throws Exception { public void operationComplete(BaseFuture future) throws Exception {
if (future.isSuccess()) { if (future.isSuccess()) {
setState(BootstrapState.DIRECT_SUCCESS, "We are directly connected and visible to other peers."); setState(BootstrapState.DIRECT_SUCCESS, "We are directly connected and visible to other peers.");
bootstrap("default"); bootstrap(BootstrapState.DIRECT_SUCCESS);
} }
else { else {
setState(BootstrapState.DIRECT_NOT_SUCCEEDED, "We are probably behind a NAT and not reachable to " + setState(BootstrapState.DIRECT_NOT_SUCCEEDED, "We are probably behind a NAT and not reachable to " +
@ -213,9 +215,7 @@ class BootstrappedPeerFactory {
@Override @Override
public void exceptionCaught(Throwable t) throws Exception { public void exceptionCaught(Throwable t) throws Exception {
setState(BootstrapState.DIRECT_FAILED, "Exception at discover: " + t.getMessage(), false); handleError(BootstrapState.DIRECT_FAILED, "Exception at discover: " + t.getMessage());
peerDHT.shutdown();
settableFuture.setException(t);
} }
}); });
} }
@ -244,9 +244,7 @@ class BootstrappedPeerFactory {
@Override @Override
public void exceptionCaught(Throwable t) throws Exception { public void exceptionCaught(Throwable t) throws Exception {
setState(BootstrapState.NAT_FAILED, "Exception at port forwarding: " + t.getMessage(), false); handleError(BootstrapState.NAT_FAILED, "Exception at port forwarding: " + t.getMessage());
peerDHT.shutdown();
settableFuture.setException(t);
} }
}); });
} }
@ -259,24 +257,17 @@ class BootstrappedPeerFactory {
public void operationComplete(BaseFuture future) throws Exception { public void operationComplete(BaseFuture future) throws Exception {
if (future.isSuccess()) { if (future.isSuccess()) {
setState(BootstrapState.NAT_SUCCESS, "Discover with automatic port forwarding was successful."); setState(BootstrapState.NAT_SUCCESS, "Discover with automatic port forwarding was successful.");
bootstrap("portForwarding"); bootstrap(BootstrapState.NAT_SUCCESS);
} }
else { else {
setState(BootstrapState.NAT_FAILED, "Discover with automatic port forwarding has failed " + handleError(BootstrapState.NAT_FAILED, "Discover with automatic port forwarding has failed " +
futureDiscover.failedReason(), false); futureDiscover.failedReason());
persistence.write(BootstrappedPeerFactory.this, "lastSuccessfulBootstrap", "default");
peerDHT.shutdown();
settableFuture.setException(new Exception("Discover with automatic port forwarding failed " +
futureDiscover.failedReason()));
} }
} }
@Override @Override
public void exceptionCaught(Throwable t) throws Exception { public void exceptionCaught(Throwable t) throws Exception {
setState(BootstrapState.NAT_FAILED, "Exception at discover: " + t, false); handleError(BootstrapState.NAT_FAILED, "Exception at discover: " + t.getMessage());
persistence.write(BootstrappedPeerFactory.this, "lastSuccessfulBootstrap", "default");
peerDHT.shutdown();
settableFuture.setException(t);
} }
}); });
} }
@ -293,50 +284,40 @@ class BootstrappedPeerFactory {
public void operationComplete(BaseFuture future) throws Exception { public void operationComplete(BaseFuture future) throws Exception {
if (future.isSuccess()) { if (future.isSuccess()) {
setState(BootstrapState.RELAY_SUCCESS, "Bootstrap using relay was successful."); setState(BootstrapState.RELAY_SUCCESS, "Bootstrap using relay was successful.");
bootstrap("relay"); bootstrap(BootstrapState.RELAY_SUCCESS);
} }
else { else {
setState(BootstrapState.RELAY_FAILED, "Bootstrap using relay has failed " + futureRelayNAT handleError(BootstrapState.RELAY_FAILED, "Bootstrap using relay has failed " +
.failedReason(), false); futureRelayNAT.failedReason());
persistence.write(BootstrappedPeerFactory.this, "lastSuccessfulBootstrap", "default");
futureRelayNAT.shutdown();
peerDHT.shutdown();
settableFuture.setException(new Exception("Bootstrap using relay failed " +
futureRelayNAT.failedReason()));
} }
} }
@Override @Override
public void exceptionCaught(Throwable t) throws Exception { public void exceptionCaught(Throwable t) throws Exception {
setState(BootstrapState.RELAY_FAILED, "Exception at bootstrapWithRelay: " + t, false); handleError(BootstrapState.RELAY_FAILED, "Exception at bootstrapWithRelay: " + t.getMessage());
persistence.write(BootstrappedPeerFactory.this, "lastSuccessfulBootstrap", "default");
futureRelayNAT.shutdown();
peerDHT.shutdown();
settableFuture.setException(t);
} }
}); });
} }
private void bootstrap(String state) { private void bootstrap(BootstrapState state) {
FutureBootstrap futureBootstrap = peer.bootstrap().peerAddress(getBootstrapAddress()).start(); FutureBootstrap futureBootstrap = peer.bootstrap().peerAddress(getBootstrapAddress()).start();
futureBootstrap.addListener(new BaseFutureListener<BaseFuture>() { futureBootstrap.addListener(new BaseFutureListener<BaseFuture>() {
@Override @Override
public void operationComplete(BaseFuture future) throws Exception { public void operationComplete(BaseFuture future) throws Exception {
if (futureBootstrap.isSuccess()) { if (futureBootstrap.isSuccess()) {
setState(BootstrapState.DIRECT_SUCCESS, "Bootstrap successful."); setState(state, "Bootstrap successful.");
persistence.write(BootstrappedPeerFactory.this, "lastSuccessfulBootstrap", state); persistence.write(BootstrappedPeerFactory.this, "lastSuccessfulBootstrap", state);
settableFuture.set(peerDHT); settableFuture.set(peerDHT);
} }
else { else {
setState(BootstrapState.DIRECT_NOT_SUCCEEDED, "Bootstrapping failed."); handleError(BootstrapState.DIRECT_NOT_SUCCEEDED, "Bootstrapping failed. " +
futureBootstrap.failedReason());
} }
} }
@Override @Override
public void exceptionCaught(Throwable t) throws Exception { public void exceptionCaught(Throwable t) throws Exception {
setState(BootstrapState.DIRECT_FAILED, "Exception at bootstrap: " + t.getMessage(), false); handleError(BootstrapState.DIRECT_FAILED, "Exception at bootstrap: " + t.getMessage());
peerDHT.shutdown();
settableFuture.setException(t);
} }
}); });
} }
@ -366,4 +347,11 @@ class BootstrappedPeerFactory {
bootstrapState.setMessage(message); bootstrapState.setMessage(message);
Platform.runLater(() -> this.bootstrapState.set(bootstrapState)); Platform.runLater(() -> this.bootstrapState.set(bootstrapState));
} }
private void handleError(BootstrapState state, String errorMessage) {
setState(state, errorMessage, false);
persistence.write(this, "lastSuccessfulBootstrap", BootstrapState.DIRECT_SUCCESS);
peerDHT.shutdown();
settableFuture.setException(new Exception(errorMessage));
}
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB