mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-06-28 08:37:16 -04: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";
|
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 USER_DATA_DIR_KEY = "user.data.dir";
|
||||||
|
|
||||||
public static final String DEFAULT_USER_DATA_DIR = defaultUserDataDir();
|
public static final String DEFAULT_USER_DATA_DIR = defaultUserDataDir();
|
||||||
|
|
||||||
public static final String APP_NAME_KEY = "app.name";
|
public static final String APP_NAME_KEY = "app.name";
|
||||||
|
|
|
@ -49,12 +49,17 @@ import javafx.scene.image.*;
|
||||||
import javafx.scene.input.*;
|
import javafx.scene.input.*;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.util.FileSystemUtils;
|
import org.springframework.util.FileSystemUtils;
|
||||||
|
|
||||||
import static io.bitsquare.app.BitsquareEnvironment.*;
|
import static io.bitsquare.app.BitsquareEnvironment.*;
|
||||||
|
|
||||||
public class BitsquareApp extends Application {
|
public class BitsquareApp extends Application {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(BitsquareAppMain.class);
|
||||||
|
|
||||||
private static Environment env;
|
private static Environment env;
|
||||||
|
|
||||||
private BitsquareAppModule bitsquareAppModule;
|
private BitsquareAppModule bitsquareAppModule;
|
||||||
|
@ -66,6 +71,9 @@ public class BitsquareApp extends Application {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage primaryStage) throws IOException {
|
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);
|
bitsquareAppModule = new BitsquareAppModule(env, primaryStage);
|
||||||
injector = Guice.createInjector(bitsquareAppModule);
|
injector = Guice.createInjector(bitsquareAppModule);
|
||||||
injector.getInstance(InjectorViewFactory.class).setInjector(injector);
|
injector.getInstance(InjectorViewFactory.class).setInjector(injector);
|
||||||
|
@ -139,7 +147,6 @@ public class BitsquareApp extends Application {
|
||||||
else
|
else
|
||||||
iconPath = "/images/task_bar_icon_linux.png";
|
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)));
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,12 @@ import io.bitsquare.network.BootstrapNodes;
|
||||||
import io.bitsquare.network.Node;
|
import io.bitsquare.network.Node;
|
||||||
import io.bitsquare.util.joptsimple.EnumValueConverter;
|
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.OptionParser;
|
||||||
import joptsimple.OptionSet;
|
import joptsimple.OptionSet;
|
||||||
|
|
||||||
|
@ -33,8 +39,17 @@ import static io.bitsquare.network.Node.*;
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
|
|
||||||
public class BitsquareAppMain extends BitsquareExecutable {
|
public class BitsquareAppMain extends BitsquareExecutable {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(BitsquareAppMain.class);
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
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);
|
new BitsquareAppMain().execute(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,11 @@ class BitsquareAppModule extends BitsquareModule {
|
||||||
bindConstant().annotatedWith(named(Persistence.PREFIX_KEY)).to(env.getRequiredProperty(Persistence.PREFIX_KEY));
|
bindConstant().annotatedWith(named(Persistence.PREFIX_KEY)).to(env.getRequiredProperty(Persistence.PREFIX_KEY));
|
||||||
bind(Persistence.class).asEagerSingleton();
|
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(messageModule());
|
||||||
install(bitcoinModule());
|
install(bitcoinModule());
|
||||||
install(cryptoModule());
|
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);
|
root.getChildren().addAll(baseApplicationContainer, splashScreen);
|
||||||
|
|
||||||
model.isReadyForMainScreen.addListener((ov, oldValue, newValue) -> {
|
model.showAppScreen.addListener((ov, oldValue, newValue) -> {
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
bankAccountComboBoxHolder.getChildren().setAll(createBankAccountComboBox());
|
bankAccountComboBoxHolder.getChildren().setAll(createBankAccountComboBox());
|
||||||
|
|
||||||
|
@ -184,15 +184,13 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
||||||
Pane notification = new Pane();
|
Pane notification = new Pane();
|
||||||
notification.relocate(30, 9);
|
notification.relocate(30, 9);
|
||||||
notification.setMouseTransparent(true);
|
notification.setMouseTransparent(true);
|
||||||
notification.setVisible(model.numPendingTrades.get() > 0);
|
|
||||||
notification.setEffect(new DropShadow(4, 1, 2, Color.GREY));
|
notification.setEffect(new DropShadow(4, 1, 2, Color.GREY));
|
||||||
notification.getChildren().addAll(icon, numPendingTradesLabel);
|
notification.getChildren().addAll(icon, numPendingTradesLabel);
|
||||||
|
notification.visibleProperty().bind(model.showPendingTradesNotification);
|
||||||
portfolioButtonHolder.getChildren().add(notification);
|
portfolioButtonHolder.getChildren().add(notification);
|
||||||
|
|
||||||
model.numPendingTrades.addListener((ov, oldValue, newValue) -> {
|
model.showPendingTradesNotification.addListener((ov, oldValue, newValue) -> {
|
||||||
notification.setVisible((int) newValue > 0);
|
if (newValue)
|
||||||
|
|
||||||
if ((int) newValue > 0)
|
|
||||||
SystemNotification.openInfoNotification(title, "You got a new trade message.");
|
SystemNotification.openInfoNotification(title, "You got a new trade message.");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -200,17 +198,17 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
||||||
private VBox createSplashScreen() {
|
private VBox createSplashScreen() {
|
||||||
VBox vBox = new VBox();
|
VBox vBox = new VBox();
|
||||||
vBox.setAlignment(Pos.CENTER);
|
vBox.setAlignment(Pos.CENTER);
|
||||||
vBox.setSpacing(10);
|
vBox.setSpacing(0);
|
||||||
vBox.setId("splash");
|
vBox.setId("splash");
|
||||||
|
|
||||||
ImageView logo = new ImageView();
|
ImageView logo = new ImageView();
|
||||||
logo.setId("image-splash-logo");
|
logo.setId("image-splash-logo");
|
||||||
|
|
||||||
Label blockchainSyncLabel = new Label();
|
Label blockchainSyncLabel = new Label();
|
||||||
blockchainSyncLabel.textProperty().bind(model.blockchainSyncState);
|
blockchainSyncLabel.textProperty().bind(model.blockchainSyncInfo);
|
||||||
model.walletServiceErrorMsg.addListener((ov, oldValue, newValue) -> {
|
model.walletServiceErrorMsg.addListener((ov, oldValue, newValue) -> {
|
||||||
blockchainSyncLabel.setId("splash-error-state-msg");
|
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);
|
newValue);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -238,7 +236,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
||||||
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(40, 0, 0, 0));
|
||||||
blockchainSyncBox.setPrefHeight(50);
|
blockchainSyncBox.setPrefHeight(50);
|
||||||
blockchainSyncBox.getChildren().addAll(blockchainSyncLabel, blockchainSyncIndicator,
|
blockchainSyncBox.getChildren().addAll(blockchainSyncLabel, blockchainSyncIndicator,
|
||||||
blockchainSyncIcon, bitcoinNetworkLabel);
|
blockchainSyncIcon, bitcoinNetworkLabel);
|
||||||
|
@ -247,20 +245,18 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
||||||
bootstrapStateLabel.setWrapText(true);
|
bootstrapStateLabel.setWrapText(true);
|
||||||
bootstrapStateLabel.setMaxWidth(500);
|
bootstrapStateLabel.setMaxWidth(500);
|
||||||
bootstrapStateLabel.setTextAlignment(TextAlignment.CENTER);
|
bootstrapStateLabel.setTextAlignment(TextAlignment.CENTER);
|
||||||
bootstrapStateLabel.textProperty().bind(model.bootstrapStateText);
|
bootstrapStateLabel.textProperty().bind(model.bootstrapInfo);
|
||||||
|
|
||||||
ProgressIndicator bootstrapIndicator = new ProgressIndicator();
|
ProgressIndicator bootstrapIndicator = new ProgressIndicator();
|
||||||
bootstrapIndicator.setMaxSize(24, 24);
|
bootstrapIndicator.setMaxSize(24, 24);
|
||||||
bootstrapIndicator.progressProperty().bind(model.bootstrapProgress);
|
bootstrapIndicator.progressProperty().bind(model.bootstrapProgress);
|
||||||
|
|
||||||
model.bootstrapFailed.addListener((ov, oldValue, newValue) -> {
|
model.bootstrapErrorMsg.addListener((ov, oldValue, newValue) -> {
|
||||||
if (newValue) {
|
|
||||||
bootstrapStateLabel.setId("splash-error-state-msg");
|
bootstrapStateLabel.setId("splash-error-state-msg");
|
||||||
bootstrapIndicator.setVisible(false);
|
bootstrapIndicator.setVisible(false);
|
||||||
|
|
||||||
Popups.openErrorPopup("Error", "Connecting to the Bitsquare network failed. \n\nReason: " +
|
Popups.openErrorPopup("Error", "Connecting to the Bitsquare network failed. \n\nReason: " +
|
||||||
model.bootstrapErrorMsg.get());
|
model.bootstrapErrorMsg.get());
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ImageView bootstrapIcon = new ImageView();
|
ImageView bootstrapIcon = new ImageView();
|
||||||
|
@ -279,11 +275,35 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
||||||
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.setPrefHeight(50);
|
bootstrapBox.setPrefHeight(50);
|
||||||
bootstrapBox.getChildren().addAll(bootstrapStateLabel, bootstrapIndicator, bootstrapIcon);
|
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;
|
return vBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,13 +18,13 @@
|
||||||
package io.bitsquare.gui.main;
|
package io.bitsquare.gui.main;
|
||||||
|
|
||||||
import io.bitsquare.account.AccountSettings;
|
import io.bitsquare.account.AccountSettings;
|
||||||
|
import io.bitsquare.app.gui.UpdateProcess;
|
||||||
import io.bitsquare.arbitrator.Arbitrator;
|
import io.bitsquare.arbitrator.Arbitrator;
|
||||||
import io.bitsquare.arbitrator.Reputation;
|
import io.bitsquare.arbitrator.Reputation;
|
||||||
import io.bitsquare.bank.BankAccount;
|
import io.bitsquare.bank.BankAccount;
|
||||||
import io.bitsquare.bank.BankAccountType;
|
import io.bitsquare.bank.BankAccountType;
|
||||||
import io.bitsquare.btc.BitcoinNetwork;
|
import io.bitsquare.btc.BitcoinNetwork;
|
||||||
import io.bitsquare.btc.WalletService;
|
import io.bitsquare.btc.WalletService;
|
||||||
import io.bitsquare.gui.components.Popups;
|
|
||||||
import io.bitsquare.gui.util.BSFormatter;
|
import io.bitsquare.gui.util.BSFormatter;
|
||||||
import io.bitsquare.locale.CountryUtil;
|
import io.bitsquare.locale.CountryUtil;
|
||||||
import io.bitsquare.locale.LanguageUtil;
|
import io.bitsquare.locale.LanguageUtil;
|
||||||
|
@ -35,7 +35,6 @@ import io.bitsquare.trade.Trade;
|
||||||
import io.bitsquare.trade.TradeManager;
|
import io.bitsquare.trade.TradeManager;
|
||||||
import io.bitsquare.user.User;
|
import io.bitsquare.user.User;
|
||||||
import io.bitsquare.util.DSAKeyUtil;
|
import io.bitsquare.util.DSAKeyUtil;
|
||||||
import io.bitsquare.util.Utilities;
|
|
||||||
|
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
import org.bitcoinj.core.ECKey;
|
import org.bitcoinj.core.ECKey;
|
||||||
|
@ -47,18 +46,16 @@ import java.util.ArrayList;
|
||||||
import java.util.Currency;
|
import java.util.Currency;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import viewfx.model.ViewModel;
|
import viewfx.model.ViewModel;
|
||||||
|
|
||||||
import javafx.animation.AnimationTimer;
|
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.property.BooleanProperty;
|
import javafx.beans.property.BooleanProperty;
|
||||||
import javafx.beans.property.DoubleProperty;
|
import javafx.beans.property.DoubleProperty;
|
||||||
import javafx.beans.property.IntegerProperty;
|
|
||||||
import javafx.beans.property.ObjectProperty;
|
import javafx.beans.property.ObjectProperty;
|
||||||
import javafx.beans.property.SimpleBooleanProperty;
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
import javafx.beans.property.SimpleDoubleProperty;
|
import javafx.beans.property.SimpleDoubleProperty;
|
||||||
import javafx.beans.property.SimpleIntegerProperty;
|
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
import javafx.beans.property.StringProperty;
|
import javafx.beans.property.StringProperty;
|
||||||
|
@ -75,106 +72,63 @@ import rx.Observable;
|
||||||
class MainViewModel implements ViewModel {
|
class MainViewModel implements ViewModel {
|
||||||
private static final Logger log = LoggerFactory.getLogger(MainViewModel.class);
|
private static final Logger log = LoggerFactory.getLogger(MainViewModel.class);
|
||||||
|
|
||||||
final DoubleProperty networkSyncProgress = new SimpleDoubleProperty(-1);
|
// BTC network
|
||||||
final IntegerProperty numPendingTrades = new SimpleIntegerProperty(0);
|
final StringProperty blockchainSyncInfo = new SimpleStringProperty("Initializing");
|
||||||
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");
|
|
||||||
final DoubleProperty blockchainSyncProgress = new SimpleDoubleProperty(-1);
|
final DoubleProperty blockchainSyncProgress = new SimpleDoubleProperty(-1);
|
||||||
final BooleanProperty blockchainSyncIndicatorVisible = new SimpleBooleanProperty(true);
|
|
||||||
final StringProperty blockchainSyncIconId = new SimpleStringProperty();
|
|
||||||
final StringProperty walletServiceErrorMsg = 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 DoubleProperty bootstrapProgress = new SimpleDoubleProperty(-1);
|
||||||
final BooleanProperty bootstrapFailed = new SimpleBooleanProperty();
|
|
||||||
final StringProperty bootstrapErrorMsg = new SimpleStringProperty();
|
final StringProperty bootstrapErrorMsg = new SimpleStringProperty();
|
||||||
final StringProperty bootstrapIconId = 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 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;
|
final String bitcoinNetworkAsString;
|
||||||
|
|
||||||
private final User user;
|
private final User user;
|
||||||
private final WalletService walletService;
|
private final WalletService walletService;
|
||||||
private final MessageService messageService;
|
private final MessageService messageService;
|
||||||
private final TradeManager tradeManager;
|
private final TradeManager tradeManager;
|
||||||
|
private UpdateProcess updateProcess;
|
||||||
private final BSFormatter formatter;
|
private final BSFormatter formatter;
|
||||||
private Persistence persistence;
|
private Persistence persistence;
|
||||||
private AccountSettings accountSettings;
|
private AccountSettings accountSettings;
|
||||||
private AnimationTimer bitcoinNetworkTimeout;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public MainViewModel(User user, WalletService walletService, MessageService messageService,
|
public MainViewModel(User user, WalletService walletService, MessageService messageService,
|
||||||
TradeManager tradeManager, BitcoinNetwork bitcoinNetwork, BSFormatter formatter,
|
TradeManager tradeManager, BitcoinNetwork bitcoinNetwork, UpdateProcess updateProcess,
|
||||||
Persistence persistence, AccountSettings accountSettings) {
|
BSFormatter formatter, Persistence persistence, AccountSettings accountSettings) {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.walletService = walletService;
|
this.walletService = walletService;
|
||||||
this.messageService = messageService;
|
this.messageService = messageService;
|
||||||
this.tradeManager = tradeManager;
|
this.tradeManager = tradeManager;
|
||||||
|
this.updateProcess = updateProcess;
|
||||||
this.formatter = formatter;
|
this.formatter = formatter;
|
||||||
this.persistence = persistence;
|
this.persistence = persistence;
|
||||||
this.accountSettings = accountSettings;
|
this.accountSettings = accountSettings;
|
||||||
|
|
||||||
bitcoinNetworkAsString = bitcoinNetwork.toString();
|
bitcoinNetworkAsString = bitcoinNetwork.toString();
|
||||||
|
|
||||||
|
updateProcess.state.addListener((observableValue, oldValue, newValue) -> applyUpdateState(newValue));
|
||||||
|
applyUpdateState(updateProcess.state.get());
|
||||||
|
|
||||||
user.getCurrentBankAccount().addListener((observable, oldValue, newValue) -> persistence.write(user));
|
user.getCurrentBankAccount().addListener((observable, oldValue, newValue) -> persistence.write(user));
|
||||||
|
|
||||||
currentBankAccount.bind(user.currentBankAccountProperty());
|
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 -> {
|
user.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" : "");
|
||||||
|
@ -182,57 +136,67 @@ class MainViewModel implements ViewModel {
|
||||||
bankAccountsComboBoxDisable.set(user.getBankAccounts().isEmpty());
|
bankAccountsComboBoxDisable.set(user.getBankAccounts().isEmpty());
|
||||||
bankAccountsComboBoxPrompt.set(user.getBankAccounts().isEmpty() ? "No accounts" : "");
|
bankAccountsComboBoxPrompt.set(user.getBankAccounts().isEmpty() ? "No accounts" : "");
|
||||||
|
|
||||||
|
|
||||||
tradeManager.featureNotImplementedWarningProperty().addListener((ov, oldValue, newValue) -> {
|
tradeManager.featureNotImplementedWarningProperty().addListener((ov, oldValue, newValue) -> {
|
||||||
if (oldValue == null && newValue != null) {
|
if (oldValue == null && newValue != null) {
|
||||||
featureNotImplementedWarning.set(newValue);
|
featureNotImplementedWarning.set(newValue);
|
||||||
Popups.openWarningPopup(newValue);
|
|
||||||
tradeManager.setFeatureNotImplementedWarning(null);
|
tradeManager.setFeatureNotImplementedWarning(null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initBackend() {
|
public void restart() {
|
||||||
bitcoinNetworkTimeout = Utilities.setTimeout(20000, animationTimer -> {
|
updateProcess.restart();
|
||||||
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 initBackend() {
|
||||||
|
setBitcoinNetworkSyncProgress(-1);
|
||||||
walletService.getDownloadProgress().subscribe(
|
walletService.getDownloadProgress().subscribe(
|
||||||
percentage -> Platform.runLater(() -> {
|
percentage -> Platform.runLater(() -> {
|
||||||
if (percentage > 0)
|
if (percentage > 0)
|
||||||
networkSyncProgress.set(percentage / 100.0);
|
setBitcoinNetworkSyncProgress(percentage / 100.0);
|
||||||
}),
|
}),
|
||||||
error -> log.error(error.toString()),
|
error -> log.error(error.toString()),
|
||||||
() -> Platform.runLater(() -> networkSyncProgress.set(1.0)));
|
() -> Platform.runLater(() -> setBitcoinNetworkSyncProgress(1.0)));
|
||||||
|
|
||||||
Observable<BootstrapState> message = messageService.init();
|
Observable<BootstrapState> message = messageService.init();
|
||||||
message.publish();
|
message.publish();
|
||||||
message.subscribe(
|
message.subscribe(
|
||||||
state -> Platform.runLater(() -> bootstrapState.set(state)),
|
state -> Platform.runLater(() -> setBootstrapState(state)),
|
||||||
error -> log.error(error.toString()),
|
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"));
|
() -> log.trace("message completed"));
|
||||||
|
|
||||||
Observable<Object> wallet = walletService.initialize(Platform::runLater);
|
Observable<Object> wallet = walletService.initialize(Platform::runLater);
|
||||||
wallet.subscribe(
|
wallet.subscribe(
|
||||||
next -> {
|
next -> {
|
||||||
|
log.trace("wallet next");
|
||||||
},
|
},
|
||||||
error -> Platform.runLater(() -> walletServiceException.set(error)),
|
error -> Platform.runLater(() -> {
|
||||||
|
log.trace("wallet error");
|
||||||
|
setWalletServiceException(error);
|
||||||
|
}),
|
||||||
() -> {
|
() -> {
|
||||||
log.trace("wallet completed");
|
log.trace("wallet completed");
|
||||||
bitcoinNetworkTimeout.stop();
|
|
||||||
bitcoinNetworkTimeout = null;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Observable<?> backend = Observable.merge(message, wallet);
|
Observable<UpdateProcess.State> updateProcess = this.updateProcess.getProcess();
|
||||||
backend.subscribe(
|
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 -> {
|
next -> {
|
||||||
},
|
},
|
||||||
error -> log.error(error.toString()),
|
error -> log.error(error.toString()),
|
||||||
|
@ -246,7 +210,7 @@ class MainViewModel implements ViewModel {
|
||||||
tradeManager.getPendingTrades().addListener(
|
tradeManager.getPendingTrades().addListener(
|
||||||
(MapChangeListener<String, Trade>) change -> updateNumPendingTrades());
|
(MapChangeListener<String, Trade>) change -> updateNumPendingTrades());
|
||||||
updateNumPendingTrades();
|
updateNumPendingTrades();
|
||||||
isReadyForMainScreen.set(true);
|
showAppScreen.set(true);
|
||||||
|
|
||||||
// For alpha version
|
// For alpha version
|
||||||
// uses messageService, so don't call it before backend is ready
|
// 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() {
|
public StringConverter<BankAccount> getBankAccountsConverter() {
|
||||||
return new StringConverter<BankAccount>() {
|
return new StringConverter<BankAccount>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -293,21 +328,24 @@ class MainViewModel implements ViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateNumPendingTrades() {
|
private void updateNumPendingTrades() {
|
||||||
numPendingTrades.set(tradeManager.getPendingTrades().size());
|
int numPendingTrades = tradeManager.getPendingTrades().size();
|
||||||
if (numPendingTrades.get() > 0)
|
if (numPendingTrades > 0)
|
||||||
numPendingTradesAsString.set(String.valueOf(numPendingTrades.get()));
|
numPendingTradesAsString.set(String.valueOf(numPendingTrades));
|
||||||
|
showPendingTradesNotification.set(numPendingTrades > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setNetworkSyncProgress(double value) {
|
private void setBitcoinNetworkSyncProgress(double value) {
|
||||||
blockchainSyncProgress.set(value);
|
blockchainSyncProgress.set(value);
|
||||||
if (value >= 1)
|
if (value >= 1) {
|
||||||
blockchainSyncState.set("Blockchain synchronization complete.");
|
blockchainSyncInfo.set("Blockchain synchronization complete.");
|
||||||
else if (value > 0.0)
|
blockchainSyncIconId.set("image-connection-synced");
|
||||||
blockchainSyncState.set("Synchronizing blockchain: " + formatter.formatToPercent(value));
|
}
|
||||||
else
|
else if (value > 0.0) {
|
||||||
blockchainSyncState.set("Connecting to the bitcoin network...");
|
blockchainSyncInfo.set("Synchronizing blockchain: " + formatter.formatToPercent(value));
|
||||||
|
}
|
||||||
blockchainSyncIndicatorVisible.set(value < 1);
|
else {
|
||||||
|
blockchainSyncInfo.set("Connecting to the bitcoin network...");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addMockArbitrator() {
|
private void addMockArbitrator() {
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
<logger name="org.bitcoinj" level="INFO"/>
|
<logger name="org.bitcoinj" level="INFO"/>
|
||||||
<logger name="net.tomp2p" level="INFO"/>
|
<logger name="net.tomp2p" level="INFO"/>
|
||||||
|
<logger name="com.vinumeris.updatefx" level="TRACE"/>
|
||||||
|
|
||||||
|
|
||||||
<logger name="net.tomp2p.message.Encoder" level="WARN"/>
|
<logger name="net.tomp2p.message.Encoder" level="WARN"/>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue