Use custom Download indicator, fix problems with testnet

This commit is contained in:
Manfred Karrer 2014-10-08 00:30:44 +02:00
parent e2cdc517e4
commit 32d482eb22
15 changed files with 55 additions and 787 deletions

View File

@ -23,7 +23,6 @@ import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionConfidence;
import org.bitcoinj.core.TransactionOutput;
import org.bitcoinj.params.RegTestParams;
import org.bitcoinj.wallet.CoinSelection;
import org.bitcoinj.wallet.DefaultCoinSelector;
@ -105,10 +104,10 @@ class AddressBasedCoinSelector extends DefaultCoinSelector {
(confidence.numBroadcastPeers() > 1 || tx.getParams() == RegTestParams.get());*/
log.debug("numBroadcastPeers = " + confidence.numBroadcastPeers());
// TODO at testnet we got confidence.numBroadcastPeers()=1
// TODO at testnet we got confidence.numBroadcastPeers()=0 -> probably because we use chained unconfirmed tx
// investigate further
return type.equals(TransactionConfidence.ConfidenceType.BUILDING) ||
type.equals(TransactionConfidence.ConfidenceType.PENDING) &&
(confidence.numBroadcastPeers() > 0 || tx.getParams() == RegTestParams.get());
type.equals(TransactionConfidence.ConfidenceType.PENDING);
}
private static boolean isInBlockChain(Transaction tx) {

View File

@ -165,7 +165,7 @@ public class WalletFacade {
// Checkpoint files are made using the BuildCheckpoints tool and usually we have to download the
// last months worth or more (takes a few seconds).
try {
walletAppKit.setCheckpoints(getClass().getResourceAsStream("wallet/checkpoints"));
walletAppKit.setCheckpoints(getClass().getResourceAsStream("/wallet/checkpoints"));
} catch (Exception e) {
e.printStackTrace();
log.error(e.toString());
@ -174,7 +174,7 @@ public class WalletFacade {
// walletAppKit.useTor();
}
else if (params == TestNet3Params.get()) {
walletAppKit.setCheckpoints(getClass().getResourceAsStream("wallet/checkpoints.testnet"));
walletAppKit.setCheckpoints(getClass().getResourceAsStream("/wallet/checkpoints.testnet"));
//walletAppKit.useTor();
}
walletAppKit.setDownloadListener(downloadListener)

View File

@ -63,9 +63,10 @@ class MainModel extends UIModel {
private boolean messageFacadeInited;
private boolean walletFacadeInited;
final BooleanProperty backendInited = new SimpleBooleanProperty();
final DoubleProperty networkSyncProgress = new SimpleDoubleProperty();
final BooleanProperty backendReady = new SimpleBooleanProperty();
final DoubleProperty networkSyncProgress = new SimpleDoubleProperty(-1);
final IntegerProperty numPendingTrades = new SimpleIntegerProperty(0);
private boolean facadesInitialised;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
@ -117,7 +118,8 @@ class MainModel extends UIModel {
@Override
public void onCompleted() {
messageFacadeInited = true;
if (walletFacadeInited) onFacadesInitialised();
if (walletFacadeInited)
onFacadesInitialised();
}
@Override
@ -149,13 +151,23 @@ class MainModel extends UIModel {
@Override
protected void progress(double percent, int blocksLeft, Date date) {
super.progress(percent, blocksLeft, date);
Platform.runLater(() -> networkSyncProgress.set(percent / 100.0));
Platform.runLater(() -> {
networkSyncProgress.set(percent / 100.0);
if (facadesInitialised && percent >= 100.0)
backendReady.set(true);
});
}
@Override
protected void doneDownload() {
super.doneDownload();
Platform.runLater(() -> networkSyncProgress.set(1.0));
Platform.runLater(() -> {
networkSyncProgress.set(1.0);
if (facadesInitialised)
backendReady.set(true);
});
}
};
@ -199,7 +211,10 @@ class MainModel extends UIModel {
Trade>) change -> updateNumPendingTrades());
updateNumPendingTrades();
backendInited.set(true);
facadesInitialised = true;
if (networkSyncProgress.get() >= 1.0)
backendReady.set(true);
}
private void updateNumPendingTrades() {

View File

@ -44,7 +44,7 @@ class MainPM extends PresentationModel<MainModel> {
private BSFormatter formatter;
final BooleanProperty backendInited = new SimpleBooleanProperty();
final BooleanProperty backendReady = new SimpleBooleanProperty();
final StringProperty bankAccountsComboBoxPrompt = new SimpleStringProperty();
final BooleanProperty bankAccountsComboBoxDisable = new SimpleBooleanProperty();
final StringProperty splashScreenInfoText = new SimpleStringProperty();
@ -71,19 +71,20 @@ class MainPM extends PresentationModel<MainModel> {
public void initialize() {
super.initialize();
backendInited.bind(model.backendInited);
backendReady.bind(model.backendReady);
networkSyncProgress.bind(model.networkSyncProgress);
numPendingTrades.bind(model.numPendingTrades);
model.networkSyncProgress.addListener((ov, oldValue, newValue) -> {
if ((double) newValue > 0)
splashScreenInfoText.set("Synchronise with network " + formatter.formatToPercent((double) newValue));
if ((double) newValue > 0.0)
splashScreenInfoText.set("Synchronise with network " + formatter.formatToPercent((double)
newValue));
else if ((double) newValue == 1)
splashScreenInfoText.set("Synchronise with network completed.");
else
splashScreenInfoText.set("Synchronise with network...");
});
splashScreenInfoText.set("Synchronise with network...");
model.getBankAccounts().addListener((ListChangeListener<BankAccount>) change -> {
bankAccountsComboBoxDisable.set(change.getList().isEmpty());

View File

@ -22,7 +22,6 @@ import io.bitsquare.bank.BankAccount;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.OverlayManager;
import io.bitsquare.gui.ViewCB;
import io.bitsquare.gui.components.NetworkSyncPane;
import io.bitsquare.gui.components.Popups;
import io.bitsquare.gui.components.SystemNotification;
import io.bitsquare.gui.util.Profiler;
@ -39,6 +38,7 @@ import java.util.ResourceBundle;
import javax.inject.Inject;
import javafx.animation.Interpolator;
import javafx.application.Platform;
import javafx.fxml.Initializable;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
@ -52,8 +52,6 @@ import javafx.scene.paint.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import wallettemplate.controls.NotificationBarPane;
public class MainViewCB extends ViewCB<MainPM> {
private static final Logger log = LoggerFactory.getLogger(MainViewCB.class);
@ -63,15 +61,13 @@ public class MainViewCB extends ViewCB<MainPM> {
private final ToggleGroup navButtonsGroup = new ToggleGroup();
private BorderPane baseApplicationContainer;
private StackPane baseOverlayContainer;
private VBox splashScreen;
private AnchorPane contentContainer;
private HBox leftNavPane, rightNavPane;
private NetworkSyncPane networkSyncPane;
private ToggleButton buyButton, sellButton, homeButton, msgButton, ordersButton, fundsButton, settingsButton,
accountButton;
private Pane ordersButtonButtonPane;
private Label numPendingTradesLabel;
private NotificationBarPane notificationBarPane;
///////////////////////////////////////////////////////////////////////////////////////////
@ -169,41 +165,22 @@ public class MainViewCB extends ViewCB<MainPM> {
private void startup() {
baseApplicationContainer = getBaseApplicationContainer();
baseOverlayContainer = new StackPane();
splashScreen = getSplashScreen();
((StackPane) root).getChildren().addAll(baseApplicationContainer, splashScreen);
baseApplicationContainer.setCenter(getApplicationContainer());
// TODO remove dependency of NotificationBarPane with getSplashScreen (borderPane content)
notificationBarPane = new NotificationBarPane(getSplashScreen());
baseOverlayContainer.getChildren().add(notificationBarPane);
final NotificationBarPane.Item syncItem = notificationBarPane.pushItem("Synchronising with the Bitcoin network",
presentationModel.networkSyncProgress);
presentationModel.networkSyncProgress.addListener((ov, oldValue, newValue) -> {
if ((double) newValue >= 1.0) {
log.debug("### networkSyncProgress " + newValue);
syncItem.cancel();
onBaseContainersCreated();
}
});
((StackPane) root).getChildren().addAll(baseApplicationContainer, baseOverlayContainer);
Platform.runLater(() -> onSplashScreenAdded());
}
private void onBaseContainersCreated() {
Profiler.printMsgWithTime("MainController.onBaseContainersCreated");
AnchorPane applicationContainer = getApplicationContainer();
baseApplicationContainer.setCenter(applicationContainer);
presentationModel.backendInited.addListener((ov, oldValue, newValue) -> {
private void onSplashScreenAdded() {
presentationModel.backendReady.addListener((ov, oldValue, newValue) -> {
if (newValue)
onBackendInited();
onBackendReady();
});
presentationModel.initBackend();
}
private void onBackendInited() {
private void onBackendReady() {
Profiler.printMsgWithTime("MainController.onBackendInited");
addMainNavigation();
}
@ -255,7 +232,7 @@ public class MainViewCB extends ViewCB<MainPM> {
private void onContentAdded() {
Profiler.printMsgWithTime("MainController.onContentAdded");
Transitions.fadeOutAndRemove(baseOverlayContainer, 1500).setInterpolator(Interpolator.EASE_IN);
Transitions.fadeOutAndRemove(splashScreen, 1500).setInterpolator(Interpolator.EASE_IN);
}
@ -301,7 +278,7 @@ public class MainViewCB extends ViewCB<MainPM> {
return borderPane;
}
private BorderPane getSplashScreen() {
private VBox getSplashScreen() {
VBox vBox = new VBox();
vBox.setAlignment(Pos.CENTER);
vBox.setSpacing(10);
@ -319,10 +296,13 @@ public class MainViewCB extends ViewCB<MainPM> {
loadingLabel.setPadding(new Insets(80, 0, 0, 0));
loadingLabel.textProperty().bind(presentationModel.splashScreenInfoText);
vBox.getChildren().addAll(logo, subTitle, loadingLabel);
ProgressBar progressBar = new ProgressBar();
progressBar.setPrefWidth(200);
progressBar.progressProperty().bind(presentationModel.networkSyncProgress);
BorderPane borderPane = new BorderPane(vBox);
return borderPane;
vBox.getChildren().addAll(logo, subTitle, loadingLabel, progressBar);
return vBox;
}
private AnchorPane getApplicationContainer() {
@ -346,13 +326,7 @@ public class MainViewCB extends ViewCB<MainPM> {
AnchorPane.setTopAnchor(contentContainer, 60d);
AnchorPane.setBottomAnchor(contentContainer, 25d);
networkSyncPane = new NetworkSyncPane();
networkSyncPane.setSpacing(10);
networkSyncPane.setPrefHeight(20);
AnchorPane.setLeftAnchor(networkSyncPane, 0d);
AnchorPane.setBottomAnchor(networkSyncPane, 5d);
anchorPane.getChildren().addAll(leftNavPane, rightNavPane, contentContainer, networkSyncPane);
anchorPane.getChildren().addAll(leftNavPane, rightNavPane, contentContainer);
return anchorPane;
}

View File

@ -171,7 +171,7 @@ class TakeOfferModel extends UIModel {
requestTakeOfferErrorMessage.set("Take offer request got rejected.");
break;
default:
log.error("Unhandled trade state: " + newValue);
log.warn("Unhandled trade state: " + newValue);
break;
}
});

View File

@ -309,7 +309,7 @@ public class BSFormatter {
decimalFormat.setMinimumFractionDigits(1);
decimalFormat.setMaximumFractionDigits(1);
decimalFormat.setGroupingUsed(false);
return decimalFormat.format(value / 100) + " %";
return decimalFormat.format(value * 100.0) + " %";
}
private String cleanInput(String input) {

View File

@ -373,7 +373,7 @@ public class TradeManager {
// probably not needed
@Override
public void onWaitingForPeerResponse(SellerTakesOfferProtocol.State state) {
log.error("onWaitingForPeerResponse");
log.debug("onWaitingForPeerResponse");
}
};

View File

@ -1,142 +0,0 @@
package wallettemplate.controls;
import javax.annotation.Nullable;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableDoubleValue;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.util.Duration;
import wallettemplate.utils.GuiUtils;
import wallettemplate.utils.easing.EasingMode;
import wallettemplate.utils.easing.ElasticInterpolator;
/**
* Wraps the given Node in a BorderPane and allows a thin bar to slide in from the bottom or top, squeezing the content
* node. The API allows different "items" to be added/removed and they will be displayed one at a time, fading between
* them when the topmost is removed. Each item is meant to be used for e.g. a background task and can contain a button
* and/or a progress bar.
*/
public class NotificationBarPane extends BorderPane {
public static final Duration ANIM_IN_DURATION = GuiUtils.UI_ANIMATION_TIME.multiply(2);
public static final Duration ANIM_OUT_DURATION = GuiUtils.UI_ANIMATION_TIME;
private HBox bar;
private Label label;
private double barHeight;
private ProgressBar progressBar;
public class Item {
public final SimpleStringProperty label;
@Nullable public final ObservableDoubleValue progress;
public Item(String label, @Nullable ObservableDoubleValue progress) {
this.label = new SimpleStringProperty(label);
this.progress = progress;
}
public void cancel() {
items.remove(this);
}
}
public final ObservableList<Item> items;
public NotificationBarPane(Node content) {
super(content);
progressBar = new ProgressBar();
label = new Label("infobar!");
bar = new HBox(label);
bar.setMinHeight(0.0);
bar.getStyleClass().add("info-bar");
bar.setFillHeight(true);
setBottom(bar);
// Figure out the height of the bar based on the CSS. Must wait until after we've been added to the parent node.
sceneProperty().addListener(o -> {
if (getParent() == null) return;
getParent().applyCss();
getParent().layout();
barHeight = bar.getHeight();
bar.setPrefHeight(0.0);
});
items = FXCollections.observableArrayList();
items.addListener((ListChangeListener<? super Item>) change -> {
config();
showOrHide();
});
}
private void config() {
if (items.isEmpty()) return;
Item item = items.get(0);
bar.getChildren().clear();
label.textProperty().bind(item.label);
label.setMaxWidth(Double.MAX_VALUE);
HBox.setHgrow(label, Priority.ALWAYS);
bar.getChildren().add(label);
if (item.progress != null) {
progressBar.setMinWidth(200);
progressBar.progressProperty().bind(item.progress);
bar.getChildren().add(progressBar);
}
}
private void showOrHide() {
if (items.isEmpty())
animateOut();
else
animateIn();
}
public boolean isShowing() {
return bar.getPrefHeight() > 0;
}
private void animateIn() {
animate(barHeight);
}
private void animateOut() {
animate(0.0);
}
private Timeline timeline;
protected void animate(Number target) {
if (timeline != null) {
timeline.stop();
timeline = null;
}
Duration duration;
Interpolator interpolator;
if (target.intValue() > 0) {
interpolator = new ElasticInterpolator(EasingMode.EASE_OUT, 1, 2);
duration = ANIM_IN_DURATION;
}
else {
interpolator = Interpolator.EASE_OUT;
duration = ANIM_OUT_DURATION;
}
KeyFrame kf = new KeyFrame(duration, new KeyValue(bar.prefHeightProperty(), target, interpolator));
timeline = new Timeline(kf);
timeline.setOnFinished(x -> timeline = null);
timeline.play();
}
public Item pushItem(String string, @Nullable ObservableDoubleValue progress) {
Item i = new Item(string, progress);
items.add(i);
return i;
}
}

View File

@ -1,166 +0,0 @@
package wallettemplate.utils;
import javafx.animation.Animation;
import javafx.animation.FadeTransition;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.ScaleTransition;
import javafx.animation.Timeline;
import javafx.application.Platform;
import javafx.scene.*;
import javafx.scene.effect.*;
import javafx.scene.layout.*;
import javafx.util.Duration;
import static com.google.common.base.Preconditions.checkState;
public class GuiUtils {
/*public static void runAlert(BiConsumer<Stage, AlertWindowController> setup) {
try {
// JavaFX2 doesn't actually have a standard alert template. Instead the Scene Builder app will create FXML
// files for an alert window for you, and then you customise it as you see fit. I guess it makes sense in
// an odd sort of way.
Stage dialogStage = new Stage();
dialogStage.initModality(Modality.APPLICATION_MODAL);
FXMLLoader loader = new FXMLLoader(GuiUtils.class.getResource("alert.fxml"));
Pane pane = loader.load();
AlertWindowController controller = loader.getController();
setup.accept(dialogStage, controller);
dialogStage.setScene(new Scene(pane));
dialogStage.showAndWait();
} catch (IOException e) {
// We crashed whilst trying to show the alert dialog (this should never happen). Give up!
throw new RuntimeException(e);
}
}*/
/* public static void crashAlert(Throwable t) {
t.printStackTrace();
Throwable rootCause = Throwables.getRootCause(t);
Runnable r = () -> {
runAlert((stage, controller) -> controller.crashAlert(stage, rootCause.toString()));
Platform.exit();
};
if (Platform.isFxApplicationThread())
r.run();
else
Platform.runLater(r);
}*/
/**
* Show a GUI alert box for any unhandled exceptions that propagate out of this thread.
*/
/*public static void handleCrashesOnThisThread() {
Thread.currentThread().setUncaughtExceptionHandler((thread, exception) -> {
GuiUtils.crashAlert(Throwables.getRootCause(exception));
});
}
public static void informationalAlert(String message, String details, Object... args) {
String formattedDetails = String.format(details, args);
Runnable r = () -> runAlert((stage, controller) -> controller.informational(stage, message, formattedDetails));
if (Platform.isFxApplicationThread())
r.run();
else
Platform.runLater(r);
}*/
public static final int UI_ANIMATION_TIME_MSEC = 600;
public static final Duration UI_ANIMATION_TIME = Duration.millis(UI_ANIMATION_TIME_MSEC);
public static Animation fadeIn(Node ui) {
return fadeIn(ui, 0);
}
public static Animation fadeIn(Node ui, int delayMillis) {
ui.setCache(true);
FadeTransition ft = new FadeTransition(Duration.millis(UI_ANIMATION_TIME_MSEC), ui);
ft.setFromValue(0.0);
ft.setToValue(1.0);
ft.setOnFinished(ev -> ui.setCache(false));
ft.setDelay(Duration.millis(delayMillis));
ft.play();
return ft;
}
public static Animation fadeOut(Node ui) {
FadeTransition ft = new FadeTransition(Duration.millis(UI_ANIMATION_TIME_MSEC), ui);
ft.setFromValue(ui.getOpacity());
ft.setToValue(0.0);
ft.play();
return ft;
}
public static Animation fadeOutAndRemove(Pane parentPane, Node... nodes) {
Animation animation = fadeOut(nodes[0]);
animation.setOnFinished(actionEvent -> parentPane.getChildren().removeAll(nodes));
return animation;
}
public static Animation fadeOutAndRemove(Duration duration, Pane parentPane, Node... nodes) {
nodes[0].setCache(true);
FadeTransition ft = new FadeTransition(duration, nodes[0]);
ft.setFromValue(nodes[0].getOpacity());
ft.setToValue(0.0);
ft.setOnFinished(actionEvent -> parentPane.getChildren().removeAll(nodes));
ft.play();
return ft;
}
public static void blurOut(Node node) {
GaussianBlur blur = new GaussianBlur(0.0);
node.setEffect(blur);
Timeline timeline = new Timeline();
KeyValue kv = new KeyValue(blur.radiusProperty(), 10.0);
KeyFrame kf = new KeyFrame(Duration.millis(UI_ANIMATION_TIME_MSEC), kv);
timeline.getKeyFrames().add(kf);
timeline.play();
}
public static void blurIn(Node node) {
GaussianBlur blur = (GaussianBlur) node.getEffect();
Timeline timeline = new Timeline();
KeyValue kv = new KeyValue(blur.radiusProperty(), 0.0);
KeyFrame kf = new KeyFrame(Duration.millis(UI_ANIMATION_TIME_MSEC), kv);
timeline.getKeyFrames().add(kf);
timeline.setOnFinished(actionEvent -> node.setEffect(null));
timeline.play();
}
public static ScaleTransition zoomIn(Node node) {
return zoomIn(node, 0);
}
public static ScaleTransition zoomIn(Node node, int delayMillis) {
return scaleFromTo(node, 0.95, 1.0, delayMillis);
}
public static ScaleTransition explodeOut(Node node) {
return scaleFromTo(node, 1.0, 1.05, 0);
}
private static ScaleTransition scaleFromTo(Node node, double from, double to, int delayMillis) {
ScaleTransition scale = new ScaleTransition(Duration.millis(UI_ANIMATION_TIME_MSEC / 2), node);
scale.setFromX(from);
scale.setFromY(from);
scale.setToX(to);
scale.setToY(to);
scale.setDelay(Duration.millis(delayMillis));
scale.play();
return scale;
}
/**
* A useful helper for development purposes. Used as a switch for loading files from local disk, allowing live
* editing whilst the app runs without rebuilds.
*/
/* public static URL getResource(String name) {
if (false)
return unchecked(() -> new URL("file:///your/path/here/src/main/wallettemplate/" + name));
else
return MainController.class.getResource(name);
}*/
public static void checkGuiThread() {
checkState(Platform.isFxApplicationThread());
}
}

View File

@ -1,87 +0,0 @@
/*
* 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 wallettemplate.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Some generic utilities to make Java a bit less annoying.
*/
public class WTUtils {
private static final Logger log = LoggerFactory.getLogger(WTUtils.class);
public interface UncheckedRun<T> {
public T run() throws Throwable;
}
public interface UncheckedRunnable {
public void run() throws Throwable;
}
public static <T> T unchecked(UncheckedRun<T> run) {
try {
return run.run();
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
}
public static void uncheck(UncheckedRunnable run) {
try {
run.run();
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
}
public static void ignoreAndLog(UncheckedRunnable runnable) {
try {
runnable.run();
} catch (Throwable t) {
log.error("Ignoring error", t);
}
}
public static <T> T ignoredAndLogged(UncheckedRun<T> runnable) {
try {
return runnable.run();
} catch (Throwable t) {
log.error("Ignoring error", t);
return null;
}
}
public static boolean didThrow(UncheckedRun run) {
try {
run.run();
return false;
} catch (Throwable throwable) {
return true;
}
}
public static boolean didThrow(UncheckedRunnable run) {
try {
run.run();
return false;
} catch (Throwable throwable) {
return true;
}
}
}

View File

@ -1,134 +0,0 @@
/*
* 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/>.
*/
/*
* The MIT License (MIT)
*
* Copyright (c) 2013, Christian Schudt
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package wallettemplate.utils.easing;
import javafx.animation.Interpolator;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
/**
* The abstract base class for all easing interpolators.
*
* @author Christian Schudt
*/
public abstract class EasingInterpolator extends Interpolator {
/**
* The easing mode.
*/
private ObjectProperty<EasingMode> easingMode = new SimpleObjectProperty<>(EasingMode.EASE_OUT);
/**
* Constructs the interpolator with a specific easing mode.
*
* @param easingMode The easing mode.
*/
public EasingInterpolator(EasingMode easingMode) {
this.easingMode.set(easingMode);
}
/**
* The easing mode property.
*
* @return The property.
* @see #getEasingMode()
* @see #setEasingMode(EasingMode)
*/
public ObjectProperty<EasingMode> easingModeProperty() {
return easingMode;
}
/**
* Gets the easing mode.
*
* @return The easing mode.
* @see #easingModeProperty()
*/
public EasingMode getEasingMode() {
return easingMode.get();
}
/**
* Sets the easing mode.
*
* @param easingMode The easing mode.
* @see #easingModeProperty()
*/
public void setEasingMode(EasingMode easingMode) {
this.easingMode.set(easingMode);
}
/**
* Defines the base curve for the interpolator.
* The base curve is then transformed into an easing-in, easing-out easing-both curve.
*
* @param v The normalized value/time/progress of the interpolation (between 0 and 1).
* @return The resulting value of the function, should return a value between 0 and 1.
* @see javafx.animation.Interpolator#curve(double)
*/
protected abstract double baseCurve(final double v);
/**
* Curves the function depending on the easing mode.
*
* @param v The normalized value (between 0 and 1).
* @return The resulting value of the function.
*/
@Override
protected final double curve(final double v) {
switch (easingMode.get()) {
case EASE_IN:
return baseCurve(v);
case EASE_OUT:
return 1 - baseCurve(1 - v);
case EASE_BOTH:
if (v <= 0.5) {
return baseCurve(2 * v) / 2;
}
else {
return (2 - baseCurve(2 * (1 - v))) / 2;
}
}
return baseCurve(v);
}
}

View File

@ -1,12 +0,0 @@
package wallettemplate.utils.easing;
/**
* Defines the three easing modes, ease-in, ease-out and ease-both.
*
* @author Christian Schudt
*/
public enum EasingMode {
EASE_IN,
EASE_OUT,
EASE_BOTH
}

View File

@ -1,180 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2013, Christian Schudt
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package wallettemplate.utils.easing;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
/**
* This interpolator simulates an elastic behavior.
* <p/>
* The following curve illustrates the interpolation.
* </p>
* <svg style="width:300px;" xmlns="http://www.w3.org/2000/svg" viewBox="-2 -40 124 140">
* <line style="stroke: rgb(187, 187, 187); stroke-width: 1px;" y2="60" y1="0" x2="0" x1="0"/>
* <text style="font-size: 12px; fill: rgb(187, 187, 187);" y="6" x="2">x</text>
* <line style="stroke: rgb(187, 187, 187); stroke-width: 1px;" y2="60" y1="60" x2="120" x1="0"/>
* <text style="font-size: 12px; fill: rgb(187, 187, 187);" y="57" x="115">t</text>
* <path style="fill: rgba(255, 255, 255, 0);stroke: black;stroke-width: 2px;"
* d="M0,60 L1.2,54.8 2.4,47.7 3.6,39.4 4.8,30.4 6.0,21.2 7.2,12.2 8.4,3.9 9.6,-3.6 10.8,-9.9 12.0,-15.0 13.2,
* -18.7 14.4,-21.1 15.6,-22.3 16.8,-22.2 18.0,-21.2 19.2,-19.4 20.4,-16.9 21.6,-13.9 22.8,-10.8 24.0,-7.5 25.2,
* -4.3 26.4,-1.4 27.6,1.3 28.8,3.5 30.0,5.3 31.2,6.6 32.4,7.5 33.6,7.9 34.8,7.9 36.0,7.5 37.2,6.8 38.4,6.0 39.6,
* 4.9 40.8,3.8 42.0,2.7 43.2,1.5 44.4,0.5 45.6,-0.5 46.8,-1.2 48.0,-1.9 49.2,-2.3 50.4,-2.6 51.6,-2.8 52.8,
* -2.8 54.0,-2.7 55.2,-2.4 56.4,-2.1 57.6,-1.7 58.8,-1.3 60.0,-0.9 61.2,-0.5 62.4,-0.2 63.6,0.2 64.8,0.4 66.0,
* 0.7 67.2,0.8 68.4,0.9 69.6,1.0 70.8,1.0 72.0,0.9 73.2,0.9 74.4,0.7 75.6,0.6 76.8,0.5 78.0,0.3 79.2,0.2 80.4,
* 0.1 81.6,-0.1 82.8,-0.2 84.0,-0.2 85.2,-0.3 86.4,-0.3 87.6,-0.3 88.8,-0.3 90.0,-0.3 91.2,-0.3 92.4,-0.3 93.6,
* -0.2 94.8,-0.2 96.0,-0.1 97.2,-0.1 98.4,-0.0 99.6,0.0 100.8,0.1 102.0,0.1 103.2,0.1 104.4,0.1 105.6,0.1 106.8,
* 0.1 108.0,0.1 109.2,0.1 110.4,0.1 111.6,0.1 112.8,0.1 114.0,0.0 115.2,0.0 116.4,0.0 117.6,-0.0 118.8,-0.0 120.0,
* 0.0"/>
* </svg>
* <p>
* The math in this class is taken from
* <a href="http://www.robertpenner.com/easing/">http://www.robertpenner.com/easing/</a>.
*
* @author Christian Schudt
*/
public class ElasticInterpolator extends EasingInterpolator {
/**
* The amplitude.
*/
private DoubleProperty amplitude = new SimpleDoubleProperty(this, "amplitude", 1);
/**
* The number of oscillations.
*/
private DoubleProperty oscillations = new SimpleDoubleProperty(this, "oscillations", 3);
/**
* Default constructor. Initializes the interpolator with ease out mode.
*/
public ElasticInterpolator() {
this(EasingMode.EASE_OUT);
}
/**
* Constructs the interpolator with a specific easing mode.
*
* @param easingMode The easing mode.
*/
public ElasticInterpolator(EasingMode easingMode) {
super(easingMode);
}
/**
* Sets the easing mode.
*
* @param easingMode The easing mode.
* @see #easingModeProperty()
*/
public ElasticInterpolator(EasingMode easingMode, double amplitude, double oscillations) {
super(easingMode);
this.amplitude.set(amplitude);
this.oscillations.set(oscillations);
}
/**
* The oscillations property. Defines number of oscillations.
*
* @return The property.
* @see #getOscillations()
* @see #setOscillations(double)
*/
public DoubleProperty oscillationsProperty() {
return oscillations;
}
/**
* The amplitude. The minimum value is 1. If this value is < 1 it will be set to 1 during animation.
*
* @return The property.
* @see #getAmplitude()
* @see #setAmplitude(double)
*/
public DoubleProperty amplitudeProperty() {
return amplitude;
}
/**
* Gets the amplitude.
*
* @return The amplitude.
* @see #amplitudeProperty()
*/
public double getAmplitude() {
return amplitude.get();
}
/**
* Sets the amplitude.
*
* @param amplitude The amplitude.
* @see #amplitudeProperty()
*/
public void setAmplitude(final double amplitude) {
this.amplitude.set(amplitude);
}
/**
* Gets the number of oscillations.
*
* @return The oscillations.
* @see #oscillationsProperty()
*/
public double getOscillations() {
return oscillations.get();
}
/**
* Sets the number of oscillations.
*
* @param oscillations The oscillations.
* @see #oscillationsProperty()
*/
public void setOscillations(final double oscillations) {
this.oscillations.set(oscillations);
}
@Override
protected double baseCurve(double v) {
if (v == 0) {
return 0;
}
if (v == 1) {
return 1;
}
double p = 1.0 / oscillations.get();
double a = amplitude.get();
double s;
if (a < Math.abs(1)) {
a = 1;
s = p / 4;
}
else {
s = p / (2 * Math.PI) * Math.asin(1 / a);
}
return -(a * Math.pow(2, 10 * (v -= 1)) * Math.sin((v - s) * (2 * Math.PI) / p));
}
}

View File

@ -25,7 +25,7 @@
<logger name="io.bitsquare" level="TRACE"/>
<logger name="org.bitcoinj" level="DEBUG"/>
<logger name="org.bitcoinj" level="WARN"/>
<logger name="net.tomp2p" level="WARN"/>
<logger name="io.netty.util" level="WARN"/>