Use BusyAnimation in Mainview, add several test animation runners

This commit is contained in:
Manfred Karrer 2016-06-27 13:45:36 +02:00
parent 0f00a8ef29
commit 2cf662d582
10 changed files with 521 additions and 26 deletions

View file

@ -0,0 +1,66 @@
package io.bitsquare.gui.components;
import ch.qos.logback.classic.Logger;
import io.bitsquare.common.Timer;
import io.bitsquare.common.UserThread;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import org.slf4j.LoggerFactory;
import java.util.concurrent.TimeUnit;
public class BusyAnimation extends Pane {
private static final Logger log = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(BusyAnimation.class);
private Timer timer;
private ImageView img1, img2;
private int incr;
private int rotation1, rotation2;
public BusyAnimation() {
setMinSize(24, 24);
setMaxSize(24, 24);
incr = 360 / 12;
img1 = new ImageView();
img1.setId("spinner");
img2 = new ImageView();
img2.setId("spinner");
sceneProperty().addListener((obs, oldVal, newVal) -> {
if (newVal == null) {
stop();
} else {
play();
}
});
getChildren().addAll(img1, img2);
sceneProperty().addListener((obs, oldVal, newVal) -> {
if (newVal == null)
stop();
else
play();
});
}
private void update() {
rotation1 += incr;
rotation2 -= incr;
img1.setRotate(rotation1);
img2.setRotate(rotation2);
}
public void play() {
stop();
timer = UserThread.runPeriodically(this::update, 100, TimeUnit.MILLISECONDS);
}
public void stop() {
if (timer != null) {
timer.stop();
timer = null;
}
}
}

View file

@ -1,4 +1,4 @@
package io.bitsquare.gui.components.indicator;
package io.bitsquare.gui.components.indicator.playground;
import javafx.application.Application;
import javafx.application.Platform;
@ -25,7 +25,7 @@ public class BitSquareProgressIndicator extends Application {
public void start(Stage stage) throws Exception {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(10);
Pane pane = new Pane();
for (int i = 0; i < 10; ++i) {
for (int i = 1; i < 2; ++i) {
Parent node = new Indicator(scheduler, 6.0, 1.0).getNode();
node.relocate(i * 50, 30);
pane.getChildren().add(node);
@ -42,7 +42,7 @@ public class BitSquareProgressIndicator extends Application {
stage.setScene(new Scene(pane));
stage.setOnCloseRequest(evt -> scheduler.shutdown());
stage.setMinWidth(500);
stage.setMinHeight(100);
stage.setMinHeight(200);
stage.show();
}

View file

@ -0,0 +1,139 @@
package io.bitsquare.gui.components.indicator.playground;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Group;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.stage.Stage;
import org.reactfx.EventStream;
import org.reactfx.EventStreams;
import java.time.Duration;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
public class BitSquareProgressIndicator2 extends Application {
private static final double FPS = 6.0;
private static final double cycleDurationSeconds = 1.0;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
EventStream<?> ticks = EventStreams.ticks(Duration.ofMillis((long) (1000 / FPS)), scheduler, Platform::runLater);
Pane pane = new Pane();
for (int i = 0; i < 10; ++i) {
Parent node = new Indicator2(ticks, (int) (FPS * cycleDurationSeconds)).getNode();
node.relocate(i * 50, 30);
pane.getChildren().add(node);
}
stage.setScene(new Scene(pane));
stage.setOnCloseRequest(evt -> scheduler.shutdown());
stage.setMinWidth(500);
stage.setMinHeight(100);
stage.show();
}
}
class Indicator2 {
private static final Color lColor = Color.rgb(0x66, 0x66, 0x66);
private static final Color rColor = Color.rgb(0x0f, 0x87, 0xc3);
private static final PathElement[] ELEMS = new PathElement[]{
new MoveTo(9.2362945, 19.934046),
new CubicCurveTo(-1.3360939, -0.28065, -1.9963146, -1.69366, -1.9796182, -2.95487),
new CubicCurveTo(-0.1152909, -1.41268, -0.5046634, -3.07081, -1.920768, -3.72287),
new CubicCurveTo(-1.4711631, -0.77284, -3.4574873, -0.11153, -4.69154031, -1.40244),
new CubicCurveTo(-1.30616123, -1.40422, -0.5308003, -4.1855799, 1.46313121, -4.4219799),
new CubicCurveTo(1.4290018, -0.25469, 3.1669517, -0.0875, 4.1676818, -1.36207),
new CubicCurveTo(0.9172241, -1.12206, 0.9594176, -2.63766, 1.0685793, -4.01259),
new CubicCurveTo(0.4020299, -1.95732999, 3.2823027, -2.72818999, 4.5638567, -1.15760999),
new CubicCurveTo(1.215789, 1.31824999, 0.738899, 3.90740999, -1.103778, 4.37267999),
new CubicCurveTo(-1.3972543, 0.40868, -3.0929979, 0.0413, -4.2208253, 1.16215),
new CubicCurveTo(-1.3524806, 1.26423, -1.3178578, 3.29187, -1.1086673, 4.9895199),
new CubicCurveTo(0.167826, 1.28946, 1.0091133, 2.5347, 2.3196964, 2.86608),
new CubicCurveTo(1.6253079, 0.53477, 3.4876372, 0.45004, 5.0294052, -0.30121),
new CubicCurveTo(1.335829, -0.81654, 1.666839, -2.49408, 1.717756, -3.9432),
new CubicCurveTo(0.08759, -1.1232899, 0.704887, -2.3061299, 1.871843, -2.5951699),
new CubicCurveTo(1.534558, -0.50726, 3.390804, 0.62784, 3.467269, 2.28631),
new CubicCurveTo(0.183147, 1.4285099, -0.949563, 2.9179999, -2.431156, 2.9383699),
new CubicCurveTo(-1.390597, 0.17337, -3.074035, 0.18128, -3.971365, 1.45069),
new CubicCurveTo(-0.99314, 1.271, -0.676157, 2.98683, -1.1715, 4.43018),
new CubicCurveTo(-0.518248, 1.11436, -1.909118, 1.63902, -3.0700005, 1.37803),
new ClosePath()
};
static {
for (int i = 1; i < ELEMS.length; ++i) {
ELEMS[i].setAbsolute(false);
}
}
private final Path left;
private final Path right;
private final Group g;
private final int steps;
private boolean fw = true;
private int step = 0;
Indicator2(EventStream<?> ticks, int ticksPerCycle) {
this.steps = ticksPerCycle;
left = new Path(ELEMS);
right = new Path(ELEMS);
right.setScaleX(-1);
right.setScaleY(-1);
right.setTranslateX(7.266);
right.setOpacity(0.0);
left.setStroke(null);
right.setStroke(null);
left.setFill(lColor);
right.setFill(rColor);
g = new Group(left, right);
ticks.conditionOnShowing(g).subscribe(tick -> step());
}
public Parent getNode() {
return g;
}
private void step() {
double lOpacity, rOpacity;
step += fw ? 1 : -1;
if (step == steps) {
fw = false;
lOpacity = 0.0;
rOpacity = 1.0;
} else if (step == 0) {
fw = true;
lOpacity = 1.0;
rOpacity = 0.0;
} else {
lOpacity = 1.0 * (steps - step) / steps;
rOpacity = 1.0 * step / steps;
}
left.setOpacity(lOpacity);
right.setOpacity(rOpacity);
}
}

View file

@ -0,0 +1,37 @@
package io.bitsquare.gui.components.indicator.playground;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
public class ProgressIndicatorRunner extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(10);
Pane pane = new Pane();
for (int i = 1; i < 2; ++i) {
ProgressIndicator node = new ProgressIndicator(-1);
node.setMaxSize(24, 24);
node.relocate(i * 50, 30);
pane.getChildren().add(node);
}
pane.setStyle("-fx-background-color: white");
final Scene scene = new Scene(pane);
stage.setScene(scene);
stage.setOnCloseRequest(evt -> scheduler.shutdown());
stage.setMinWidth(500);
stage.setMinHeight(500);
stage.show();
}
}

View file

@ -0,0 +1,151 @@
package io.bitsquare.gui.components.indicator.playground;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Group;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Arc;
import javafx.scene.shape.ArcType;
import javafx.stage.Stage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class RingAnimRunner extends Application {
private static final Logger log = LoggerFactory.getLogger(RingAnimRunner.class);
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(10);
Pane pane = new Pane();
for (int i = 1; i < 2; ++i) {
Parent node = new Animation(scheduler, 6.0, 1.0).getNode();
// ProgressIndicator node = new ProgressIndicator(-1);
// StaticProgressIndicator node = new StaticProgressIndicator(-1);
//node.setMinSize(324, 324);
node.relocate(i * 50, 30);
pane.getChildren().add(node);
}
/* for (int i = 0; i < 10; ++i) {
ProgressIndicator node = new ProgressIndicator(-1);
node.setMaxWidth(20);
node.setMaxHeight(20);
node.relocate(i * 50, 30);
pane.getChildren().add(node);
}*/
pane.setStyle("-fx-background-color: white");
final Scene scene = new Scene(pane);
scene.getStylesheets().setAll(
"/io/bitsquare/gui/bitsquare.css",
"/io/bitsquare/gui/images.css");
stage.setScene(scene);
stage.setOnCloseRequest(evt -> scheduler.shutdown());
stage.setMinWidth(500);
stage.setMinHeight(500);
stage.show();
}
}
class Animation {
private final Group group;
private final ScheduledExecutorService scheduler;
private final long periodMs;
private final int steps;
private final Arc arc1, arc2;
private boolean fw;
private int step;
private int rotationStep;
private int speed;
private double opacity1, opacity2;
private ScheduledFuture<?> scheduled = null;
Animation(ScheduledExecutorService scheduler, double fps, double durationSeconds) {
this.scheduler = scheduler;
this.periodMs = (long) (1000 * durationSeconds / fps);
this.steps = (int) (fps * durationSeconds);
speed = (int) (360.0 / steps);
double x = 30;
double y = 30;
double radius1 = 11;
double radius2 = 8;
arc1 = new Arc(x, y, radius1, radius1, 0, 270);
arc1.setType(ArcType.OPEN);
arc1.setStroke(Color.rgb(0x66, 0x66, 0x66));
arc1.setFill(null);
arc1.setStrokeWidth(1);
arc2 = new Arc(x, y, radius2, radius2, 90, 270);
arc2.setType(ArcType.OPEN);
arc2.setStroke(Color.rgb(0x0f, 0x87, 0xc3));
arc2.setFill(null);
arc2.setStrokeWidth(1);
group = new Group(arc1, arc2);
group.sceneProperty().addListener((obs, oldVal, newVal) -> {
if (newVal == null) {
stop();
} else {
play();
}
});
}
public Parent getNode() {
return group;
}
private void step() {
rotationStep += speed;
step += fw ? 1 : -1;
if (step == steps) {
fw = false;
opacity1 = 0.0;
opacity2 = 1.0;
} else if (step == 0) {
fw = true;
opacity1 = 1.0;
opacity2 = 0.0;
} else {
opacity1 = 1.0 * (steps - step) / steps;
opacity2 = 1.0 * step / steps;
}
arc1.setOpacity(opacity1);
arc2.setOpacity(opacity2);
arc1.setRotate(rotationStep);
arc2.setRotate(rotationStep * -1);
}
private void play() {
stop();
fw = true;
step = 0;
rotationStep = 0;
scheduled = scheduler.scheduleAtFixedRate(() -> Platform.runLater(this::step), periodMs, periodMs, TimeUnit.MILLISECONDS);
}
private void stop() {
if (scheduled != null) {
scheduled.cancel(false);
scheduled = null;
}
}
}

View file

@ -0,0 +1,100 @@
package io.bitsquare.gui.components.indicator.playground;
import ch.qos.logback.classic.Logger;
import io.bitsquare.common.Timer;
import io.bitsquare.common.UserThread;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import org.slf4j.LoggerFactory;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class Spinner1Runner extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Pane pane = new Pane();
for (int i = 1; i < 2; ++i) {
Parent node = new Spinner1(scheduler).getNode();
node.relocate(i * 50, 30);
pane.getChildren().add(node);
}
pane.setStyle("-fx-background-color: white");
final Scene scene = new Scene(pane);
scene.getStylesheets().setAll(
"/io/bitsquare/gui/bitsquare.css",
"/io/bitsquare/gui/images.css");
stage.setScene(scene);
stage.setOnCloseRequest(evt -> scheduler.shutdown());
stage.setMinWidth(500);
stage.setMinHeight(500);
stage.show();
}
}
class Spinner1 {
private static final Logger log = (Logger) LoggerFactory.getLogger(Spinner1.class);
private final Group group;
private double rotation1, rotation2;
private double speed1, speed2;
private ImageView img1, img2;
private ScheduledFuture<?> scheduled = null;
private Timer timer;
Spinner1(ScheduledExecutorService scheduler) {
speed1 = 360 / 12;
speed2 = 360 / 12;
img1 = new ImageView();
img1.setId("spinner");
img2 = new ImageView();
img2.setId("spinner");
group = new Group(img1, img2);
group.sceneProperty().addListener((obs, oldVal, newVal) -> {
if (newVal == null) {
stop();
} else {
play();
}
});
}
public Parent getNode() {
return group;
}
private void update() {
rotation1 += speed1;
rotation2 -= speed2;
img1.setRotate(rotation1);
img2.setRotate(rotation2);
}
private void play() {
stop();
timer = UserThread.runPeriodically(this::update, 100, TimeUnit.MILLISECONDS);
}
private void stop() {
if (timer != null) {
timer.stop();
timer = null;
}
}
}

View file

@ -294,5 +294,9 @@
-fx-image: url("../../../images/btcaverage.png");
}
#spinner {
-fx-image: url("../../../images/spinner.png");
}

View file

@ -27,7 +27,7 @@ import io.bitsquare.common.util.Tuple3;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.common.view.*;
import io.bitsquare.gui.components.indicator.StaticProgressIndicator;
import io.bitsquare.gui.components.BusyAnimation;
import io.bitsquare.gui.main.account.AccountView;
import io.bitsquare.gui.main.disputes.DisputesView;
import io.bitsquare.gui.main.funds.FundsView;
@ -98,8 +98,8 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
private ChangeListener<String> btcSyncIconIdListener;
private ChangeListener<String> splashP2PNetworkErrorMsgListener;
private ChangeListener<String> splashP2PNetworkIconIdListener;
private ChangeListener<Number> splashP2PNetworkProgressListener;
private StaticProgressIndicator splashP2PNetworkIndicator;
private ChangeListener<Boolean> splashP2PNetworkVisibleListener;
private BusyAnimation splashP2PNetworkBusyAnimation;
private Label splashP2PNetworkLabel;
private ProgressBar btcSyncIndicator;
private Label btcSplashInfo;
@ -339,7 +339,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
HBox hBox2 = new HBox();
hBox2.getChildren().setAll(label, spacer, btcAverageIconButton, poloniexIconButton);
VBox vBox = new VBox();
vBox.setSpacing(3);
vBox.setPadding(new Insets(11, 0, 0, 0));
@ -403,15 +403,16 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
splashP2PNetworkLabel.setTextAlignment(TextAlignment.CENTER);
splashP2PNetworkLabel.textProperty().bind(model.p2PNetworkInfo);
splashP2PNetworkIndicator = new StaticProgressIndicator();
splashP2PNetworkIndicator.setPrefSize(24, 24);
splashP2PNetworkIndicator.progressProperty().bind(model.splashP2PNetworkProgress);
splashP2PNetworkBusyAnimation = new BusyAnimation();
splashP2PNetworkBusyAnimation.setPrefSize(24, 24);
splashP2PNetworkErrorMsgListener = (ov, oldValue, newValue) -> {
if (newValue != null) {
if (newValue != null)
splashP2PNetworkLabel.setId("splash-error-state-msg");
splashP2PNetworkIndicator.setVisible(false);
}
splashP2PNetworkBusyAnimation.setVisible(newValue == null);
splashP2PNetworkBusyAnimation.setManaged(newValue == null);
};
model.p2pNetworkWarnMsg.addListener(splashP2PNetworkErrorMsgListener);
@ -429,19 +430,17 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
};
model.p2PNetworkIconId.addListener(splashP2PNetworkIconIdListener);
splashP2PNetworkProgressListener = (ov, oldValue, newValue) -> {
if ((double) newValue != -1) {
splashP2PNetworkIndicator.setVisible(false);
splashP2PNetworkIndicator.setManaged(false);
}
splashP2PNetworkVisibleListener = (ov, oldValue, newValue) -> {
splashP2PNetworkBusyAnimation.setVisible(newValue);
splashP2PNetworkBusyAnimation.setManaged(newValue);
};
model.splashP2PNetworkProgress.addListener(splashP2PNetworkProgressListener);
model.splashP2PNetworkVisible.addListener(splashP2PNetworkVisibleListener);
HBox splashP2PNetworkBox = new HBox();
splashP2PNetworkBox.setSpacing(10);
splashP2PNetworkBox.setAlignment(Pos.CENTER);
splashP2PNetworkBox.setPrefHeight(50);
splashP2PNetworkBox.getChildren().addAll(splashP2PNetworkLabel, splashP2PNetworkIndicator, splashP2PNetworkIcon);
splashP2PNetworkBox.getChildren().addAll(splashP2PNetworkLabel, splashP2PNetworkBusyAnimation, splashP2PNetworkIcon);
vBox.getChildren().addAll(logo, blockchainSyncBox, splashP2PNetworkBox);
return vBox;
@ -453,13 +452,12 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
model.p2pNetworkWarnMsg.removeListener(splashP2PNetworkErrorMsgListener);
model.p2PNetworkIconId.removeListener(splashP2PNetworkIconIdListener);
model.splashP2PNetworkProgress.removeListener(splashP2PNetworkProgressListener);
model.splashP2PNetworkVisible.removeListener(splashP2PNetworkVisibleListener);
btcSplashInfo.textProperty().unbind();
btcSyncIndicator.progressProperty().unbind();
splashP2PNetworkLabel.textProperty().unbind();
splashP2PNetworkIndicator.progressProperty().unbind();
model.onSplashScreenRemoved();
}

View file

@ -130,7 +130,7 @@ public class MainViewModel implements ViewModel {
// P2P network
final StringProperty p2PNetworkInfo = new SimpleStringProperty();
private MonadicBinding<String> p2PNetworkInfoBinding;
final DoubleProperty splashP2PNetworkProgress = new SimpleDoubleProperty(DevFlags.STRESS_TEST_MODE ? 0 : -1);
final BooleanProperty splashP2PNetworkVisible = new SimpleBooleanProperty(true);
final StringProperty p2pNetworkWarnMsg = new SimpleStringProperty();
final StringProperty p2PNetworkIconId = new SimpleStringProperty();
final BooleanProperty bootstrapComplete = new SimpleBooleanProperty();
@ -381,7 +381,7 @@ public class MainViewModel implements ViewModel {
@Override
public void onBootstrapComplete() {
splashP2PNetworkProgress.set(1);
splashP2PNetworkVisible.set(false);
bootstrapComplete.set(true);
}
@ -390,7 +390,7 @@ public class MainViewModel implements ViewModel {
p2pNetworkWarnMsg.set("Connecting to the P2P network failed (reported error: "
+ throwable.getMessage() + ").\n" +
"Please check your internet connection or try to restart the application.");
splashP2PNetworkProgress.set(0);
splashP2PNetworkVisible.set(false);
bootstrapWarning.set("Bootstrapping to P2P network failed");
p2pNetworkLabelId.set("splash-error-state-msg");
}
@ -458,7 +458,7 @@ public class MainViewModel implements ViewModel {
if (walletService.getWallet().isEncrypted()) {
if (p2pNetWorkReady.get())
splashP2PNetworkProgress.set(0);
splashP2PNetworkVisible.set(false);
walletPasswordWindow
.onAesKey(aesKey -> {

Binary file not shown.

After

Width:  |  Height:  |  Size: 892 B