improved startup, add splash screen, make it smoother

This commit is contained in:
Manfred Karrer 2014-08-11 13:40:16 +02:00
parent 89d5c9ee86
commit 17697afa24
17 changed files with 387 additions and 247 deletions

View file

@ -21,13 +21,9 @@ import java.util.Arrays;
import javafx.application.Application; import javafx.application.Application;
import javafx.scene.Parent; import javafx.scene.Parent;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination; import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination; import javafx.scene.input.KeyCombination;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage; import javafx.stage.Stage;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -47,8 +43,7 @@ public class BitSquare extends Application
public static void main(String[] args) public static void main(String[] args)
{ {
Profiler.init(); Profiler.init();
Profiler.printMsgWithTime("main called"); Profiler.printMsgWithTime("BitSquare.main called with args " + Arrays.asList(args).toString());
log.debug("Startup: main " + Arrays.asList(args).toString());
if (args != null && args.length > 0) APP_NAME = args[0]; if (args != null && args.length > 0) APP_NAME = args[0];
launch(args); launch(args);
@ -67,7 +62,7 @@ public class BitSquare extends Application
@Override @Override
public void start(Stage primaryStage) throws IOException public void start(Stage primaryStage) throws IOException
{ {
Profiler.printMsgWithTime("start called"); Profiler.printMsgWithTime("BitSquare.start called");
BitSquare.primaryStage = primaryStage; BitSquare.primaryStage = primaryStage;
Thread.currentThread().setUncaughtExceptionHandler((thread, throwable) -> Popups.handleUncaughtExceptions(Throwables.getRootCause(throwable))); Thread.currentThread().setUncaughtExceptionHandler((thread, throwable) -> Popups.handleUncaughtExceptions(Throwables.getRootCause(throwable)));
@ -81,7 +76,7 @@ public class BitSquare extends Application
walletFacade = injector.getInstance(WalletFacade.class); walletFacade = injector.getInstance(WalletFacade.class);
messageFacade = injector.getInstance(MessageFacade.class); messageFacade = injector.getInstance(MessageFacade.class);
Profiler.printMsgWithTime("Startup: messageFacade, walletFacade inited"); Profiler.printMsgWithTime("BitSquare: messageFacade, walletFacade created");
// apply stored data // apply stored data
final User user = injector.getInstance(User.class); final User user = injector.getInstance(User.class);
@ -100,14 +95,9 @@ public class BitSquare extends Application
GuiceFXMLLoader.setInjector(injector); GuiceFXMLLoader.setInjector(injector);
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(NavigationItem.MAIN.getFxmlUrl())); final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(NavigationItem.MAIN.getFxmlUrl()));
final Parent mainView = loader.load(); final Parent view = loader.load();
BorderPane rootPane = new BorderPane(); final Scene scene = new Scene(view, 1000, 750);
rootPane.setTop(getMenuBar()); scene.getStylesheets().setAll(getClass().getResource("/io/bitsquare/gui/bitsquare.css").toExternalForm());
rootPane.setCenter(mainView);
final Scene scene = new Scene(rootPane, 1000, 750);
scene.getStylesheets().setAll(getClass().getResource("/io/bitsquare/gui/bitsquare.css").toExternalForm(),
getClass().getResource("/io/bitsquare/gui/validation.css").toExternalForm());
setupCloseHandlers(primaryStage, scene); setupCloseHandlers(primaryStage, scene);
@ -117,7 +107,7 @@ public class BitSquare extends Application
primaryStage.show(); primaryStage.show();
Profiler.printMsgWithTime("Startup: primaryStage.show"); Profiler.printMsgWithTime("BitSquare: start finished");
} }
private void setupCloseHandlers(Stage primaryStage, Scene scene) private void setupCloseHandlers(Stage primaryStage, Scene scene)
@ -130,34 +120,6 @@ public class BitSquare extends Application
}); });
} }
private MenuBar getMenuBar()
{
MenuBar menuBar = new MenuBar();
// on mac we could placemenu bar in the systems menu
// menuBar.setUseSystemMenuBar(true);
menuBar.setUseSystemMenuBar(false);
Menu fileMenu = new Menu("_File");
fileMenu.setMnemonicParsing(true);
MenuItem backupMenuItem = new MenuItem("Backup wallet");
fileMenu.getItems().addAll(backupMenuItem);
Menu settingsMenu = new Menu("_Settings");
settingsMenu.setMnemonicParsing(true);
MenuItem changePwMenuItem = new MenuItem("Change password");
settingsMenu.getItems().addAll(changePwMenuItem);
Menu helpMenu = new Menu("_Help");
helpMenu.setMnemonicParsing(true);
MenuItem faqMenuItem = new MenuItem("FAQ");
MenuItem forumMenuItem = new MenuItem("Forum");
helpMenu.getItems().addAll(faqMenuItem, forumMenuItem);
menuBar.getMenus().setAll(fileMenu, settingsMenu, helpMenu);
return menuBar;
}
@Override @Override
public void stop() throws Exception public void stop() throws Exception
{ {

View file

@ -8,7 +8,8 @@ import io.bitsquare.di.GuiceFXMLLoader;
import io.bitsquare.gui.components.NetworkSyncPane; import io.bitsquare.gui.components.NetworkSyncPane;
import io.bitsquare.gui.market.MarketController; import io.bitsquare.gui.market.MarketController;
import io.bitsquare.gui.orders.OrdersController; import io.bitsquare.gui.orders.OrdersController;
import io.bitsquare.gui.util.Icons; import io.bitsquare.gui.util.ImageUtil;
import io.bitsquare.gui.util.Profiler;
import io.bitsquare.gui.util.Transitions; import io.bitsquare.gui.util.Transitions;
import io.bitsquare.msg.BootstrapListener; import io.bitsquare.msg.BootstrapListener;
import io.bitsquare.msg.MessageFacade; import io.bitsquare.msg.MessageFacade;
@ -20,24 +21,29 @@ import io.bitsquare.util.AWTSystemTray;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import javafx.application.Platform;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.control.*; import javafx.scene.control.*;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.*;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.util.StringConverter; import javafx.util.StringConverter;
import javax.inject.Inject; import javax.inject.Inject;
import net.tomp2p.peers.PeerAddress; import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/**
* Holds the splash screen and the application views.
* It builds up all the views and initializes the facades.
* We use a sequence of Platform.runLater cascaded calls to make the startup more smooth, otherwise the rendering is frozen for too long.
* Pre-loading of views is not implemented yet, and after a quick test it seemed that it does not give much improvements.
*/
public class MainController implements Initializable, NavigationController public class MainController implements Initializable, NavigationController
{ {
private static final Logger log = LoggerFactory.getLogger(MainController.class); private static final Logger log = LoggerFactory.getLogger(MainController.class);
@ -49,7 +55,7 @@ public class MainController implements Initializable, NavigationController
private final TradeManager tradeManager; private final TradeManager tradeManager;
private final Persistence persistence; private final Persistence persistence;
private final ToggleGroup toggleGroup = new ToggleGroup(); private final ToggleGroup toggleGroup = new ToggleGroup();
private final ViewBuilder viewBuilder;
private ChildController controller; private ChildController controller;
private ToggleButton prevToggleButton; private ToggleButton prevToggleButton;
@ -59,18 +65,7 @@ public class MainController implements Initializable, NavigationController
private boolean messageFacadeInited; private boolean messageFacadeInited;
private boolean walletFacadeInited; private boolean walletFacadeInited;
@FXML @FXML private BorderPane root;
private Pane contentPane;
@FXML
private HBox leftNavPane, rightNavPane;
@FXML
private ProgressBar loadingBar;
@FXML
private AnchorPane rootPane;
@FXML
private Label loadingLabel;
@FXML
private NetworkSyncPane networkSyncPane;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -86,6 +81,8 @@ public class MainController implements Initializable, NavigationController
this.tradeManager = tradeManager; this.tradeManager = tradeManager;
this.persistence = persistence; this.persistence = persistence;
viewBuilder = new ViewBuilder();
MainController.INSTANCE = this; MainController.INSTANCE = this;
} }
@ -107,49 +104,14 @@ public class MainController implements Initializable, NavigationController
@Override @Override
public void initialize(URL url, ResourceBundle rb) public void initialize(URL url, ResourceBundle rb)
{ {
messageFacade.init(new BootstrapListener() Profiler.printMsgWithTime("MainController.initialize");
{ Platform.runLater(() -> viewBuilder.buildSplashScreen(root, this));
@Override
public void onCompleted()
{
messageFacadeInited = true;
if (walletFacadeInited) initialisationDone();
}
@Override
public void onFailed(Throwable throwable)
{
}
});
walletFacade.addDownloadListener(new WalletFacade.DownloadListener()
{
@Override
public void progress(double percent)
{
networkSyncPane.setProgress(percent);
}
@Override
public void doneDownload()
{
networkSyncPane.doneDownload();
}
});
walletFacade.initialize(() -> {
walletFacadeInited = true;
if (messageFacadeInited) initialisationDone();
});
tradeManager.addTakeOfferRequestListener(this::onTakeOfferRequested);
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Interface implementation: NavigationController // Interface implementation: NavigationController
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Override @Override
public ChildController navigateToView(NavigationItem navigationItem) public ChildController navigateToView(NavigationItem navigationItem)
{ {
@ -181,57 +143,69 @@ public class MainController implements Initializable, NavigationController
} }
private ChildController loadView(NavigationItem navigationItem) ///////////////////////////////////////////////////////////////////////////////////////////
{ // Startup Handlers
if (controller != null) ///////////////////////////////////////////////////////////////////////////////////////////
{
controller.cleanup();
}
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl())); public void onViewInitialized()
try {
Profiler.printMsgWithTime("MainController.onViewInitialized");
Platform.runLater(this::initFacades);
}
private void onFacadesInitialised()
{
Profiler.printMsgWithTime("MainController.onFacadesInitialised");
// never called on regtest
walletFacade.addDownloadListener(new WalletFacade.DownloadListener()
{ {
final Node view = loader.load(); @Override
contentPane.getChildren().setAll(view); public void progress(double percent)
controller = loader.getController(); {
controller.setNavigationController(this); viewBuilder.loadingLabel.setText("Synchronise with network...");
} catch (IOException e) }
{
e.printStackTrace(); @Override
log.error("Loading view failed. " + navigationItem.getFxmlUrl()); public void doneDownload()
} {
return controller; viewBuilder.loadingLabel.setText("Synchronise with network done.");
}
});
tradeManager.addTakeOfferRequestListener(this::onTakeOfferRequested);
Platform.runLater(this::addNavigation);
}
private void onNavigationAdded()
{
Profiler.printMsgWithTime("MainController.onNavigationAdded");
Platform.runLater(this::loadContentView);
}
private void onContentViewLoaded()
{
Profiler.printMsgWithTime("MainController.onContentViewLoaded");
root.setId("main-view");
Platform.runLater(this::fadeOutSplash);
}
private void fadeOutSplash()
{
Profiler.printMsgWithTime("MainController.fadeOutSplash");
Transitions.blurOutAndRemove(viewBuilder.splashVBox);
Transitions.fadeIn(viewBuilder.menuBar);
Transitions.fadeIn(viewBuilder.anchorPane);
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Private methods // Handlers
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private void initialisationDone()
{
addNavigation();
Transitions.fadeOutAndRemove(loadingLabel);
Transitions.fadeOutAndRemove(loadingBar);
Transitions.fadeIn(leftNavPane);
Transitions.fadeIn(rightNavPane);
Transitions.fadeIn(contentPane);
NavigationItem selectedNavigationItem = (NavigationItem) persistence.read(this, "selectedNavigationItem");
if (selectedNavigationItem == null)
{
selectedNavigationItem = NavigationItem.HOME;
}
navigateToView(selectedNavigationItem);
}
//TODO make ordersButton also reacting to jump to pending tab //TODO make ordersButton also reacting to jump to pending tab
private void onTakeOfferRequested(String offerId, PeerAddress sender) private void onTakeOfferRequested(String offerId, PeerAddress sender)
{ {
final Button alertButton = new Button("", Icons.getIconImageView(Icons.MSG_ALERT)); final Button alertButton = new Button("", ImageUtil.getIconImageView(ImageUtil.MSG_ALERT));
alertButton.setId("nav-alert-button"); alertButton.setId("nav-alert-button");
alertButton.relocate(36, 19); alertButton.relocate(36, 19);
alertButton.setOnAction((e) -> { alertButton.setOnAction((e) -> {
@ -244,36 +218,103 @@ public class MainController implements Initializable, NavigationController
AWTSystemTray.setAlert(); AWTSystemTray.setAlert();
} }
///////////////////////////////////////////////////////////////////////////////////////////
// Private startup methods
///////////////////////////////////////////////////////////////////////////////////////////
private void initFacades()
{
Profiler.printMsgWithTime("MainController.initFacades");
messageFacade.init(new BootstrapListener()
{
@Override
public void onCompleted()
{
messageFacadeInited = true;
if (walletFacadeInited) onFacadesInitialised();
}
@Override
public void onFailed(Throwable throwable)
{
log.error(throwable.toString());
}
});
walletFacade.initialize(() -> {
walletFacadeInited = true;
if (messageFacadeInited) onFacadesInitialised();
});
}
private void addNavigation() private void addNavigation()
{ {
homeButton = addNavButton(leftNavPane, "Overview", NavigationItem.HOME); Profiler.printMsgWithTime("MainController.addNavigation");
homeButton = addNavButton(viewBuilder.leftNavPane, "Overview", NavigationItem.HOME);
buyButton = addNavButton(leftNavPane, "Buy BTC", NavigationItem.BUY); buyButton = addNavButton(viewBuilder.leftNavPane, "Buy BTC", NavigationItem.BUY);
sellButton = addNavButton(viewBuilder.leftNavPane, "Sell BTC", NavigationItem.SELL);
sellButton = addNavButton(leftNavPane, "Sell BTC", NavigationItem.SELL);
ordersButtonButtonHolder = new Pane(); ordersButtonButtonHolder = new Pane();
ordersButton = addNavButton(ordersButtonButtonHolder, "Orders", NavigationItem.ORDERS); ordersButton = addNavButton(ordersButtonButtonHolder, "Orders", NavigationItem.ORDERS);
leftNavPane.getChildren().add(ordersButtonButtonHolder); viewBuilder.leftNavPane.getChildren().add(ordersButtonButtonHolder);
fundsButton = addNavButton(leftNavPane, "Funds", NavigationItem.FUNDS); fundsButton = addNavButton(viewBuilder.leftNavPane, "Funds", NavigationItem.FUNDS);
final Pane msgButtonHolder = new Pane(); final Pane msgButtonHolder = new Pane();
msgButton = addNavButton(msgButtonHolder, "Message", NavigationItem.MSG); msgButton = addNavButton(msgButtonHolder, "Message", NavigationItem.MSG);
leftNavPane.getChildren().add(msgButtonHolder); viewBuilder.leftNavPane.getChildren().add(msgButtonHolder);
addBalanceInfo(rightNavPane); addBalanceInfo(viewBuilder.rightNavPane);
addAccountComboBox(rightNavPane); addAccountComboBox(viewBuilder.rightNavPane);
settingsButton = addNavButton(rightNavPane, "Settings", NavigationItem.SETTINGS); settingsButton = addNavButton(viewBuilder.rightNavPane, "Settings", NavigationItem.SETTINGS);
Platform.runLater(this::onNavigationAdded);
} }
private void loadContentView()
{
Profiler.printMsgWithTime("MainController.loadContentView");
NavigationItem selectedNavigationItem = (NavigationItem) persistence.read(this, "selectedNavigationItem");
if (selectedNavigationItem == null)
selectedNavigationItem = NavigationItem.BUY;
navigateToView(selectedNavigationItem);
Platform.runLater(this::onContentViewLoaded);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private methods
///////////////////////////////////////////////////////////////////////////////////////////
private ChildController loadView(NavigationItem navigationItem)
{
if (controller != null)
controller.cleanup();
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()));
try
{
final Node view = loader.load();
viewBuilder.contentPane.getChildren().setAll(view);
controller = loader.getController();
controller.setNavigationController(this);
} catch (IOException e)
{
e.printStackTrace();
log.error("Loading view failed. " + navigationItem.getFxmlUrl());
}
return controller;
}
private ToggleButton addNavButton(Pane parent, String title, NavigationItem navigationItem) private ToggleButton addNavButton(Pane parent, String title, NavigationItem navigationItem)
{ {
final Pane pane = new Pane(); final Pane pane = new Pane();
pane.setPrefSize(50, 50); pane.setPrefSize(50, 50);
final ToggleButton toggleButton = new ToggleButton("", Icons.getIconImageView(navigationItem.getIcon())); final ToggleButton toggleButton = new ToggleButton("", ImageUtil.getIconImageView(navigationItem.getIcon()));
toggleButton.setToggleGroup(toggleGroup); toggleButton.setToggleGroup(toggleGroup);
toggleButton.setId("nav-button"); toggleButton.setId("nav-button");
toggleButton.setPrefSize(50, 50); toggleButton.setPrefSize(50, 50);
@ -283,7 +324,7 @@ public class MainController implements Initializable, NavigationController
((ImageView) (prevToggleButton.getGraphic())).setImage(prevToggleButtonIcon); ((ImageView) (prevToggleButton.getGraphic())).setImage(prevToggleButtonIcon);
} }
prevToggleButtonIcon = ((ImageView) (toggleButton.getGraphic())).getImage(); prevToggleButtonIcon = ((ImageView) (toggleButton.getGraphic())).getImage();
((ImageView) (toggleButton.getGraphic())).setImage(Icons.getIconImage(navigationItem.getActiveIcon())); ((ImageView) (toggleButton.getGraphic())).setImage(ImageUtil.getIconImage(navigationItem.getActiveIcon()));
controller = loadView(navigationItem); controller = loadView(navigationItem);
@ -313,7 +354,7 @@ public class MainController implements Initializable, NavigationController
{ {
final TextField balanceTextField = new TextField(); final TextField balanceTextField = new TextField();
balanceTextField.setEditable(false); balanceTextField.setEditable(false);
balanceTextField.setPrefWidth(90); balanceTextField.setPrefWidth(110);
balanceTextField.setId("nav-balance-label"); balanceTextField.setId("nav-balance-label");
balanceTextField.setText(walletFacade.getWalletBalance().toFriendlyString()); balanceTextField.setText(walletFacade.getWalletBalance().toFriendlyString());
walletFacade.addBalanceListener(new BalanceListener() walletFacade.addBalanceListener(new BalanceListener()
@ -325,12 +366,9 @@ public class MainController implements Initializable, NavigationController
} }
}); });
final Label balanceCurrencyLabel = new Label("BTC");
balanceCurrencyLabel.setPadding(new Insets(6, 0, 0, 0));
final HBox hBox = new HBox(); final HBox hBox = new HBox();
hBox.setSpacing(2); hBox.setSpacing(2);
hBox.getChildren().setAll(balanceTextField, balanceCurrencyLabel); hBox.getChildren().setAll(balanceTextField);
final Label titleLabel = new Label("Balance"); final Label titleLabel = new Label("Balance");
titleLabel.setMouseTransparent(true); titleLabel.setMouseTransparent(true);
@ -382,4 +420,134 @@ public class MainController implements Initializable, NavigationController
parent.getChildren().add(vBox); parent.getChildren().add(vBox);
} }
} }
}
class ViewBuilder
{
HBox leftNavPane, rightNavPane;
AnchorPane contentPane;
NetworkSyncPane networkSyncPane;
StackPane stackPane;
AnchorPane anchorPane;
VBox splashVBox;
MenuBar menuBar;
BorderPane root;
Label loadingLabel;
void buildSplashScreen(BorderPane root, MainController controller)
{
Profiler.printMsgWithTime("MainController.ViewBuilder.buildSplashScreen");
this.root = root;
stackPane = new StackPane();
splashVBox = getSplashScreen();
stackPane.getChildren().add(splashVBox);
root.setCenter(stackPane);
menuBar = getMenuBar();
root.setTop(menuBar);
Platform.runLater(() -> buildContentView(controller));
}
void buildContentView(MainController controller)
{
Profiler.printMsgWithTime("MainController.ViewBuilder.buildContentView");
anchorPane = getContentScreen();
stackPane.getChildren().add(anchorPane);
Platform.runLater(controller::onViewInitialized);
}
AnchorPane getContentScreen()
{
AnchorPane anchorPane = new AnchorPane();
anchorPane.setId("content-pane");
leftNavPane = new HBox();
leftNavPane.setAlignment(Pos.CENTER);
leftNavPane.setSpacing(10);
AnchorPane.setLeftAnchor(leftNavPane, 0d);
AnchorPane.setTopAnchor(leftNavPane, 0d);
rightNavPane = new HBox();
rightNavPane.setAlignment(Pos.CENTER);
rightNavPane.setSpacing(10);
AnchorPane.setRightAnchor(rightNavPane, 10d);
AnchorPane.setTopAnchor(rightNavPane, 0d);
contentPane = new AnchorPane();
contentPane.setId("content-pane");
AnchorPane.setLeftAnchor(contentPane, 0d);
AnchorPane.setRightAnchor(contentPane, 0d);
AnchorPane.setTopAnchor(contentPane, 60d);
AnchorPane.setBottomAnchor(contentPane, 20d);
networkSyncPane = new NetworkSyncPane();
networkSyncPane.setSpacing(10);
networkSyncPane.setPrefHeight(20);
AnchorPane.setLeftAnchor(networkSyncPane, 0d);
AnchorPane.setBottomAnchor(networkSyncPane, 0d);
anchorPane.getChildren().addAll(leftNavPane, rightNavPane, contentPane, networkSyncPane);
anchorPane.setOpacity(0);
return anchorPane;
}
VBox getSplashScreen()
{
VBox splashVBox = new VBox();
splashVBox.setAlignment(Pos.CENTER);
splashVBox.setSpacing(10);
ImageView logo = ImageUtil.getIconImageView(ImageUtil.SPLASH_LOGO);
logo.setFitWidth(270);
logo.setFitHeight(200);
ImageView titleLabel = ImageUtil.getIconImageView(ImageUtil.SPLASH_LABEL);
titleLabel.setFitWidth(300);
titleLabel.setFitHeight(79);
Label subTitle = new Label("The P2P Fiat-Bitcoin Exchange");
subTitle.setAlignment(Pos.CENTER);
subTitle.setId("logo-sub-title-label");
loadingLabel = new Label("Initializing...");
loadingLabel.setAlignment(Pos.CENTER);
loadingLabel.setPadding(new Insets(80, 0, 0, 0));
splashVBox.getChildren().addAll(logo, titleLabel, subTitle, loadingLabel);
return splashVBox;
}
MenuBar getMenuBar()
{
MenuBar menuBar = new MenuBar();
// on mac we could place menu bar in the systems menu
// menuBar.setUseSystemMenuBar(true);
menuBar.setUseSystemMenuBar(false);
Menu fileMenu = new Menu("_File");
fileMenu.setMnemonicParsing(true);
MenuItem backupMenuItem = new MenuItem("Backup wallet");
fileMenu.getItems().addAll(backupMenuItem);
Menu settingsMenu = new Menu("_Settings");
settingsMenu.setMnemonicParsing(true);
MenuItem changePwMenuItem = new MenuItem("Change password");
settingsMenu.getItems().addAll(changePwMenuItem);
Menu helpMenu = new Menu("_Help");
helpMenu.setMnemonicParsing(true);
MenuItem faqMenuItem = new MenuItem("FAQ");
MenuItem forumMenuItem = new MenuItem("Forum");
helpMenu.getItems().addAll(faqMenuItem, forumMenuItem);
menuBar.getMenus().setAll(fileMenu, settingsMenu, helpMenu);
menuBar.setOpacity(0);
return menuBar;
}
} }

View file

@ -1,16 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import io.bitsquare.gui.components.NetworkSyncPane?> <?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.Label?> <BorderPane fx:id="root" id="splash" fx:controller="io.bitsquare.gui.MainController" prefHeight="750" prefWidth="1000" stylesheets="/io/bitsquare/gui/bitsquare.css"
<?import javafx.scene.control.ProgressBar?>
<?import javafx.scene.layout.*?>
<AnchorPane fx:id="rootPane" id="root-pane" fx:controller="io.bitsquare.gui.MainController" stylesheets="/io/bitsquare/gui/bitsquare.css"
xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<HBox fx:id="leftNavPane" opacity="0" spacing="10" AnchorPane.leftAnchor="0" AnchorPane.topAnchor="0"/> </BorderPane>
<HBox fx:id="rightNavPane" opacity="0" spacing="10" AnchorPane.rightAnchor="10" AnchorPane.topAnchor="0"/>
<AnchorPane fx:id="contentPane" id="content-pane" opacity="0" AnchorPane.bottomAnchor="20" AnchorPane.leftAnchor="0" AnchorPane.rightAnchor="0" AnchorPane.topAnchor="60"/>
<NetworkSyncPane fx:id="networkSyncPane" spacing="10" prefHeight="20" AnchorPane.bottomAnchor="0" AnchorPane.leftAnchor="0"/>
<ProgressBar fx:id="loadingBar" progress="-1" prefHeight="20" prefWidth="200" AnchorPane.topAnchor="250" AnchorPane.leftAnchor="300"/>
<Label fx:id="loadingLabel" text="Loading..." textAlignment="CENTER" alignment="CENTER" prefHeight="20" prefWidth="200" AnchorPane.topAnchor="280" AnchorPane.leftAnchor="300"/>
</AnchorPane>

View file

@ -1,17 +1,17 @@
package io.bitsquare.gui; package io.bitsquare.gui;
import io.bitsquare.gui.util.Icons; import io.bitsquare.gui.util.ImageUtil;
public enum NavigationItem public enum NavigationItem
{ {
MAIN("/io/bitsquare/gui/MainView.fxml"), MAIN("/io/bitsquare/gui/MainView.fxml"),
HOME("/io/bitsquare/gui/home/HomeView.fxml", Icons.HOME, Icons.HOME_ACTIVE), HOME("/io/bitsquare/gui/home/HomeView.fxml", ImageUtil.HOME, ImageUtil.HOME_ACTIVE),
BUY("/io/bitsquare/gui/market/MarketView.fxml", Icons.NAV_BUY, Icons.NAV_BUY_ACTIVE), BUY("/io/bitsquare/gui/market/MarketView.fxml", ImageUtil.NAV_BUY, ImageUtil.NAV_BUY_ACTIVE),
SELL("/io/bitsquare/gui/market/MarketView.fxml", Icons.NAV_SELL, Icons.NAV_SELL_ACTIVE), SELL("/io/bitsquare/gui/market/MarketView.fxml", ImageUtil.NAV_SELL, ImageUtil.NAV_SELL_ACTIVE),
ORDERS("/io/bitsquare/gui/orders/OrdersView.fxml", Icons.ORDERS, Icons.ORDERS_ACTIVE), ORDERS("/io/bitsquare/gui/orders/OrdersView.fxml", ImageUtil.ORDERS, ImageUtil.ORDERS_ACTIVE),
FUNDS("/io/bitsquare/gui/funds/FundsView.fxml", Icons.FUNDS, Icons.FUNDS_ACTIVE), FUNDS("/io/bitsquare/gui/funds/FundsView.fxml", ImageUtil.FUNDS, ImageUtil.FUNDS_ACTIVE),
MSG("/io/bitsquare/gui/msg/MsgView.fxml", Icons.MSG, Icons.MSG_ACTIVE), MSG("/io/bitsquare/gui/msg/MsgView.fxml", ImageUtil.MSG, ImageUtil.MSG_ACTIVE),
SETTINGS("/io/bitsquare/gui/settings/SettingsView.fxml", Icons.SETTINGS, Icons.SETTINGS_ACTIVE), SETTINGS("/io/bitsquare/gui/settings/SettingsView.fxml", ImageUtil.SETTINGS, ImageUtil.SETTINGS_ACTIVE),
ORDER_BOOK("/io/bitsquare/gui/market/orderbook/OrderBookView.fxml"), ORDER_BOOK("/io/bitsquare/gui/market/orderbook/OrderBookView.fxml"),
CREATE_OFFER("/io/bitsquare/gui/market/createOffer/CreateOfferView.fxml"), CREATE_OFFER("/io/bitsquare/gui/market/createOffer/CreateOfferView.fxml"),

View file

@ -1,4 +1,13 @@
#root-pane { #splash {
-fx-background-color: #ffffff;
}
#logo-sub-title-label{
-fx-font-weight: bold;
-fx-font-size: 24;
}
#main-view {
-fx-background-color: #dddddd; -fx-background-color: #dddddd;
} }
@ -53,7 +62,7 @@
.text-field:readonly { .text-field:readonly {
-fx-text-fill: #000000; -fx-text-fill: #000000;
-fx-background-color: #FAFAFA; -fx-background-color: #FBFBFB;
} }
#feedback-text { #feedback-text {

View file

@ -15,7 +15,7 @@ import io.bitsquare.gui.market.createOffer.CreateOfferController;
import io.bitsquare.gui.market.trade.TakerOfferController; import io.bitsquare.gui.market.trade.TakerOfferController;
import io.bitsquare.gui.popups.Popups; import io.bitsquare.gui.popups.Popups;
import io.bitsquare.gui.util.BitSquareFormatter; import io.bitsquare.gui.util.BitSquareFormatter;
import io.bitsquare.gui.util.Icons; import io.bitsquare.gui.util.ImageUtil;
import io.bitsquare.locale.Country; import io.bitsquare.locale.Country;
import io.bitsquare.locale.CurrencyUtil; import io.bitsquare.locale.CurrencyUtil;
import io.bitsquare.locale.Localisation; import io.bitsquare.locale.Localisation;
@ -65,8 +65,8 @@ public class OrderBookController implements Initializable, ChildController
private final Settings settings; private final Settings settings;
private final Persistence persistence; private final Persistence persistence;
private final Image buyIcon = Icons.getIconImage(Icons.BUY); private final Image buyIcon = ImageUtil.getIconImage(ImageUtil.BUY);
private final Image sellIcon = Icons.getIconImage(Icons.SELL); private final Image sellIcon = ImageUtil.getIconImage(ImageUtil.SELL);
@FXML @FXML
public AnchorPane holderPane; public AnchorPane holderPane;
@FXML @FXML
@ -433,7 +433,7 @@ public class OrderBookController implements Initializable, ChildController
if (offer.getMessagePublicKey().equals(user.getMessagePublicKey())) if (offer.getMessagePublicKey().equals(user.getMessagePublicKey()))
{ {
icon = Icons.getIconImage(Icons.REMOVE); icon = ImageUtil.getIconImage(ImageUtil.REMOVE);
title = "Remove"; title = "Remove";
button.setOnAction(event -> removeOffer(orderBookListItem.getOffer())); button.setOnAction(event -> removeOffer(orderBookListItem.getOffer()));
} }
@ -499,7 +499,7 @@ public class OrderBookController implements Initializable, ChildController
Country country = orderBookListItem.getOffer().getBankAccountCountry(); Country country = orderBookListItem.getOffer().getBankAccountCountry();
try try
{ {
hBox.getChildren().add(Icons.getIconImageView("/images/countries/" + country.getCode().toLowerCase() + ".png")); hBox.getChildren().add(ImageUtil.getIconImageView("/images/countries/" + country.getCode().toLowerCase() + ".png"));
} catch (Exception e) } catch (Exception e)
{ {

View file

@ -3,7 +3,7 @@ package io.bitsquare.gui.orders.offer;
import io.bitsquare.gui.ChildController; import io.bitsquare.gui.ChildController;
import io.bitsquare.gui.Hibernate; import io.bitsquare.gui.Hibernate;
import io.bitsquare.gui.NavigationController; import io.bitsquare.gui.NavigationController;
import io.bitsquare.gui.util.Icons; import io.bitsquare.gui.util.ImageUtil;
import io.bitsquare.trade.Offer; import io.bitsquare.trade.Offer;
import io.bitsquare.trade.TradeManager; import io.bitsquare.trade.TradeManager;
import java.net.URL; import java.net.URL;
@ -172,7 +172,7 @@ public class OfferController implements Initializable, ChildController, Hibernat
{ {
return new TableCell<String, OfferListItem>() return new TableCell<String, OfferListItem>()
{ {
final ImageView iconView = Icons.getIconImageView(Icons.REMOVE); final ImageView iconView = ImageUtil.getIconImageView(ImageUtil.REMOVE);
final Button button = new Button(); final Button button = new Button();
{ {

View file

@ -14,7 +14,7 @@ import io.bitsquare.gui.NavigationController;
import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator; import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator;
import io.bitsquare.gui.util.BitSquareFormatter; import io.bitsquare.gui.util.BitSquareFormatter;
import io.bitsquare.gui.util.ConfidenceDisplay; import io.bitsquare.gui.util.ConfidenceDisplay;
import io.bitsquare.gui.util.Icons; import io.bitsquare.gui.util.ImageUtil;
import io.bitsquare.locale.Country; import io.bitsquare.locale.Country;
import io.bitsquare.locale.Localisation; import io.bitsquare.locale.Localisation;
import io.bitsquare.trade.Direction; import io.bitsquare.trade.Direction;
@ -52,8 +52,8 @@ public class PendingTradeController implements Initializable, ChildController, H
private Trade currentTrade; private Trade currentTrade;
private NavigationController navigationController; private NavigationController navigationController;
private Image buyIcon = Icons.getIconImage(Icons.BUY); private Image buyIcon = ImageUtil.getIconImage(ImageUtil.BUY);
private Image sellIcon = Icons.getIconImage(Icons.SELL); private Image sellIcon = ImageUtil.getIconImage(ImageUtil.SELL);
private ConfidenceDisplay confidenceDisplay; private ConfidenceDisplay confidenceDisplay;
@FXML @FXML
@ -390,7 +390,7 @@ public class PendingTradeController implements Initializable, ChildController, H
Country country = tradesTableItem.getTrade().getOffer().getBankAccountCountry(); Country country = tradesTableItem.getTrade().getOffer().getBankAccountCountry();
try try
{ {
hBox.getChildren().add(Icons.getIconImageView("/images/countries/" + country.getCode().toLowerCase() + ".png")); hBox.getChildren().add(ImageUtil.getIconImageView("/images/countries/" + country.getCode().toLowerCase() + ".png"));
} catch (Exception e) } catch (Exception e)
{ {

View file

@ -10,7 +10,7 @@ import io.bitsquare.gui.ChildController;
import io.bitsquare.gui.NavigationController; import io.bitsquare.gui.NavigationController;
import io.bitsquare.gui.NavigationItem; import io.bitsquare.gui.NavigationItem;
import io.bitsquare.gui.util.BitSquareValidator; import io.bitsquare.gui.util.BitSquareValidator;
import io.bitsquare.gui.util.Icons; import io.bitsquare.gui.util.ImageUtil;
import io.bitsquare.locale.*; import io.bitsquare.locale.*;
import io.bitsquare.msg.MessageFacade; import io.bitsquare.msg.MessageFacade;
import io.bitsquare.settings.Settings; import io.bitsquare.settings.Settings;
@ -358,7 +358,7 @@ public class SettingsController implements Initializable, ChildController, Navig
final HBox hBox = new HBox(); final HBox hBox = new HBox();
final Label label = new Label(); final Label label = new Label();
final Button removeButton = new Button(); final Button removeButton = new Button();
final ImageView icon = Icons.getIconImageView(Icons.REMOVE); final ImageView icon = ImageUtil.getIconImageView(ImageUtil.REMOVE);
{ {
label.setPrefWidth(565); label.setPrefWidth(565);
@ -443,7 +443,7 @@ public class SettingsController implements Initializable, ChildController, Navig
final HBox hBox = new HBox(); final HBox hBox = new HBox();
final Label label = new Label(); final Label label = new Label();
final Button removeButton = new Button(); final Button removeButton = new Button();
final ImageView icon = Icons.getIconImageView(Icons.REMOVE); final ImageView icon = ImageUtil.getIconImageView(ImageUtil.REMOVE);
{ {
label.setPrefWidth(565); label.setPrefWidth(565);
@ -513,7 +513,7 @@ public class SettingsController implements Initializable, ChildController, Navig
final HBox hBox = new HBox(); final HBox hBox = new HBox();
final Label label = new Label(); final Label label = new Label();
final Button removeButton = new Button(); final Button removeButton = new Button();
final ImageView icon = Icons.getIconImageView(Icons.REMOVE); final ImageView icon = ImageUtil.getIconImageView(ImageUtil.REMOVE);
{ {
label.setPrefWidth(565); label.setPrefWidth(565);

View file

@ -3,8 +3,11 @@ package io.bitsquare.gui.util;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
public class Icons public class ImageUtil
{ {
public static final String SPLASH_LOGO = "/images/logo_200_270.png";
public static final String SPLASH_LABEL = "/images/bitsquare_logo_label_300_69.png";
public static final String SYS_TRAY = "/images/systemTrayIcon.png"; public static final String SYS_TRAY = "/images/systemTrayIcon.png";
public static final String SYS_TRAY_ALERT = "/images/systemTrayAlertIcon.png"; public static final String SYS_TRAY_ALERT = "/images/systemTrayAlertIcon.png";
@ -32,12 +35,12 @@ public class Icons
public static Image getIconImage(String iconName) public static Image getIconImage(String iconName)
{ {
return new Image(Icons.class.getResourceAsStream(iconName)); return new Image(ImageUtil.class.getResourceAsStream(iconName));
} }
public static ImageView getIconImageView(String iconName) public static ImageView getIconImageView(String iconName)
{ {
return new ImageView(new Image(Icons.class.getResourceAsStream(iconName))); return new ImageView(new Image(ImageUtil.class.getResourceAsStream(iconName)));
} }
} }

View file

@ -6,74 +6,104 @@ import javafx.scene.Node;
import javafx.scene.effect.GaussianBlur; import javafx.scene.effect.GaussianBlur;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
import javafx.util.Duration; import javafx.util.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public class Transitions public class Transitions
{ {
private static final Logger log = LoggerFactory.getLogger(Transitions.class);
public static final int UI_ANIMATION_TIME = 800; public static final int UI_ANIMATION_TIME = 800;
public static void fadeIn(Node ui) public static void fadeIn(Node node)
{ {
fadeIn(ui, UI_ANIMATION_TIME); fadeIn(node, UI_ANIMATION_TIME);
} }
@SuppressWarnings("SameParameterValue") @SuppressWarnings("SameParameterValue")
public static void fadeIn(Node ui, int time) public static void fadeIn(Node node, int duration)
{ {
FadeTransition ft = new FadeTransition(Duration.millis(time), ui); FadeTransition ft = new FadeTransition(Duration.millis(duration), node);
ft.setFromValue(0.0); ft.setFromValue(0.0);
ft.setToValue(1.0); ft.setToValue(1.0);
ft.play(); ft.play();
} }
public static Animation fadeOut(Node node)
public static Animation fadeOut(Node ui)
{ {
FadeTransition ft = new FadeTransition(Duration.millis(UI_ANIMATION_TIME), ui); return fadeOut(node, UI_ANIMATION_TIME);
ft.setFromValue(ui.getOpacity()); }
public static Animation fadeOut(Node node, int duration)
{
FadeTransition ft = new FadeTransition(Duration.millis(duration), node);
ft.setFromValue(node.getOpacity());
ft.setToValue(0.0); ft.setToValue(0.0);
ft.play(); ft.play();
return ft; return ft;
} }
@SuppressWarnings("UnusedReturnValue") @SuppressWarnings("UnusedReturnValue")
public static Animation fadeOutAndRemove(Node node)
public static Animation fadeOutAndRemove(Node ui)
{ {
Animation animation = fadeOut(ui); return fadeOutAndRemove(node, UI_ANIMATION_TIME);
animation.setOnFinished(actionEvent -> ((Pane) (ui.getParent())).getChildren().remove(ui)); }
public static Animation fadeOutAndRemove(Node node, int duration)
{
Animation animation = fadeOut(node, duration);
animation.setOnFinished(actionEvent -> {
((Pane) (node.getParent())).getChildren().remove(node);
Profiler.printMsgWithTime("fadeOutAndRemove");
});
return animation; return animation;
} }
public static Timeline blurOutAndRemove(Node node)
{
return blurOutAndRemove(node, UI_ANIMATION_TIME);
}
public static Timeline blurOutAndRemove(Node node, int duration)
{
Timeline timeline = blurOut(node, duration);
timeline.setOnFinished(actionEvent -> {
((Pane) (node.getParent())).getChildren().remove(node);
Profiler.printMsgWithTime("blurOutAndRemove");
});
return timeline;
}
public static void blurOut(Node node) public static void blurOut(Node node)
{ {
blurOut(node, UI_ANIMATION_TIME); blurOut(node, UI_ANIMATION_TIME);
} }
@SuppressWarnings("SameParameterValue") @SuppressWarnings("SameParameterValue")
public static void blurOut(Node node, int time) public static Timeline blurOut(Node node, int duration)
{ {
GaussianBlur blur = new GaussianBlur(0.0); GaussianBlur blur = new GaussianBlur(0.0);
node.setEffect(blur); node.setEffect(blur);
Timeline timeline = new Timeline(); Timeline timeline = new Timeline();
KeyValue kv = new KeyValue(blur.radiusProperty(), 10.0); KeyValue kv = new KeyValue(blur.radiusProperty(), 10.0);
KeyFrame kf = new KeyFrame(Duration.millis(time), kv); KeyFrame kf = new KeyFrame(Duration.millis(duration), kv);
timeline.getKeyFrames().add(kf); timeline.getKeyFrames().add(kf);
timeline.play(); timeline.play();
return timeline;
} }
public static void blurIn(Node node) public static void blurIn(Node node)
{ {
GaussianBlur blur = (GaussianBlur) node.getEffect(); GaussianBlur blur = (GaussianBlur) node.getEffect();
Timeline timeline = new Timeline(); Timeline durationline = new Timeline();
KeyValue kv = new KeyValue(blur.radiusProperty(), 0.0); KeyValue kv = new KeyValue(blur.radiusProperty(), 0.0);
KeyFrame kf = new KeyFrame(Duration.millis(UI_ANIMATION_TIME), kv); KeyFrame kf = new KeyFrame(Duration.millis(UI_ANIMATION_TIME), kv);
timeline.getKeyFrames().add(kf); durationline.getKeyFrames().add(kf);
timeline.setOnFinished(actionEvent -> node.setEffect(null)); durationline.setOnFinished(actionEvent -> node.setEffect(null));
timeline.play(); durationline.play();
} }
public static void checkGuiThread() public static void checkGuiThread()

View file

@ -1,22 +0,0 @@
.text-field.validation_error, .text-area.validation_error .content, .date-picker.validation_error > .text-field {
-fx-effect: innershadow(three-pass-box, red, 12 , 0.5, 1, 1);
}
#error-msg-item .label {
-fx-text-fill: white;
}
#error-msg-item:focused {
-fx-background-color: #B80000;
}
#error-msg-item:focused .label {
-fx-text-fill: white;
}
#error-msg {
-fx-background-color: #B80000;
-fx-padding: 0;
-fx-background-radius: 4 4 4 4;
}

View file

@ -258,7 +258,7 @@ public class MessageFacade implements MessageBroker
Platform.runLater(() -> orderBookListeners.stream().forEach(orderBookListener -> orderBookListener.onOffersReceived(futureGet.dataMap(), baseFuture.isSuccess()))); Platform.runLater(() -> orderBookListeners.stream().forEach(orderBookListener -> orderBookListener.onOffersReceived(futureGet.dataMap(), baseFuture.isSuccess())));
if (baseFuture.isSuccess()) if (baseFuture.isSuccess())
{ {
log.trace("Get offers from DHT was successful. Stored data: [key: " + locationKey + ", values: " + futureGet.dataMap() + "]"); //log.trace("Get offers from DHT was successful. Stored data: [key: " + locationKey + ", values: " + futureGet.dataMap() + "]");
} }
else else
{ {

View file

@ -2,7 +2,7 @@ package io.bitsquare.util;
import io.bitsquare.BitSquare; import io.bitsquare.BitSquare;
import io.bitsquare.gui.util.Icons; import io.bitsquare.gui.util.ImageUtil;
import java.awt.*; import java.awt.*;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.stage.Stage; import javafx.stage.Stage;
@ -27,7 +27,7 @@ public class AWTSystemTray
Platform.setImplicitExit(false); Platform.setImplicitExit(false);
SystemTray systemTray = SystemTray.getSystemTray(); SystemTray systemTray = SystemTray.getSystemTray();
trayIcon = new TrayIcon(getImage(Icons.SYS_TRAY)); trayIcon = new TrayIcon(getImage(ImageUtil.SYS_TRAY));
trayIcon.setToolTip("BitSquare P2P Fiat-Bitcoin exchange"); trayIcon.setToolTip("BitSquare P2P Fiat-Bitcoin exchange");
PopupMenu popupMenu = new PopupMenu(); PopupMenu popupMenu = new PopupMenu();
@ -78,12 +78,12 @@ public class AWTSystemTray
public static void setAlert() public static void setAlert()
{ {
trayIcon.setImage(getImage(Icons.SYS_TRAY_ALERT)); trayIcon.setImage(getImage(ImageUtil.SYS_TRAY_ALERT));
} }
public static void unSetAlert() public static void unSetAlert()
{ {
trayIcon.setImage(getImage(Icons.SYS_TRAY)); trayIcon.setImage(getImage(ImageUtil.SYS_TRAY));
} }
public static void setStageHidden() public static void setStageHidden()

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB