mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-24 23:18:17 +01:00
Integrate UpdateFX with MockUpdateProcess
This commit is contained in:
parent
2e97e900e5
commit
426b38180c
10 changed files with 605 additions and 131 deletions
|
@ -45,7 +45,9 @@ public class BitsquareEnvironment extends StandardEnvironment {
|
|||
|
||||
public static final String APP_VERSION_KEY = "app.version";
|
||||
|
||||
// TODO what is the difference to APP_DATA_DIR ?
|
||||
public static final String USER_DATA_DIR_KEY = "user.data.dir";
|
||||
|
||||
public static final String DEFAULT_USER_DATA_DIR = defaultUserDataDir();
|
||||
|
||||
public static final String APP_NAME_KEY = "app.name";
|
||||
|
|
|
@ -49,12 +49,17 @@ import javafx.scene.image.*;
|
|||
import javafx.scene.input.*;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.FileSystemUtils;
|
||||
|
||||
import static io.bitsquare.app.BitsquareEnvironment.*;
|
||||
|
||||
public class BitsquareApp extends Application {
|
||||
private static final Logger log = LoggerFactory.getLogger(BitsquareAppMain.class);
|
||||
|
||||
private static Environment env;
|
||||
|
||||
private BitsquareAppModule bitsquareAppModule;
|
||||
|
@ -66,6 +71,9 @@ public class BitsquareApp extends Application {
|
|||
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws IOException {
|
||||
// For some reason the JavaFX launch process results in us losing the thread context class loader: reset it.
|
||||
Thread.currentThread().setContextClassLoader(BitsquareApp.class.getClassLoader());
|
||||
|
||||
bitsquareAppModule = new BitsquareAppModule(env, primaryStage);
|
||||
injector = Guice.createInjector(bitsquareAppModule);
|
||||
injector.getInstance(InjectorViewFactory.class).setInjector(injector);
|
||||
|
@ -139,8 +147,7 @@ public class BitsquareApp extends Application {
|
|||
else
|
||||
iconPath = "/images/task_bar_icon_linux.png";
|
||||
|
||||
if (iconPath != null)
|
||||
primaryStage.getIcons().add(new Image(getClass().getResourceAsStream(iconPath)));
|
||||
primaryStage.getIcons().add(new Image(getClass().getResourceAsStream(iconPath)));
|
||||
|
||||
|
||||
// make the UI visible
|
||||
|
|
|
@ -24,6 +24,12 @@ import io.bitsquare.network.BootstrapNodes;
|
|||
import io.bitsquare.network.Node;
|
||||
import io.bitsquare.util.joptsimple.EnumValueConverter;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.vinumeris.updatefx.UpdateFX;
|
||||
import joptsimple.OptionParser;
|
||||
import joptsimple.OptionSet;
|
||||
|
||||
|
@ -33,8 +39,17 @@ import static io.bitsquare.network.Node.*;
|
|||
import static java.util.Arrays.asList;
|
||||
|
||||
public class BitsquareAppMain extends BitsquareExecutable {
|
||||
private static final Logger log = LoggerFactory.getLogger(BitsquareAppMain.class);
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// We don't want to do the whole arg parsing/setup here as that might easily change in update versions
|
||||
// So we only handle the absolute minimum which is APP_NAME and USER_DATA_DIR
|
||||
// TODO Not impl. yet, just use default for first testings
|
||||
UpdateFX.bootstrap(BitsquareAppMain.class, new File(BitsquareEnvironment.DEFAULT_APP_DATA_DIR).toPath(), args);
|
||||
}
|
||||
|
||||
// That will be called from UpdateFX after updates are checked
|
||||
public static void realMain(String[] args) throws Exception {
|
||||
new BitsquareAppMain().execute(args);
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,11 @@ class BitsquareAppModule extends BitsquareModule {
|
|||
bindConstant().annotatedWith(named(Persistence.PREFIX_KEY)).to(env.getRequiredProperty(Persistence.PREFIX_KEY));
|
||||
bind(Persistence.class).asEagerSingleton();
|
||||
|
||||
// TODO UpdateFXHelper needs Environment. Should we just expose the 2 properties needed?
|
||||
bind(Environment.class).toInstance(env);
|
||||
// for temp testing with mock
|
||||
bind(UpdateProcess.class).to(MockUpdateProcess.class).asEagerSingleton();
|
||||
|
||||
install(messageModule());
|
||||
install(bitcoinModule());
|
||||
install(cryptoModule());
|
||||
|
|
154
src/main/java/io/bitsquare/app/gui/ExampleApp.java
Normal file
154
src/main/java/io/bitsquare/app/gui/ExampleApp.java
Normal file
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.app.gui;
|
||||
|
||||
import org.bitcoinj.utils.BriefLogFormatter;
|
||||
|
||||
import com.google.common.util.concurrent.Uninterruptibles;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.FileHandler;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.*;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.layout.*;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.vinumeris.updatefx.AppDirectory;
|
||||
import com.vinumeris.updatefx.Crypto;
|
||||
import com.vinumeris.updatefx.UpdateFX;
|
||||
import com.vinumeris.updatefx.UpdateSummary;
|
||||
import com.vinumeris.updatefx.Updater;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
|
||||
// TODO remove it after we have impl. UpdateFX.
|
||||
// Let it here for reference and for easier test setup for the moment.
|
||||
public class ExampleApp extends Application {
|
||||
private static final Logger log = LoggerFactory.getLogger(ExampleApp.class);
|
||||
public static int VERSION = 3;
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
// We want to store updates in our app dir so must init that here.
|
||||
AppDirectory.initAppDir("UpdateFX Example App");
|
||||
setupLogging();
|
||||
// re-enter at realMain, but possibly running a newer version of the software i.e. after this point the
|
||||
// rest of this code may be ignored.
|
||||
UpdateFX.bootstrap(ExampleApp.class, AppDirectory.dir(), args);
|
||||
}
|
||||
|
||||
public static void realMain(String[] args) {
|
||||
launch(args);
|
||||
}
|
||||
|
||||
private static java.util.logging.Logger logger;
|
||||
|
||||
private static void setupLogging() throws IOException {
|
||||
logger = java.util.logging.Logger.getLogger("");
|
||||
logger.getHandlers()[0].setFormatter(new BriefLogFormatter());
|
||||
FileHandler handler = new FileHandler(AppDirectory.dir().resolve("log.txt").toString(), true);
|
||||
handler.setFormatter(new BriefLogFormatter());
|
||||
logger.addHandler(handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws Exception {
|
||||
// For some reason the JavaFX launch process results in us losing the thread context class loader: reset it.
|
||||
Thread.currentThread().setContextClassLoader(ExampleApp.class.getClassLoader());
|
||||
// Must be done twice for the times when we come here via realMain.
|
||||
AppDirectory.initAppDir("UpdateFX Example App");
|
||||
|
||||
log.info("Hello World! This is version " + VERSION);
|
||||
|
||||
ProgressIndicator indicator = showGiantProgressWheel(primaryStage);
|
||||
|
||||
List<ECPoint> pubkeys = Crypto.decode("028B41BDDCDCAD97B6AE088FEECA16DC369353B717E13319370C729CB97D677A11",
|
||||
// wallet_1
|
||||
"031E3D80F21A4D10D385A32ABEDC300DACBEDBC839FBA58376FBD5D791D806BA68"); // wallet
|
||||
|
||||
Updater updater = new Updater("http://localhost:8000/", "ExampleApp/" + VERSION, VERSION,
|
||||
AppDirectory.dir(), UpdateFX.findCodePath(ExampleApp.class),
|
||||
pubkeys, 1) {
|
||||
@Override
|
||||
protected void updateProgress(long workDone, long max) {
|
||||
super.updateProgress(workDone, max);
|
||||
// Give UI a chance to show.
|
||||
Uninterruptibles.sleepUninterruptibly(100, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
};
|
||||
|
||||
indicator.progressProperty().bind(updater.progressProperty());
|
||||
|
||||
log.info("Checking for updates!");
|
||||
updater.setOnSucceeded(event -> {
|
||||
try {
|
||||
UpdateSummary summary = updater.get();
|
||||
if (summary.descriptions.size() > 0) {
|
||||
log.info("One liner: {}", summary.descriptions.get(0).getOneLiner());
|
||||
log.info("{}", summary.descriptions.get(0).getDescription());
|
||||
}
|
||||
if (summary.highestVersion > VERSION) {
|
||||
log.info("Restarting to get version " + summary.highestVersion);
|
||||
if (UpdateFX.getVersionPin(AppDirectory.dir()) == 0)
|
||||
UpdateFX.restartApp();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
log.error("oops", e);
|
||||
}
|
||||
});
|
||||
updater.setOnFailed(event -> {
|
||||
log.error("Update error: {}", updater.getException());
|
||||
updater.getException().printStackTrace();
|
||||
});
|
||||
|
||||
indicator.setOnMouseClicked(ev -> UpdateFX.restartApp());
|
||||
|
||||
new Thread(updater, "UpdateFX Thread").start();
|
||||
|
||||
primaryStage.show();
|
||||
}
|
||||
|
||||
private ProgressIndicator showGiantProgressWheel(Stage stage) {
|
||||
ProgressIndicator indicator = new ProgressIndicator();
|
||||
BorderPane borderPane = new BorderPane(indicator);
|
||||
borderPane.setMinWidth(640);
|
||||
borderPane.setMinHeight(480);
|
||||
Button pinButton = new Button();
|
||||
pinButton.setText("Pin to version 1");
|
||||
pinButton.setOnAction(event -> {
|
||||
UpdateFX.pinToVersion(AppDirectory.dir(), 1);
|
||||
UpdateFX.restartApp();
|
||||
});
|
||||
HBox box = new HBox(new Label("Version " + VERSION), pinButton);
|
||||
box.setSpacing(10);
|
||||
box.setAlignment(Pos.CENTER_LEFT);
|
||||
box.setPadding(new Insets(10));
|
||||
borderPane.setTop(box);
|
||||
Scene scene = new Scene(borderPane);
|
||||
stage.setScene(scene);
|
||||
return indicator;
|
||||
}
|
||||
}
|
56
src/main/java/io/bitsquare/app/gui/MockUpdateProcess.java
Normal file
56
src/main/java/io/bitsquare/app/gui/MockUpdateProcess.java
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.app.gui;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
public class MockUpdateProcess extends UpdateProcess {
|
||||
private static final Logger log = LoggerFactory.getLogger(MockUpdateProcess.class);
|
||||
|
||||
@Inject
|
||||
public MockUpdateProcess(Environment environment) {
|
||||
super(environment);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init(Environment environment) {
|
||||
|
||||
/* timeoutTimer.stop();
|
||||
state.set(State.UPDATE_AVAILABLE);*/
|
||||
|
||||
state.set(State.UP_TO_DATE);
|
||||
timeoutTimer.stop();
|
||||
process.onCompleted();
|
||||
|
||||
/* state.set(State.FAILURE);
|
||||
errorMessage = "dummy exc.";
|
||||
timeoutTimer.stop();
|
||||
process.onCompleted();*/
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restart() {
|
||||
log.debug("restart requested");
|
||||
}
|
||||
}
|
176
src/main/java/io/bitsquare/app/gui/UpdateProcess.java
Normal file
176
src/main/java/io/bitsquare/app/gui/UpdateProcess.java
Normal file
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.app.gui;
|
||||
|
||||
import io.bitsquare.app.BitsquareEnvironment;
|
||||
import io.bitsquare.util.Utilities;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javafx.animation.AnimationTimer;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.vinumeris.updatefx.Crypto;
|
||||
import com.vinumeris.updatefx.UpdateFX;
|
||||
import com.vinumeris.updatefx.UpdateSummary;
|
||||
import com.vinumeris.updatefx.Updater;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.springframework.core.env.Environment;
|
||||
import rx.Observable;
|
||||
import rx.subjects.BehaviorSubject;
|
||||
import rx.subjects.Subject;
|
||||
|
||||
public class UpdateProcess {
|
||||
private static final Logger log = LoggerFactory.getLogger(UpdateProcess.class);
|
||||
|
||||
private static final int VERSION = 1;
|
||||
private static final List<ECPoint> UPDATE_SIGNING_KEYS = Crypto.decode(
|
||||
"028B41BDDCDCAD97B6AE088FEECA16DC369353B717E13319370C729CB97D677A11",
|
||||
"031E3D80F21A4D10D385A32ABEDC300DACBEDBC839FBA58376FBD5D791D806BA68"
|
||||
);
|
||||
private static final int UPDATE_SIGNING_THRESHOLD = 1;
|
||||
private static final String UPDATES_BASE_URL = "http://localhost:8000/";
|
||||
private static final Path ROOT_CLASS_PATH = UpdateFX.findCodePath(BitsquareAppMain.class);
|
||||
|
||||
|
||||
public enum State {
|
||||
CHECK_FOR_UPDATES,
|
||||
UPDATE_AVAILABLE,
|
||||
UP_TO_DATE,
|
||||
FAILURE
|
||||
}
|
||||
|
||||
public final ObjectProperty<State> state = new SimpleObjectProperty<>(State.CHECK_FOR_UPDATES);
|
||||
|
||||
protected String errorMessage;
|
||||
protected final Subject<State, State> process = BehaviorSubject.create();
|
||||
protected final AnimationTimer timeoutTimer;
|
||||
|
||||
@Inject
|
||||
public UpdateProcess(Environment environment) {
|
||||
// process.timeout() will cause an error state back but we dont want to break startup in case of an update
|
||||
// timeout
|
||||
timeoutTimer = Utilities.setTimeout(10000, new Function<AnimationTimer, Void>() {
|
||||
@Override
|
||||
public Void apply(AnimationTimer animationTimer) {
|
||||
process.onCompleted();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
timeoutTimer.start();
|
||||
|
||||
init(environment);
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
UpdateFX.restartApp();
|
||||
}
|
||||
|
||||
public Observable<State> getProcess() {
|
||||
return process.asObservable();
|
||||
}
|
||||
|
||||
public String getErrorMessage() {
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
protected void init(Environment environment) {
|
||||
log.info("version " + VERSION);
|
||||
|
||||
String agent = environment.getProperty(BitsquareEnvironment.APP_NAME_KEY) + VERSION;
|
||||
Path dataDirPath = new File(environment.getProperty(BitsquareEnvironment.APP_DATA_DIR_KEY)).toPath();
|
||||
Updater updater = new Updater(UPDATES_BASE_URL, agent, VERSION, dataDirPath, ROOT_CLASS_PATH,
|
||||
UPDATE_SIGNING_KEYS, UPDATE_SIGNING_THRESHOLD) {
|
||||
@Override
|
||||
protected void updateProgress(long workDone, long max) {
|
||||
log.debug("updateProgress " + workDone + "/" + max);
|
||||
super.updateProgress(workDone, max);
|
||||
}
|
||||
};
|
||||
|
||||
updater.progressProperty().addListener(new ChangeListener<Number>() {
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends Number> observableValue, Number oldValue, Number newValue) {
|
||||
log.trace("progressProperty newValue = " + newValue);
|
||||
}
|
||||
});
|
||||
|
||||
log.info("Checking for updates!");
|
||||
updater.setOnSucceeded(event -> {
|
||||
try {
|
||||
UpdateSummary summary = updater.get();
|
||||
if (summary.descriptions.size() > 0) {
|
||||
log.info("One liner: {}", summary.descriptions.get(0).getOneLiner());
|
||||
log.info("{}", summary.descriptions.get(0).getDescription());
|
||||
}
|
||||
if (summary.highestVersion > VERSION) {
|
||||
state.set(State.UPDATE_AVAILABLE);
|
||||
}
|
||||
else if (summary.highestVersion == VERSION) {
|
||||
state.set(State.UP_TO_DATE);
|
||||
timeoutTimer.stop();
|
||||
process.onCompleted();
|
||||
}
|
||||
|
||||
/* if (summary.highestVersion > VERSION) {
|
||||
log.info("Restarting to get version " + summary.highestVersion);
|
||||
if (UpdateFX.getVersionPin(dataDirPath) == 0)
|
||||
UpdateFX.restartApp();
|
||||
}*/
|
||||
} catch (Throwable e) {
|
||||
log.error("Exception at processing UpdateSummary: " + e.getMessage());
|
||||
|
||||
// we treat errors as update not as critical errors to prevent startup,
|
||||
// so we use state.onCompleted() instead of state.onError()
|
||||
errorMessage = "Exception at processing UpdateSummary: " + e.getMessage();
|
||||
state.set(State.FAILURE);
|
||||
timeoutTimer.stop();
|
||||
process.onCompleted();
|
||||
}
|
||||
});
|
||||
updater.setOnFailed(event -> {
|
||||
log.error("Update failed: " + updater.getException());
|
||||
updater.getException().printStackTrace();
|
||||
|
||||
// we treat errors as update not as critical errors to prevent startup,
|
||||
// so we use state.onCompleted() instead of state.onError()
|
||||
errorMessage = "Update failed: " + updater.getException();
|
||||
state.set(State.FAILURE);
|
||||
timeoutTimer.stop();
|
||||
process.onCompleted();
|
||||
});
|
||||
|
||||
Thread thread = new Thread(updater, "Online update check");
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
}
|
|
@ -152,7 +152,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
|||
|
||||
root.getChildren().addAll(baseApplicationContainer, splashScreen);
|
||||
|
||||
model.isReadyForMainScreen.addListener((ov, oldValue, newValue) -> {
|
||||
model.showAppScreen.addListener((ov, oldValue, newValue) -> {
|
||||
if (newValue) {
|
||||
bankAccountComboBoxHolder.getChildren().setAll(createBankAccountComboBox());
|
||||
|
||||
|
@ -184,15 +184,13 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
|||
Pane notification = new Pane();
|
||||
notification.relocate(30, 9);
|
||||
notification.setMouseTransparent(true);
|
||||
notification.setVisible(model.numPendingTrades.get() > 0);
|
||||
notification.setEffect(new DropShadow(4, 1, 2, Color.GREY));
|
||||
notification.getChildren().addAll(icon, numPendingTradesLabel);
|
||||
notification.visibleProperty().bind(model.showPendingTradesNotification);
|
||||
portfolioButtonHolder.getChildren().add(notification);
|
||||
|
||||
model.numPendingTrades.addListener((ov, oldValue, newValue) -> {
|
||||
notification.setVisible((int) newValue > 0);
|
||||
|
||||
if ((int) newValue > 0)
|
||||
model.showPendingTradesNotification.addListener((ov, oldValue, newValue) -> {
|
||||
if (newValue)
|
||||
SystemNotification.openInfoNotification(title, "You got a new trade message.");
|
||||
});
|
||||
}
|
||||
|
@ -200,17 +198,17 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
|||
private VBox createSplashScreen() {
|
||||
VBox vBox = new VBox();
|
||||
vBox.setAlignment(Pos.CENTER);
|
||||
vBox.setSpacing(10);
|
||||
vBox.setSpacing(0);
|
||||
vBox.setId("splash");
|
||||
|
||||
ImageView logo = new ImageView();
|
||||
logo.setId("image-splash-logo");
|
||||
|
||||
Label blockchainSyncLabel = new Label();
|
||||
blockchainSyncLabel.textProperty().bind(model.blockchainSyncState);
|
||||
blockchainSyncLabel.textProperty().bind(model.blockchainSyncInfo);
|
||||
model.walletServiceErrorMsg.addListener((ov, oldValue, newValue) -> {
|
||||
blockchainSyncLabel.setId("splash-error-state-msg");
|
||||
Popups.openErrorPopup("Error", "An error occurred at startup. \n\nError message:\n" +
|
||||
Popups.openErrorPopup("Error", "Connecting to the bitcoin network failed. \n\nReason: " +
|
||||
newValue);
|
||||
});
|
||||
|
||||
|
@ -238,7 +236,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
|||
HBox blockchainSyncBox = new HBox();
|
||||
blockchainSyncBox.setSpacing(10);
|
||||
blockchainSyncBox.setAlignment(Pos.CENTER);
|
||||
blockchainSyncBox.setPadding(new Insets(60, 0, 0, 0));
|
||||
blockchainSyncBox.setPadding(new Insets(40, 0, 0, 0));
|
||||
blockchainSyncBox.setPrefHeight(50);
|
||||
blockchainSyncBox.getChildren().addAll(blockchainSyncLabel, blockchainSyncIndicator,
|
||||
blockchainSyncIcon, bitcoinNetworkLabel);
|
||||
|
@ -247,20 +245,18 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
|||
bootstrapStateLabel.setWrapText(true);
|
||||
bootstrapStateLabel.setMaxWidth(500);
|
||||
bootstrapStateLabel.setTextAlignment(TextAlignment.CENTER);
|
||||
bootstrapStateLabel.textProperty().bind(model.bootstrapStateText);
|
||||
bootstrapStateLabel.textProperty().bind(model.bootstrapInfo);
|
||||
|
||||
ProgressIndicator bootstrapIndicator = new ProgressIndicator();
|
||||
bootstrapIndicator.setMaxSize(24, 24);
|
||||
bootstrapIndicator.progressProperty().bind(model.bootstrapProgress);
|
||||
|
||||
model.bootstrapFailed.addListener((ov, oldValue, newValue) -> {
|
||||
if (newValue) {
|
||||
bootstrapStateLabel.setId("splash-error-state-msg");
|
||||
bootstrapIndicator.setVisible(false);
|
||||
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());
|
||||
}
|
||||
Popups.openErrorPopup("Error", "Connecting to the Bitsquare network failed. \n\nReason: " +
|
||||
model.bootstrapErrorMsg.get());
|
||||
});
|
||||
|
||||
ImageView bootstrapIcon = new ImageView();
|
||||
|
@ -279,11 +275,35 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
|||
HBox bootstrapBox = new HBox();
|
||||
bootstrapBox.setSpacing(10);
|
||||
bootstrapBox.setAlignment(Pos.CENTER);
|
||||
bootstrapBox.setPadding(new Insets(10, 0, 0, 0));
|
||||
bootstrapBox.setPrefHeight(50);
|
||||
bootstrapBox.getChildren().addAll(bootstrapStateLabel, bootstrapIndicator, bootstrapIcon);
|
||||
|
||||
vBox.getChildren().addAll(logo, blockchainSyncBox, bootstrapBox);
|
||||
// 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, blockchainSyncBox, bootstrapBox, updateBox);
|
||||
return vBox;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,13 +18,13 @@
|
|||
package io.bitsquare.gui.main;
|
||||
|
||||
import io.bitsquare.account.AccountSettings;
|
||||
import io.bitsquare.app.gui.UpdateProcess;
|
||||
import io.bitsquare.arbitrator.Arbitrator;
|
||||
import io.bitsquare.arbitrator.Reputation;
|
||||
import io.bitsquare.bank.BankAccount;
|
||||
import io.bitsquare.bank.BankAccountType;
|
||||
import io.bitsquare.btc.BitcoinNetwork;
|
||||
import io.bitsquare.btc.WalletService;
|
||||
import io.bitsquare.gui.components.Popups;
|
||||
import io.bitsquare.gui.util.BSFormatter;
|
||||
import io.bitsquare.locale.CountryUtil;
|
||||
import io.bitsquare.locale.LanguageUtil;
|
||||
|
@ -35,7 +35,6 @@ import io.bitsquare.trade.Trade;
|
|||
import io.bitsquare.trade.TradeManager;
|
||||
import io.bitsquare.user.User;
|
||||
import io.bitsquare.util.DSAKeyUtil;
|
||||
import io.bitsquare.util.Utilities;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.ECKey;
|
||||
|
@ -47,18 +46,16 @@ import java.util.ArrayList;
|
|||
import java.util.Currency;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import viewfx.model.ViewModel;
|
||||
|
||||
import javafx.animation.AnimationTimer;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.DoubleProperty;
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleDoubleProperty;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
|
@ -75,106 +72,63 @@ import rx.Observable;
|
|||
class MainViewModel implements ViewModel {
|
||||
private static final Logger log = LoggerFactory.getLogger(MainViewModel.class);
|
||||
|
||||
final DoubleProperty networkSyncProgress = new SimpleDoubleProperty(-1);
|
||||
final IntegerProperty numPendingTrades = new SimpleIntegerProperty(0);
|
||||
final StringProperty numPendingTradesAsString = new SimpleStringProperty();
|
||||
final ObjectProperty<BootstrapState> bootstrapState = new SimpleObjectProperty<>();
|
||||
final StringProperty bootstrapStateText = new SimpleStringProperty();
|
||||
final ObjectProperty walletServiceException = new SimpleObjectProperty<Throwable>();
|
||||
|
||||
final StringProperty bankAccountsComboBoxPrompt = new SimpleStringProperty();
|
||||
final BooleanProperty bankAccountsComboBoxDisable = new SimpleBooleanProperty();
|
||||
|
||||
final StringProperty blockchainSyncState = new SimpleStringProperty("Initializing");
|
||||
// BTC network
|
||||
final StringProperty blockchainSyncInfo = new SimpleStringProperty("Initializing");
|
||||
final DoubleProperty blockchainSyncProgress = new SimpleDoubleProperty(-1);
|
||||
final BooleanProperty blockchainSyncIndicatorVisible = new SimpleBooleanProperty(true);
|
||||
final StringProperty blockchainSyncIconId = new SimpleStringProperty();
|
||||
final StringProperty walletServiceErrorMsg = new SimpleStringProperty();
|
||||
final BooleanProperty isReadyForMainScreen = new SimpleBooleanProperty();
|
||||
final StringProperty blockchainSyncIconId = new SimpleStringProperty();
|
||||
|
||||
// P2P network
|
||||
final StringProperty bootstrapInfo = new SimpleStringProperty();
|
||||
final DoubleProperty bootstrapProgress = new SimpleDoubleProperty(-1);
|
||||
final BooleanProperty bootstrapFailed = new SimpleBooleanProperty();
|
||||
final StringProperty bootstrapErrorMsg = new SimpleStringProperty();
|
||||
final StringProperty bootstrapIconId = new SimpleStringProperty();
|
||||
|
||||
final StringProperty featureNotImplementedWarning = new SimpleStringProperty();
|
||||
// software update
|
||||
final StringProperty updateInfo = new SimpleStringProperty();
|
||||
final BooleanProperty showRestartButton = new SimpleBooleanProperty(false);
|
||||
final StringProperty updateIconId = new SimpleStringProperty();
|
||||
|
||||
final StringProperty bankAccountsComboBoxPrompt = new SimpleStringProperty();
|
||||
final BooleanProperty bankAccountsComboBoxDisable = new SimpleBooleanProperty();
|
||||
final ObjectProperty<BankAccount> currentBankAccount = new SimpleObjectProperty<>();
|
||||
|
||||
final BooleanProperty showAppScreen = new SimpleBooleanProperty();
|
||||
final StringProperty featureNotImplementedWarning = new SimpleStringProperty();
|
||||
final StringProperty numPendingTradesAsString = new SimpleStringProperty();
|
||||
final BooleanProperty showPendingTradesNotification = new SimpleBooleanProperty();
|
||||
|
||||
final String bitcoinNetworkAsString;
|
||||
|
||||
private final User user;
|
||||
private final WalletService walletService;
|
||||
private final MessageService messageService;
|
||||
private final TradeManager tradeManager;
|
||||
private UpdateProcess updateProcess;
|
||||
private final BSFormatter formatter;
|
||||
private Persistence persistence;
|
||||
private AccountSettings accountSettings;
|
||||
private AnimationTimer bitcoinNetworkTimeout;
|
||||
|
||||
@Inject
|
||||
public MainViewModel(User user, WalletService walletService, MessageService messageService,
|
||||
TradeManager tradeManager, BitcoinNetwork bitcoinNetwork, BSFormatter formatter,
|
||||
Persistence persistence, AccountSettings accountSettings) {
|
||||
TradeManager tradeManager, BitcoinNetwork bitcoinNetwork, UpdateProcess updateProcess,
|
||||
BSFormatter formatter, Persistence persistence, AccountSettings accountSettings) {
|
||||
this.user = user;
|
||||
this.walletService = walletService;
|
||||
this.messageService = messageService;
|
||||
this.tradeManager = tradeManager;
|
||||
this.updateProcess = updateProcess;
|
||||
this.formatter = formatter;
|
||||
this.persistence = persistence;
|
||||
this.accountSettings = accountSettings;
|
||||
|
||||
bitcoinNetworkAsString = bitcoinNetwork.toString();
|
||||
|
||||
updateProcess.state.addListener((observableValue, oldValue, newValue) -> applyUpdateState(newValue));
|
||||
applyUpdateState(updateProcess.state.get());
|
||||
|
||||
user.getCurrentBankAccount().addListener((observable, oldValue, newValue) -> persistence.write(user));
|
||||
|
||||
currentBankAccount.bind(user.currentBankAccountProperty());
|
||||
|
||||
bootstrapState.addListener((ov, oldValue, newValue) -> {
|
||||
if (newValue == BootstrapState.DISCOVERY_DIRECT_SUCCEEDED ||
|
||||
newValue == BootstrapState.DISCOVERY_MANUAL_PORT_FORWARDING_SUCCEEDED ||
|
||||
newValue == BootstrapState.DISCOVERY_AUTO_PORT_FORWARDING_SUCCEEDED ||
|
||||
newValue == BootstrapState.RELAY_SUCCEEDED) {
|
||||
bootstrapStateText.set("Successfully connected to P2P network: " + newValue.getMessage());
|
||||
bootstrapProgress.set(1);
|
||||
|
||||
if (newValue == BootstrapState.DISCOVERY_DIRECT_SUCCEEDED)
|
||||
bootstrapIconId.set("image-connection-direct");
|
||||
else if (newValue == BootstrapState.DISCOVERY_MANUAL_PORT_FORWARDING_SUCCEEDED ||
|
||||
newValue == BootstrapState.DISCOVERY_AUTO_PORT_FORWARDING_SUCCEEDED)
|
||||
bootstrapIconId.set("image-connection-nat");
|
||||
else if (newValue == BootstrapState.RELAY_SUCCEEDED)
|
||||
bootstrapIconId.set("image-connection-relay");
|
||||
}
|
||||
else if (newValue == BootstrapState.PEER_CREATION_FAILED ||
|
||||
newValue == BootstrapState.DISCOVERY_FAILED ||
|
||||
newValue == BootstrapState.DISCOVERY_AUTO_PORT_FORWARDING_FAILED ||
|
||||
newValue == BootstrapState.RELAY_FAILED) {
|
||||
|
||||
bootstrapErrorMsg.set(newValue.getMessage());
|
||||
bootstrapStateText.set("Connecting to the Bitsquare network failed.");
|
||||
bootstrapProgress.set(0);
|
||||
bootstrapFailed.set(true);
|
||||
}
|
||||
else {
|
||||
bootstrapStateText.set("Connecting to the Bitsquare network: " + newValue.getMessage());
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
walletServiceException.addListener((ov, oldValue, newValue) -> {
|
||||
blockchainSyncIndicatorVisible.set(false);
|
||||
blockchainSyncState.set("Startup failed.");
|
||||
walletServiceErrorMsg.set(((Throwable) newValue).getMessage());
|
||||
});
|
||||
|
||||
networkSyncProgress.addListener((ov, oldValue, newValue) -> {
|
||||
setNetworkSyncProgress((double) newValue);
|
||||
|
||||
if ((double) newValue >= 1)
|
||||
blockchainSyncIconId.set("image-connection-synced");
|
||||
});
|
||||
setNetworkSyncProgress(networkSyncProgress.get());
|
||||
|
||||
|
||||
user.getBankAccounts().addListener((ListChangeListener<BankAccount>) change -> {
|
||||
bankAccountsComboBoxDisable.set(change.getList().isEmpty());
|
||||
bankAccountsComboBoxPrompt.set(change.getList().isEmpty() ? "No accounts" : "");
|
||||
|
@ -182,57 +136,67 @@ class MainViewModel implements ViewModel {
|
|||
bankAccountsComboBoxDisable.set(user.getBankAccounts().isEmpty());
|
||||
bankAccountsComboBoxPrompt.set(user.getBankAccounts().isEmpty() ? "No accounts" : "");
|
||||
|
||||
|
||||
tradeManager.featureNotImplementedWarningProperty().addListener((ov, oldValue, newValue) -> {
|
||||
if (oldValue == null && newValue != null) {
|
||||
featureNotImplementedWarning.set(newValue);
|
||||
Popups.openWarningPopup(newValue);
|
||||
tradeManager.setFeatureNotImplementedWarning(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void initBackend() {
|
||||
bitcoinNetworkTimeout = Utilities.setTimeout(20000, animationTimer -> {
|
||||
Platform.runLater(() -> {
|
||||
networkSyncProgress.set(0);
|
||||
blockchainSyncState.set("Connecting to the bitcoin network failed.");
|
||||
Popups.openErrorPopup("Connecting to the bitcoin network failed",
|
||||
"Please check your network connection.\n\n" +
|
||||
"You must allow outgoing TCP connections to port 18333 for the bitcoin testnet.\n\n" +
|
||||
"See https://github.com/bitsquare/bitsquare/wiki for instructions.");
|
||||
});
|
||||
return null;
|
||||
});
|
||||
public void restart() {
|
||||
updateProcess.restart();
|
||||
}
|
||||
|
||||
public void initBackend() {
|
||||
setBitcoinNetworkSyncProgress(-1);
|
||||
walletService.getDownloadProgress().subscribe(
|
||||
percentage -> Platform.runLater(() -> {
|
||||
if (percentage > 0)
|
||||
networkSyncProgress.set(percentage / 100.0);
|
||||
setBitcoinNetworkSyncProgress(percentage / 100.0);
|
||||
}),
|
||||
error -> log.error(error.toString()),
|
||||
() -> Platform.runLater(() -> networkSyncProgress.set(1.0)));
|
||||
() -> Platform.runLater(() -> setBitcoinNetworkSyncProgress(1.0)));
|
||||
|
||||
Observable<BootstrapState> message = messageService.init();
|
||||
message.publish();
|
||||
message.subscribe(
|
||||
state -> Platform.runLater(() -> bootstrapState.set(state)),
|
||||
error -> log.error(error.toString()),
|
||||
state -> Platform.runLater(() -> setBootstrapState(state)),
|
||||
error -> Platform.runLater(() -> {
|
||||
log.error(error.toString());
|
||||
bootstrapErrorMsg.set(error.getMessage());
|
||||
bootstrapInfo.set("Connecting to the Bitsquare network failed.");
|
||||
bootstrapProgress.set(0);
|
||||
|
||||
}),
|
||||
() -> log.trace("message completed"));
|
||||
|
||||
Observable<Object> wallet = walletService.initialize(Platform::runLater);
|
||||
wallet.subscribe(
|
||||
next -> {
|
||||
log.trace("wallet next");
|
||||
},
|
||||
error -> Platform.runLater(() -> walletServiceException.set(error)),
|
||||
error -> Platform.runLater(() -> {
|
||||
log.trace("wallet error");
|
||||
setWalletServiceException(error);
|
||||
}),
|
||||
() -> {
|
||||
log.trace("wallet completed");
|
||||
bitcoinNetworkTimeout.stop();
|
||||
bitcoinNetworkTimeout = null;
|
||||
});
|
||||
|
||||
Observable<?> backend = Observable.merge(message, wallet);
|
||||
backend.subscribe(
|
||||
Observable<UpdateProcess.State> updateProcess = this.updateProcess.getProcess();
|
||||
updateProcess.subscribe(next -> {
|
||||
log.trace("updateProcess next");
|
||||
},
|
||||
error -> {
|
||||
log.trace("updateProcess error");
|
||||
},
|
||||
() -> {
|
||||
log.trace("updateProcess completed");
|
||||
});
|
||||
|
||||
Observable<?> backEnd = Observable.merge(message, wallet, updateProcess);
|
||||
backEnd.subscribe(
|
||||
next -> {
|
||||
},
|
||||
error -> log.error(error.toString()),
|
||||
|
@ -246,7 +210,7 @@ class MainViewModel implements ViewModel {
|
|||
tradeManager.getPendingTrades().addListener(
|
||||
(MapChangeListener<String, Trade>) change -> updateNumPendingTrades());
|
||||
updateNumPendingTrades();
|
||||
isReadyForMainScreen.set(true);
|
||||
showAppScreen.set(true);
|
||||
|
||||
// For alpha version
|
||||
// uses messageService, so don't call it before backend is ready
|
||||
|
@ -270,6 +234,77 @@ class MainViewModel implements ViewModel {
|
|||
}
|
||||
}
|
||||
|
||||
private void applyUpdateState(UpdateProcess.State state) {
|
||||
switch (state) {
|
||||
case CHECK_FOR_UPDATES:
|
||||
updateInfo.set("Checking for updates...");
|
||||
updateIconId.set("image-update-in-progress");
|
||||
break;
|
||||
case UPDATE_AVAILABLE:
|
||||
updateInfo.set("New update available. Please restart!");
|
||||
updateIconId.set("image-update-available");
|
||||
showRestartButton.set(true);
|
||||
break;
|
||||
case UP_TO_DATE:
|
||||
updateInfo.set("Software is up to date.");
|
||||
updateIconId.set("image-update-up-to-date");
|
||||
break;
|
||||
case FAILURE:
|
||||
updateInfo.set(updateProcess.getErrorMessage());
|
||||
updateIconId.set("image-update-failed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void setBootstrapState(BootstrapState state) {
|
||||
switch (state) {
|
||||
case DISCOVERY_DIRECT_SUCCEEDED:
|
||||
bootstrapIconId.set("image-connection-direct");
|
||||
break;
|
||||
case DISCOVERY_MANUAL_PORT_FORWARDING_SUCCEEDED:
|
||||
case DISCOVERY_AUTO_PORT_FORWARDING_SUCCEEDED:
|
||||
bootstrapIconId.set("image-connection-nat");
|
||||
break;
|
||||
case RELAY_SUCCEEDED:
|
||||
bootstrapIconId.set("image-connection-relay");
|
||||
break;
|
||||
default:
|
||||
bootstrapIconId.set(null);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case DISCOVERY_DIRECT_SUCCEEDED:
|
||||
case DISCOVERY_MANUAL_PORT_FORWARDING_SUCCEEDED:
|
||||
case DISCOVERY_AUTO_PORT_FORWARDING_SUCCEEDED:
|
||||
case RELAY_SUCCEEDED:
|
||||
bootstrapInfo.set("Successfully connected to P2P network: " + state.getMessage());
|
||||
bootstrapProgress.set(1);
|
||||
break;
|
||||
default:
|
||||
bootstrapInfo.set("Connecting to the Bitsquare network: " + state.getMessage());
|
||||
bootstrapProgress.set(-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void setWalletServiceException(Throwable error) {
|
||||
setBitcoinNetworkSyncProgress(0);
|
||||
blockchainSyncInfo.set("Connecting to the bitcoin network 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" +
|
||||
"See https://github.com/bitsquare/bitsquare/wiki for instructions.");
|
||||
}
|
||||
else if (error.getMessage() != null) {
|
||||
walletServiceErrorMsg.set(error.getMessage());
|
||||
}
|
||||
else {
|
||||
walletServiceErrorMsg.set(error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public StringConverter<BankAccount> getBankAccountsConverter() {
|
||||
return new StringConverter<BankAccount>() {
|
||||
@Override
|
||||
|
@ -293,21 +328,24 @@ class MainViewModel implements ViewModel {
|
|||
}
|
||||
|
||||
private void updateNumPendingTrades() {
|
||||
numPendingTrades.set(tradeManager.getPendingTrades().size());
|
||||
if (numPendingTrades.get() > 0)
|
||||
numPendingTradesAsString.set(String.valueOf(numPendingTrades.get()));
|
||||
int numPendingTrades = tradeManager.getPendingTrades().size();
|
||||
if (numPendingTrades > 0)
|
||||
numPendingTradesAsString.set(String.valueOf(numPendingTrades));
|
||||
showPendingTradesNotification.set(numPendingTrades > 0);
|
||||
}
|
||||
|
||||
private void setNetworkSyncProgress(double value) {
|
||||
private void setBitcoinNetworkSyncProgress(double value) {
|
||||
blockchainSyncProgress.set(value);
|
||||
if (value >= 1)
|
||||
blockchainSyncState.set("Blockchain synchronization complete.");
|
||||
else if (value > 0.0)
|
||||
blockchainSyncState.set("Synchronizing blockchain: " + formatter.formatToPercent(value));
|
||||
else
|
||||
blockchainSyncState.set("Connecting to the bitcoin network...");
|
||||
|
||||
blockchainSyncIndicatorVisible.set(value < 1);
|
||||
if (value >= 1) {
|
||||
blockchainSyncInfo.set("Blockchain synchronization complete.");
|
||||
blockchainSyncIconId.set("image-connection-synced");
|
||||
}
|
||||
else if (value > 0.0) {
|
||||
blockchainSyncInfo.set("Synchronizing blockchain: " + formatter.formatToPercent(value));
|
||||
}
|
||||
else {
|
||||
blockchainSyncInfo.set("Connecting to the bitcoin network...");
|
||||
}
|
||||
}
|
||||
|
||||
private void addMockArbitrator() {
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
<logger name="org.bitcoinj" level="INFO"/>
|
||||
<logger name="net.tomp2p" level="INFO"/>
|
||||
<logger name="com.vinumeris.updatefx" level="TRACE"/>
|
||||
|
||||
|
||||
<logger name="net.tomp2p.message.Encoder" level="WARN"/>
|
||||
|
|
Loading…
Add table
Reference in a new issue