From 9ea6b2163e3d11c110086948451a842708efe5e4 Mon Sep 17 00:00:00 2001 From: battleofwizards Date: Tue, 17 Sep 2019 12:56:56 +0200 Subject: [PATCH 1/2] Remove reactfx dependency The reactfx was a 0.33MB dependency / 238 Java source files. We only used it for FxTimer helper and to measure FPS in development mode. The small FxTimer class got copied over into the project, so there is no change in semantics. The FPS measurement got replaced w/ com.sun.javafx.perf.PerformanceTracker, an internal but long stable part of JavaFx. This is probably not a problem, because it only concerns a rarely used, developer feature. --- build.gradle | 2 - .../java/bisq/common/reactfx/FxTimer.java | 104 ++++++++++++++++++ .../src/main/java/bisq/common/reactfx/LICENSE | 10 ++ .../main/java/bisq/common/reactfx/README.md | 6 + .../main/java/bisq/common/reactfx/Timer.java | 66 +++++++++++ .../main/java/bisq/desktop/app/BisqApp.java | 18 ++- .../java/bisq/desktop/common/UITimer.java | 5 +- gradle/witness/gradle-witness.gradle | 1 - 8 files changed, 196 insertions(+), 16 deletions(-) create mode 100644 common/src/main/java/bisq/common/reactfx/FxTimer.java create mode 100644 common/src/main/java/bisq/common/reactfx/LICENSE create mode 100644 common/src/main/java/bisq/common/reactfx/README.md create mode 100644 common/src/main/java/bisq/common/reactfx/Timer.java diff --git a/build.gradle b/build.gradle index ea1c0ea83dc..e9e8937a8a0 100644 --- a/build.gradle +++ b/build.gradle @@ -64,7 +64,6 @@ configure(subprojects) { protobufVersion = '3.9.1' pushyVersion = '0.13.2' qrgenVersion = '1.3' - reactfxVersion = '2.0-M3' sarxosVersion = '0.3.12' slf4jVersion = '1.7.22' sparkVersion = '2.5.2' @@ -290,7 +289,6 @@ configure(project(':desktop')) { dependencies { compile project(':core') compile "org.controlsfx:controlsfx:$controlsfxVersion" - compile "org.reactfx:reactfx:$reactfxVersion" compile "net.glxn:qrgen:$qrgenVersion" compile "de.jensd:fontawesomefx:$fontawesomefxVersion" compile "de.jensd:fontawesomefx-commons:$fontawesomefxCommonsVersion" diff --git a/common/src/main/java/bisq/common/reactfx/FxTimer.java b/common/src/main/java/bisq/common/reactfx/FxTimer.java new file mode 100644 index 00000000000..dfd4aabb786 --- /dev/null +++ b/common/src/main/java/bisq/common/reactfx/FxTimer.java @@ -0,0 +1,104 @@ +package bisq.common.reactfx; + +import javafx.animation.Animation; +import javafx.animation.KeyFrame; +import javafx.animation.Timeline; +import javafx.util.Duration; + +/** + * Provides factory methods for timers that are manipulated from and execute + * their action on the JavaFX application thread. + * + * Copied from: + * https://github.com/TomasMikula/ReactFX/blob/537fffdbb2958a77dfbca08b712bb2192862e960/reactfx/src/main/java/org/reactfx/util/FxTimer.java + * + */ +public class FxTimer implements Timer { + + /** + * Prepares a (stopped) timer that lasts for {@code delay} and whose action runs when timer ends. + */ + public static Timer create(java.time.Duration delay, Runnable action) { + return new FxTimer(delay, delay, action, 1); + } + + /** + * Equivalent to {@code create(delay, action).restart()}. + */ + public static Timer runLater(java.time.Duration delay, Runnable action) { + Timer timer = create(delay, action); + timer.restart(); + return timer; + } + + /** + * Prepares a (stopped) timer that lasts for {@code interval} and that executes the given action periodically + * when the timer ends. + */ + public static Timer createPeriodic(java.time.Duration interval, Runnable action) { + return new FxTimer(interval, interval, action, Animation.INDEFINITE); + } + + /** + * Equivalent to {@code createPeriodic(interval, action).restart()}. + */ + public static Timer runPeriodically(java.time.Duration interval, Runnable action) { + Timer timer = createPeriodic(interval, action); + timer.restart(); + return timer; + } + + /** + * Prepares a (stopped) timer that lasts for {@code interval} and that executes the given action periodically + * when the timer starts. + */ + public static Timer createPeriodic0(java.time.Duration interval, Runnable action) { + return new FxTimer(java.time.Duration.ZERO, interval, action, Animation.INDEFINITE); + } + + /** + * Equivalent to {@code createPeriodic0(interval, action).restart()}. + */ + public static Timer runPeriodically0(java.time.Duration interval, Runnable action) { + Timer timer = createPeriodic0(interval, action); + timer.restart(); + return timer; + } + + private final Duration actionTime; + private final Timeline timeline; + private final Runnable action; + + private long seq = 0; + + private FxTimer(java.time.Duration actionTime, java.time.Duration period, Runnable action, int cycles) { + this.actionTime = Duration.millis(actionTime.toMillis()); + this.timeline = new Timeline(); + this.action = action; + + timeline.getKeyFrames().add(new KeyFrame(this.actionTime)); // used as placeholder + if (period != actionTime) { + timeline.getKeyFrames().add(new KeyFrame(Duration.millis(period.toMillis()))); + } + + timeline.setCycleCount(cycles); + } + + @Override + public void restart() { + stop(); + long expected = seq; + timeline.getKeyFrames().set(0, new KeyFrame(actionTime, ae -> { + if(seq == expected) { + action.run(); + } + })); + timeline.play(); + } + + @Override + public void stop() { + timeline.stop(); + ++seq; + } +} diff --git a/common/src/main/java/bisq/common/reactfx/LICENSE b/common/src/main/java/bisq/common/reactfx/LICENSE new file mode 100644 index 00000000000..801693cd47e --- /dev/null +++ b/common/src/main/java/bisq/common/reactfx/LICENSE @@ -0,0 +1,10 @@ +Copyright (c) 2013-2014, Tomas Mikula +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/common/src/main/java/bisq/common/reactfx/README.md b/common/src/main/java/bisq/common/reactfx/README.md new file mode 100644 index 00000000000..965f0afbd9c --- /dev/null +++ b/common/src/main/java/bisq/common/reactfx/README.md @@ -0,0 +1,6 @@ +This package is a very minimal subset of the external library `org.reactfx`. + +Two small files from `org.reactfx` were embedded into the project +to avoid having it as dependency: + +[https://github.com/TomasMikula/ReactFX] diff --git a/common/src/main/java/bisq/common/reactfx/Timer.java b/common/src/main/java/bisq/common/reactfx/Timer.java new file mode 100644 index 00000000000..b7ae0a23eaa --- /dev/null +++ b/common/src/main/java/bisq/common/reactfx/Timer.java @@ -0,0 +1,66 @@ +package bisq.common.reactfx; + +/** + * Timer represents a delayed action. This means that every timer has an + * associated action and an associated delay. Action and delay are specified + * on timer creation. + * + *

Every timer also has an associated thread (such as JavaFX application + * thread or a single-thread executor's thread). Timer may only be accessed + * from its associated thread. Timer's action is executed on its associated + * thread, too. This design allows to implement guarantees provided by + * {@link #stop()}. + * + * Copied from: + * https://raw.githubusercontent.com/TomasMikula/ReactFX/537fffdbb2958a77dfbca08b712bb2192862e960/reactfx/src/main/java/org/reactfx/util/Timer.java* + */ +public interface Timer { + /** + * Schedules the associated action to be executed after the associated + * delay. If the action is already scheduled but hasn't been executed yet, + * the timeout is reset, so that the action won't be executed before the + * full delay from now. + */ + void restart(); + + /** + * If the associated action has been scheduled for execution but not yet + * executed, this method prevents it from being executed at all. This is + * also true in case the timer's timeout has already expired, but the + * associated action hasn't had a chance to be executed on the associated + * thread. Note that this is a stronger guarantee than the one given by + * {@link javafx.animation.Animation#stop()}: + * + *

+     * {@code
+     * Timeline timeline = new Timeline(new KeyFrame(
+     *         Duration.millis(1000),
+     *         ae -> System.out.println("FIRED ANYWAY")));
+     * timeline.play();
+     *
+     * // later on the JavaFX application thread,
+     * // but still before the action has been executed
+     * timeline.stop();
+     *
+     * // later, "FIRED ANYWAY" may still be printed
+     * }
+     * 
+ * + * In contrast, using the {@link FxTimer}, the action is guaranteed not to + * be executed after {@code stop()}: + *
+     * {@code
+     * Timer timer = FxTimer.runLater(
+     *         Duration.ofMillis(1000),
+     *         () -> System.out.println("FIRED"));
+     *
+     * // later on the JavaFX application thread,
+     * // but still before the action has been executed
+     * timer.stop();
+     *
+     * // "FIRED" is guaranteed *not* to be printed
+     * }
+     * 
+ */ + void stop(); +} diff --git a/desktop/src/main/java/bisq/desktop/app/BisqApp.java b/desktop/src/main/java/bisq/desktop/app/BisqApp.java index 640d34c848f..7dda9b2264d 100644 --- a/desktop/src/main/java/bisq/desktop/app/BisqApp.java +++ b/desktop/src/main/java/bisq/desktop/app/BisqApp.java @@ -57,8 +57,6 @@ import com.google.inject.Key; import com.google.inject.name.Names; -import org.reactfx.EventStreams; - import javafx.application.Application; import javafx.stage.Modality; @@ -80,6 +78,8 @@ import java.util.concurrent.TimeUnit; import java.util.function.Consumer; +import com.sun.javafx.perf.PerformanceTracker; + import org.slf4j.LoggerFactory; import ch.qos.logback.classic.Level; @@ -404,14 +404,12 @@ private void showDebugWindow(Scene scene, Injector injector) { private void showFPSWindow(Scene scene) { Label label = new AutoTooltipLabel(); - EventStreams.animationTicks() - .latestN(100) - .map(ticks -> { - int n = ticks.size() - 1; - return n * 1_000_000_000.0 / (ticks.get(n) - ticks.get(0)); - }) - .map(d -> String.format("FPS: %.3f", d)) // Don't translate, just for dev - .feedTo(label.textProperty()); + + PerformanceTracker performance = PerformanceTracker.getSceneTracker(scene); + UserThread.runPeriodically(() -> { + float fps = performance.getInstantPulses(); + label.setText(String.format("FPS: %.1f", fps)); + }, 1000, TimeUnit.MILLISECONDS); Pane root = new StackPane(); root.getChildren().add(label); diff --git a/desktop/src/main/java/bisq/desktop/common/UITimer.java b/desktop/src/main/java/bisq/desktop/common/UITimer.java index f1952bd12db..0d23f93ad84 100644 --- a/desktop/src/main/java/bisq/desktop/common/UITimer.java +++ b/desktop/src/main/java/bisq/desktop/common/UITimer.java @@ -18,8 +18,7 @@ package bisq.desktop.common; import bisq.common.Timer; - -import org.reactfx.util.FxTimer; +import bisq.common.reactfx.FxTimer; import java.time.Duration; @@ -28,7 +27,7 @@ public class UITimer implements Timer { private final Logger log = LoggerFactory.getLogger(UITimer.class); - private org.reactfx.util.Timer timer; + private bisq.common.reactfx.Timer timer; public UITimer() { } diff --git a/gradle/witness/gradle-witness.gradle b/gradle/witness/gradle-witness.gradle index 2d6c2c0d8e3..c41b682a4d4 100644 --- a/gradle/witness/gradle-witness.gradle +++ b/gradle/witness/gradle-witness.gradle @@ -15,7 +15,6 @@ dependencyVerification { verify = [ 'org.controlsfx:controlsfx:b98f1c9507c05600f80323674b33d15674926c71b0116f70085b62bdacf1e573', - 'org.reactfx:reactfx:81ec8fe545d65661222735711114c2ce427e2187a65f1722e8ac4e4805beeca3', 'net.glxn:qrgen:c85d9d8512d91e8ad11fe56259a7825bd50ce0245447e236cf168d1b17591882', 'de.jensd:fontawesomefx:73bacc991a0a6f5cf0f911767c8db161e0949dbca61e8371eb4342e3da96887b', 'de.jensd:fontawesomefx-materialdesignfont:dbad8dfdd1c85e298d5bbae25b2399aec9e85064db57b2427d10f3815aa98752', From 2290eb28750a6e89ae9abf447d13a5d0fab3c085 Mon Sep 17 00:00:00 2001 From: battleofwizards Date: Wed, 18 Sep 2019 09:32:37 +0200 Subject: [PATCH 2/2] Remove showing FPS rate in developer mode --- .../main/java/bisq/desktop/app/BisqApp.java | 35 +------------------ 1 file changed, 1 insertion(+), 34 deletions(-) diff --git a/desktop/src/main/java/bisq/desktop/app/BisqApp.java b/desktop/src/main/java/bisq/desktop/app/BisqApp.java index 7dda9b2264d..dc42230b4a6 100644 --- a/desktop/src/main/java/bisq/desktop/app/BisqApp.java +++ b/desktop/src/main/java/bisq/desktop/app/BisqApp.java @@ -20,7 +20,6 @@ import bisq.desktop.common.view.CachingViewLoader; import bisq.desktop.common.view.View; import bisq.desktop.common.view.ViewLoader; -import bisq.desktop.components.AutoTooltipLabel; import bisq.desktop.main.MainView; import bisq.desktop.main.debug.DebugView; import bisq.desktop.main.overlays.popups.Popup; @@ -65,11 +64,9 @@ import javafx.scene.Parent; import javafx.scene.Scene; -import javafx.scene.control.Label; import javafx.scene.image.Image; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; -import javafx.scene.layout.Pane; import javafx.scene.layout.StackPane; import java.awt.GraphicsEnvironment; @@ -78,8 +75,6 @@ import java.util.concurrent.TimeUnit; import java.util.function.Consumer; -import com.sun.javafx.perf.PerformanceTracker; - import org.slf4j.LoggerFactory; import ch.qos.logback.classic.Level; @@ -318,12 +313,8 @@ private void addSceneKeyEventHandler(Scene scene, Injector injector) { else new Popup<>().warning(Res.get("popup.warning.walletNotInitialized")).show(); } else if (DevEnv.isDevMode()) { - // dev ode only - if (Utilities.isAltOrCtrlPressed(KeyCode.P, keyEvent)) { - showFPSWindow(scene); - } else if (Utilities.isAltOrCtrlPressed(KeyCode.Z, keyEvent)) { + if (Utilities.isAltOrCtrlPressed(KeyCode.Z, keyEvent)) showDebugWindow(scene, injector); - } } } }); @@ -401,28 +392,4 @@ private void showDebugWindow(Scene scene, Injector injector) { stage.setY(this.stage.getY()); stage.show(); } - - private void showFPSWindow(Scene scene) { - Label label = new AutoTooltipLabel(); - - PerformanceTracker performance = PerformanceTracker.getSceneTracker(scene); - UserThread.runPeriodically(() -> { - float fps = performance.getInstantPulses(); - label.setText(String.format("FPS: %.1f", fps)); - }, 1000, TimeUnit.MILLISECONDS); - - Pane root = new StackPane(); - root.getChildren().add(label); - Stage stage = new Stage(); - stage.setScene(new Scene(root)); - stage.setTitle("FPS"); // Don't translate, just for dev - stage.initModality(Modality.NONE); - stage.initStyle(StageStyle.UTILITY); - stage.initOwner(scene.getWindow()); - stage.setX(this.stage.getX() + this.stage.getWidth() + 10); - stage.setY(this.stage.getY()); - stage.setWidth(200); - stage.setHeight(100); - stage.show(); - } }