mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-24 15:10:44 +01:00
Add time interval selector
This commit is contained in:
parent
9dab4fd65a
commit
67d76cda27
9 changed files with 273 additions and 97 deletions
|
@ -21,6 +21,8 @@ import bisq.desktop.common.model.ActivatableViewModel;
|
||||||
|
|
||||||
import bisq.common.util.Tuple2;
|
import bisq.common.util.Tuple2;
|
||||||
|
|
||||||
|
import java.time.temporal.TemporalAdjuster;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
@ -28,7 +30,7 @@ import java.util.function.Predicate;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class ChartModel extends ActivatableViewModel {
|
public abstract class ChartModel extends ActivatableViewModel {
|
||||||
public interface Listener {
|
public interface Listener {
|
||||||
/**
|
/**
|
||||||
* @param fromDate Epoch date in millis for earliest data
|
* @param fromDate Epoch date in millis for earliest data
|
||||||
|
@ -40,9 +42,12 @@ public class ChartModel extends ActivatableViewModel {
|
||||||
protected Number lowerBound, upperBound;
|
protected Number lowerBound, upperBound;
|
||||||
protected final Set<Listener> listeners = new HashSet<>();
|
protected final Set<Listener> listeners = new HashSet<>();
|
||||||
|
|
||||||
|
private Predicate<Long> predicate = e -> true;
|
||||||
|
|
||||||
public ChartModel() {
|
public ChartModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -84,8 +89,17 @@ public class ChartModel extends ActivatableViewModel {
|
||||||
return new Tuple2<>(fromDateSec, toDateSec);
|
return new Tuple2<>(fromDateSec, toDateSec);
|
||||||
}
|
}
|
||||||
|
|
||||||
Predicate<Long> getPredicate(Tuple2<Double, Double> fromToTuple) {
|
protected abstract void applyTemporalAdjuster(TemporalAdjuster temporalAdjuster);
|
||||||
return value -> value >= fromToTuple.first && value <= fromToTuple.second;
|
|
||||||
|
protected abstract TemporalAdjuster getTemporalAdjuster();
|
||||||
|
|
||||||
|
Predicate<Long> getPredicate() {
|
||||||
|
return predicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
Predicate<Long> setAndGetPredicate(Tuple2<Double, Double> fromToTuple) {
|
||||||
|
predicate = value -> value >= fromToTuple.first && value <= fromToTuple.second;
|
||||||
|
return predicate;
|
||||||
}
|
}
|
||||||
|
|
||||||
void notifyListeners(Tuple2<Double, Double> fromToTuple) {
|
void notifyListeners(Tuple2<Double, Double> fromToTuple) {
|
||||||
|
|
|
@ -19,6 +19,9 @@ package bisq.desktop.components.chart;
|
||||||
|
|
||||||
import bisq.desktop.common.view.ActivatableView;
|
import bisq.desktop.common.view.ActivatableView;
|
||||||
import bisq.desktop.components.AutoTooltipSlideToggleButton;
|
import bisq.desktop.components.AutoTooltipSlideToggleButton;
|
||||||
|
import bisq.desktop.components.AutoTooltipToggleButton;
|
||||||
|
|
||||||
|
import bisq.core.locale.Res;
|
||||||
|
|
||||||
import bisq.common.util.Tuple2;
|
import bisq.common.util.Tuple2;
|
||||||
|
|
||||||
|
@ -29,8 +32,12 @@ import javafx.scene.chart.NumberAxis;
|
||||||
import javafx.scene.chart.XYChart;
|
import javafx.scene.chart.XYChart;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.SplitPane;
|
import javafx.scene.control.SplitPane;
|
||||||
|
import javafx.scene.control.Toggle;
|
||||||
|
import javafx.scene.control.ToggleButton;
|
||||||
|
import javafx.scene.control.ToggleGroup;
|
||||||
import javafx.scene.control.Tooltip;
|
import javafx.scene.control.Tooltip;
|
||||||
import javafx.scene.input.MouseEvent;
|
import javafx.scene.input.MouseEvent;
|
||||||
|
import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.Pane;
|
||||||
import javafx.scene.layout.Priority;
|
import javafx.scene.layout.Priority;
|
||||||
|
@ -44,6 +51,8 @@ import javafx.beans.value.ChangeListener;
|
||||||
|
|
||||||
import javafx.util.StringConverter;
|
import javafx.util.StringConverter;
|
||||||
|
|
||||||
|
import java.time.temporal.TemporalAdjuster;
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
|
||||||
|
@ -54,12 +63,15 @@ import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import static bisq.desktop.util.FormBuilder.getTopLabelWithVBox;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public abstract class ChartView<T extends ChartModel> extends ActivatableView<VBox, T> {
|
public abstract class ChartView<T extends ChartModel> extends ActivatableView<VBox, T> {
|
||||||
private final Pane center;
|
private final Pane center;
|
||||||
|
@ -72,28 +84,27 @@ public abstract class ChartView<T extends ChartModel> extends ActivatableView<VB
|
||||||
private final HBox timelineLabels;
|
private final HBox timelineLabels;
|
||||||
private final List<Node> dividerNodes = new ArrayList<>();
|
private final List<Node> dividerNodes = new ArrayList<>();
|
||||||
private final Double[] dividerPositions = new Double[]{0d, 1d};
|
private final Double[] dividerPositions = new Double[]{0d, 1d};
|
||||||
|
private final ToggleGroup timeUnitToggleGroup = new ToggleGroup();
|
||||||
private boolean pressed;
|
private boolean pressed;
|
||||||
private double x;
|
private double x;
|
||||||
private ChangeListener<Number> widthListener;
|
private ChangeListener<Number> widthListener;
|
||||||
private int maxSeriesSize;
|
private int maxSeriesSize;
|
||||||
|
private ChangeListener<Toggle> timeUnitChangeListener;
|
||||||
|
protected String dateFormatPatters = "dd MMM\nyyyy";
|
||||||
|
|
||||||
public ChartView(T model) {
|
public ChartView(T model) {
|
||||||
super(model);
|
super(model);
|
||||||
|
|
||||||
root = new VBox();
|
root = new VBox();
|
||||||
Pane left = new Pane();
|
|
||||||
center = new Pane();
|
|
||||||
Pane right = new Pane();
|
|
||||||
splitPane = new SplitPane();
|
|
||||||
splitPane.getItems().addAll(left, center, right);
|
|
||||||
|
|
||||||
|
// time units
|
||||||
|
Pane timeIntervalBox = getTimeIntervalBox();
|
||||||
|
|
||||||
|
// chart
|
||||||
xAxis = getXAxis();
|
xAxis = getXAxis();
|
||||||
yAxis = getYAxis();
|
yAxis = getYAxis();
|
||||||
|
|
||||||
chart = getChart();
|
chart = getChart();
|
||||||
|
|
||||||
addSeries();
|
addSeries();
|
||||||
|
|
||||||
HBox legendBox1 = getLegendBox(getSeriesForLegend1());
|
HBox legendBox1 = getLegendBox(getSeriesForLegend1());
|
||||||
Collection<XYChart.Series<Number, Number>> seriesForLegend2 = getSeriesForLegend2();
|
Collection<XYChart.Series<Number, Number>> seriesForLegend2 = getSeriesForLegend2();
|
||||||
HBox legendBox2 = null;
|
HBox legendBox2 = null;
|
||||||
|
@ -101,8 +112,15 @@ public abstract class ChartView<T extends ChartModel> extends ActivatableView<VB
|
||||||
legendBox2 = getLegendBox(seriesForLegend2);
|
legendBox2 = getLegendBox(seriesForLegend2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Time navigation
|
||||||
|
Pane left = new Pane();
|
||||||
|
center = new Pane();
|
||||||
|
Pane right = new Pane();
|
||||||
|
splitPane = new SplitPane();
|
||||||
|
splitPane.getItems().addAll(left, center, right);
|
||||||
timelineLabels = new HBox();
|
timelineLabels = new HBox();
|
||||||
|
|
||||||
|
// Container
|
||||||
VBox box = new VBox();
|
VBox box = new VBox();
|
||||||
int paddingRight = 89;
|
int paddingRight = 89;
|
||||||
int paddingLeft = 15;
|
int paddingLeft = 15;
|
||||||
|
@ -114,14 +132,9 @@ public abstract class ChartView<T extends ChartModel> extends ActivatableView<VB
|
||||||
VBox.setMargin(legendBox2, new Insets(-20, paddingRight, 0, paddingLeft));
|
VBox.setMargin(legendBox2, new Insets(-20, paddingRight, 0, paddingLeft));
|
||||||
box.getChildren().add(legendBox2);
|
box.getChildren().add(legendBox2);
|
||||||
}
|
}
|
||||||
root.getChildren().addAll(chart, box);
|
root.getChildren().addAll(timeIntervalBox, chart, box);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract Collection<XYChart.Series<Number, Number>> getSeriesForLegend1();
|
|
||||||
|
|
||||||
protected abstract Collection<XYChart.Series<Number, Number>> getSeriesForLegend2();
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -138,24 +151,37 @@ public abstract class ChartView<T extends ChartModel> extends ActivatableView<VB
|
||||||
splitPane.setDividerPosition(0, dividerPositions[0]);
|
splitPane.setDividerPosition(0, dividerPositions[0]);
|
||||||
splitPane.setDividerPosition(1, dividerPositions[1]);
|
splitPane.setDividerPosition(1, dividerPositions[1]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
timeUnitChangeListener = (observable, oldValue, newValue) -> {
|
||||||
|
TemporalAdjusterUtil.Interval interval = (TemporalAdjusterUtil.Interval) newValue.getUserData();
|
||||||
|
applyTemporalAdjuster(interval.getAdjuster());
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void activate() {
|
public void activate() {
|
||||||
root.widthProperty().addListener(widthListener);
|
root.widthProperty().addListener(widthListener);
|
||||||
|
timeUnitToggleGroup.selectedToggleProperty().addListener(timeUnitChangeListener);
|
||||||
|
|
||||||
splitPane.setOnMousePressed(this::onMousePressedSplitPane);
|
splitPane.setOnMousePressed(this::onMousePressedSplitPane);
|
||||||
splitPane.setOnMouseDragged(this::onMouseDragged);
|
splitPane.setOnMouseDragged(this::onMouseDragged);
|
||||||
center.setOnMousePressed(this::onMousePressedCenter);
|
center.setOnMousePressed(this::onMousePressedCenter);
|
||||||
center.setOnMouseReleased(this::onMouseReleasedCenter);
|
center.setOnMouseReleased(this::onMouseReleasedCenter);
|
||||||
|
|
||||||
initData();
|
initData();
|
||||||
|
|
||||||
initDividerMouseHandlers();
|
initDividerMouseHandlers();
|
||||||
|
// Need to get called again here as otherwise styles are not applied correctly
|
||||||
|
applySeriesStyles();
|
||||||
|
|
||||||
|
TemporalAdjuster temporalAdjuster = model.getTemporalAdjuster();
|
||||||
|
applyTemporalAdjuster(temporalAdjuster);
|
||||||
|
findToggleByTemporalAdjuster(temporalAdjuster).ifPresent(timeUnitToggleGroup::selectToggle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deactivate() {
|
public void deactivate() {
|
||||||
root.widthProperty().removeListener(widthListener);
|
root.widthProperty().removeListener(widthListener);
|
||||||
|
timeUnitToggleGroup.selectedToggleProperty().removeListener(timeUnitChangeListener);
|
||||||
splitPane.setOnMousePressed(null);
|
splitPane.setOnMousePressed(null);
|
||||||
splitPane.setOnMouseDragged(null);
|
splitPane.setOnMouseDragged(null);
|
||||||
center.setOnMousePressed(null);
|
center.setOnMousePressed(null);
|
||||||
|
@ -176,6 +202,40 @@ public abstract class ChartView<T extends ChartModel> extends ActivatableView<VB
|
||||||
// Customisations
|
// Customisations
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
protected Pane getTimeIntervalBox() {
|
||||||
|
ToggleButton year = getToggleButton(Res.get("time.year"), TemporalAdjusterUtil.Interval.YEAR,
|
||||||
|
timeUnitToggleGroup, "toggle-left");
|
||||||
|
ToggleButton month = getToggleButton(Res.get("time.month"), TemporalAdjusterUtil.Interval.MONTH,
|
||||||
|
timeUnitToggleGroup, "toggle-center");
|
||||||
|
ToggleButton week = getToggleButton(Res.get("time.week"), TemporalAdjusterUtil.Interval.WEEK,
|
||||||
|
timeUnitToggleGroup, "toggle-center");
|
||||||
|
ToggleButton day = getToggleButton(Res.get("time.day"), TemporalAdjusterUtil.Interval.DAY,
|
||||||
|
timeUnitToggleGroup, "toggle-center");
|
||||||
|
|
||||||
|
HBox toggleBox = new HBox();
|
||||||
|
toggleBox.setSpacing(0);
|
||||||
|
toggleBox.setAlignment(Pos.CENTER_LEFT);
|
||||||
|
toggleBox.getChildren().addAll(year, month, week, day);
|
||||||
|
|
||||||
|
Tuple2<Label, VBox> topLabelWithVBox = getTopLabelWithVBox(Res.get("shared.interval"), toggleBox);
|
||||||
|
AnchorPane pane = new AnchorPane();
|
||||||
|
VBox vBox = topLabelWithVBox.second;
|
||||||
|
pane.getChildren().add(vBox);
|
||||||
|
AnchorPane.setRightAnchor(vBox, 90d);
|
||||||
|
return pane;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ToggleButton getToggleButton(String label,
|
||||||
|
TemporalAdjusterUtil.Interval interval,
|
||||||
|
ToggleGroup toggleGroup,
|
||||||
|
String style) {
|
||||||
|
ToggleButton toggleButton = new AutoTooltipToggleButton(label);
|
||||||
|
toggleButton.setUserData(interval);
|
||||||
|
toggleButton.setToggleGroup(toggleGroup);
|
||||||
|
toggleButton.setId(style);
|
||||||
|
return toggleButton;
|
||||||
|
}
|
||||||
|
|
||||||
protected NumberAxis getXAxis() {
|
protected NumberAxis getXAxis() {
|
||||||
NumberAxis xAxis;
|
NumberAxis xAxis;
|
||||||
xAxis = new NumberAxis();
|
xAxis = new NumberAxis();
|
||||||
|
@ -214,7 +274,7 @@ public abstract class ChartView<T extends ChartModel> extends ActivatableView<VB
|
||||||
toggle.setText(seriesName);
|
toggle.setText(seriesName);
|
||||||
toggle.setId("charts-legend-toggle" + seriesIndexMap.get(seriesName));
|
toggle.setId("charts-legend-toggle" + seriesIndexMap.get(seriesName));
|
||||||
toggle.setSelected(true);
|
toggle.setSelected(true);
|
||||||
toggle.setOnAction(e -> onSelectToggle(series, toggle.isSelected()));
|
toggle.setOnAction(e -> onSelectLegendToggle(series, toggle.isSelected()));
|
||||||
hBox.getChildren().add(toggle);
|
hBox.getChildren().add(toggle);
|
||||||
});
|
});
|
||||||
Region spacer = new Region();
|
Region spacer = new Region();
|
||||||
|
@ -223,27 +283,32 @@ public abstract class ChartView<T extends ChartModel> extends ActivatableView<VB
|
||||||
return hBox;
|
return hBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onSelectToggle(XYChart.Series<Number, Number> series, boolean isSelected) {
|
protected abstract Collection<XYChart.Series<Number, Number>> getSeriesForLegend1();
|
||||||
|
|
||||||
|
protected abstract Collection<XYChart.Series<Number, Number>> getSeriesForLegend2();
|
||||||
|
|
||||||
|
private void onSelectLegendToggle(XYChart.Series<Number, Number> series, boolean isSelected) {
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
chart.getData().add(series);
|
chart.getData().add(series);
|
||||||
} else {
|
} else {
|
||||||
chart.getData().remove(series);
|
chart.getData().remove(series);
|
||||||
}
|
}
|
||||||
applySeriesStyles();
|
applySeriesStyles();
|
||||||
|
applyTooltip();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void hideSeries(XYChart.Series<Number, Number> series) {
|
protected void hideSeries(XYChart.Series<Number, Number> series) {
|
||||||
toggleBySeriesName.get(series.getName()).setSelected(false);
|
toggleBySeriesName.get(series.getName()).setSelected(false);
|
||||||
onSelectToggle(series, false);
|
onSelectLegendToggle(series, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected StringConverter<Number> getTimeAxisStringConverter() {
|
protected StringConverter<Number> getTimeAxisStringConverter() {
|
||||||
return new StringConverter<>() {
|
return new StringConverter<>() {
|
||||||
@Override
|
@Override
|
||||||
public String toString(Number value) {
|
public String toString(Number value) {
|
||||||
DateFormat f = new SimpleDateFormat("YYYY-MM");
|
DateFormat format = new SimpleDateFormat(dateFormatPatters);
|
||||||
Date date = new Date(Math.round(value.doubleValue()) * 1000);
|
Date date = new Date(Math.round(value.doubleValue()) * 1000);
|
||||||
return f.format(date);
|
return format.format(date);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -267,6 +332,30 @@ public abstract class ChartView<T extends ChartModel> extends ActivatableView<VB
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void applyTemporalAdjuster(TemporalAdjuster temporalAdjuster) {
|
||||||
|
model.applyTemporalAdjuster(temporalAdjuster);
|
||||||
|
findToggleByTemporalAdjuster(temporalAdjuster)
|
||||||
|
.map(e -> (TemporalAdjusterUtil.Interval) e.getUserData())
|
||||||
|
.ifPresent(interval -> setDateFormatPatters(interval));
|
||||||
|
|
||||||
|
updateData(model.getPredicate());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDateFormatPatters(TemporalAdjusterUtil.Interval interval) {
|
||||||
|
switch (interval) {
|
||||||
|
case YEAR:
|
||||||
|
dateFormatPatters = "yyyy";
|
||||||
|
break;
|
||||||
|
case MONTH:
|
||||||
|
dateFormatPatters = "MMM\nyyyy";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dateFormatPatters = "MMM dd\nyyyy";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract void initData();
|
protected abstract void initData();
|
||||||
|
|
||||||
protected abstract void updateData(Predicate<Long> predicate);
|
protected abstract void updateData(Predicate<Long> predicate);
|
||||||
|
@ -274,20 +363,25 @@ public abstract class ChartView<T extends ChartModel> extends ActivatableView<VB
|
||||||
protected void applyTooltip() {
|
protected void applyTooltip() {
|
||||||
chart.getData().forEach(series -> {
|
chart.getData().forEach(series -> {
|
||||||
series.getData().forEach(data -> {
|
series.getData().forEach(data -> {
|
||||||
String xValue = getXAxis().getTickLabelFormatter().toString(data.getXValue());
|
|
||||||
String yValue = getYAxis().getTickLabelFormatter().toString(data.getYValue());
|
|
||||||
Node node = data.getNode();
|
Node node = data.getNode();
|
||||||
Tooltip.install(node, new Tooltip(yValue + "\n" + xValue));
|
if (node == null) {
|
||||||
|
return;
|
||||||
//Adding class on hover
|
}
|
||||||
node.setOnMouseEntered(event -> node.getStyleClass().add("onHover"));
|
String xValue = getTooltipDateConverter(data.getXValue());
|
||||||
|
String yValue = getYAxisStringConverter().toString(data.getYValue());
|
||||||
//Removing class on exit
|
Tooltip.install(node, new Tooltip(Res.get("dao.factsAndFigures.supply.chart.tradeFee.toolTip", yValue, xValue)));
|
||||||
node.setOnMouseExited(event -> node.getStyleClass().remove("onHover"));
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected String getTooltipDateConverter(Number date) {
|
||||||
|
return getTimeAxisStringConverter().toString(date).replace("\n", " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getTooltipValueConverter(Number value) {
|
||||||
|
return getYAxisStringConverter().toString(value);
|
||||||
|
}
|
||||||
|
|
||||||
// Only called once when initial data are applied. We want the min. and max. values so we have the max. scale for
|
// Only called once when initial data are applied. We want the min. and max. values so we have the max. scale for
|
||||||
// navigation.
|
// navigation.
|
||||||
protected void setTimeLineLabels() {
|
protected void setTimeLineLabels() {
|
||||||
|
@ -317,7 +411,7 @@ public abstract class ChartView<T extends ChartModel> extends ActivatableView<VB
|
||||||
|
|
||||||
// The chart framework assigns the colored depending on the order it got added, but want to keep colors
|
// The chart framework assigns the colored depending on the order it got added, but want to keep colors
|
||||||
// the same so they match with the legend toggle.
|
// the same so they match with the legend toggle.
|
||||||
private void applySeriesStyles() {
|
protected void applySeriesStyles() {
|
||||||
for (int index = 0; index < chart.getData().size(); index++) {
|
for (int index = 0; index < chart.getData().size(); index++) {
|
||||||
XYChart.Series<Number, Number> series = chart.getData().get(index);
|
XYChart.Series<Number, Number> series = chart.getData().get(index);
|
||||||
int staticIndex = seriesIndexMap.get(series.getName());
|
int staticIndex = seriesIndexMap.get(series.getName());
|
||||||
|
@ -350,6 +444,12 @@ public abstract class ChartView<T extends ChartModel> extends ActivatableView<VB
|
||||||
return maxSeriesSize;
|
return maxSeriesSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Optional<Toggle> findToggleByTemporalAdjuster(TemporalAdjuster adjuster) {
|
||||||
|
return timeUnitToggleGroup.getToggles().stream()
|
||||||
|
.filter(toggle -> ((TemporalAdjusterUtil.Interval) toggle.getUserData()).getAdjuster().equals(adjuster))
|
||||||
|
.findAny();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Timeline navigation
|
// Timeline navigation
|
||||||
|
@ -371,8 +471,7 @@ public abstract class ChartView<T extends ChartModel> extends ActivatableView<VB
|
||||||
dividerPositions[1] = rightPos;
|
dividerPositions[1] = rightPos;
|
||||||
splitPane.setDividerPositions(leftPos, rightPos);
|
splitPane.setDividerPositions(leftPos, rightPos);
|
||||||
Tuple2<Double, Double> fromToTuple = model.timelinePositionToEpochSeconds(leftPos, rightPos);
|
Tuple2<Double, Double> fromToTuple = model.timelinePositionToEpochSeconds(leftPos, rightPos);
|
||||||
updateData(model.getPredicate(fromToTuple));
|
updateData(model.setAndGetPredicate(fromToTuple));
|
||||||
applySeriesStyles();
|
|
||||||
model.notifyListeners(fromToTuple);
|
model.notifyListeners(fromToTuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Bisq.
|
||||||
|
*
|
||||||
|
* Bisq 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.
|
||||||
|
*
|
||||||
|
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package bisq.desktop.components.chart;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.temporal.TemporalAdjuster;
|
||||||
|
import java.time.temporal.TemporalAdjusters;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
public class TemporalAdjusterUtil {
|
||||||
|
public enum Interval {
|
||||||
|
YEAR(TemporalAdjusters.firstDayOfYear()),
|
||||||
|
MONTH(TemporalAdjusters.firstDayOfMonth()),
|
||||||
|
WEEK(TemporalAdjusters.ofDateAdjuster(date -> date.plusWeeks(1))),
|
||||||
|
DAY(TemporalAdjusters.ofDateAdjuster(d -> d));
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final TemporalAdjuster adjuster;
|
||||||
|
|
||||||
|
Interval(TemporalAdjuster adjuster) {
|
||||||
|
this.adjuster = adjuster;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final ZoneId ZONE_ID = ZoneId.systemDefault();
|
||||||
|
|
||||||
|
public static long toTimeInterval(Instant instant, TemporalAdjuster temporalAdjuster) {
|
||||||
|
return instant
|
||||||
|
.atZone(ZONE_ID)
|
||||||
|
.toLocalDate()
|
||||||
|
.with(temporalAdjuster)
|
||||||
|
.atStartOfDay(ZONE_ID)
|
||||||
|
.toInstant()
|
||||||
|
.getEpochSecond();
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package bisq.desktop.main.dao.economy.supply;
|
package bisq.desktop.main.dao.economy.supply;
|
||||||
|
|
||||||
|
import bisq.desktop.components.chart.TemporalAdjusterUtil;
|
||||||
|
|
||||||
import bisq.core.dao.state.DaoStateService;
|
import bisq.core.dao.state.DaoStateService;
|
||||||
import bisq.core.dao.state.model.blockchain.Tx;
|
import bisq.core.dao.state.model.blockchain.Tx;
|
||||||
import bisq.core.dao.state.model.governance.Issuance;
|
import bisq.core.dao.state.model.governance.Issuance;
|
||||||
|
@ -26,9 +28,7 @@ import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.ZoneId;
|
|
||||||
import java.time.temporal.TemporalAdjuster;
|
import java.time.temporal.TemporalAdjuster;
|
||||||
import java.time.temporal.TemporalAdjusters;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -46,11 +46,10 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Singleton
|
@Singleton
|
||||||
public class DaoEconomyDataProvider {
|
public class DaoEconomyDataProvider {
|
||||||
private static final ZoneId ZONE_ID = ZoneId.systemDefault();
|
|
||||||
private static final TemporalAdjuster FIRST_DAY_OF_MONTH = TemporalAdjusters.firstDayOfMonth();
|
|
||||||
|
|
||||||
private final DaoStateService daoStateService;
|
private final DaoStateService daoStateService;
|
||||||
private final Function<Integer, Long> blockHeightToEpochSeconds;
|
private final Function<Issuance, Long> blockTimeOfIssuanceFunction;
|
||||||
|
|
||||||
|
private TemporalAdjuster temporalAdjuster = TemporalAdjusterUtil.Interval.MONTH.getAdjuster();
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -62,8 +61,23 @@ public class DaoEconomyDataProvider {
|
||||||
super();
|
super();
|
||||||
this.daoStateService = daoStateService;
|
this.daoStateService = daoStateService;
|
||||||
|
|
||||||
blockHeightToEpochSeconds = memoize(height ->
|
blockTimeOfIssuanceFunction = memoize(issuance -> {
|
||||||
toStartOfMonth(Instant.ofEpochMilli(daoStateService.getBlockTime(height))));
|
int height = daoStateService.getStartHeightOfCurrentCycle(issuance.getChainHeight()).orElse(0);
|
||||||
|
return daoStateService.getBlockTime(height);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// API
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void setTemporalAdjuster(TemporalAdjuster temporalAdjuster) {
|
||||||
|
this.temporalAdjuster = temporalAdjuster;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TemporalAdjuster getTemporalAdjuster() {
|
||||||
|
return temporalAdjuster;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -109,7 +123,7 @@ public class DaoEconomyDataProvider {
|
||||||
|
|
||||||
public Map<Long, Long> getBurnedBsqByMonth(Collection<Tx> txs, Predicate<Long> predicate) {
|
public Map<Long, Long> getBurnedBsqByMonth(Collection<Tx> txs, Predicate<Long> predicate) {
|
||||||
return txs.stream()
|
return txs.stream()
|
||||||
.collect(Collectors.groupingBy(tx -> toStartOfMonth(Instant.ofEpochMilli(tx.getTime()))))
|
.collect(Collectors.groupingBy(tx -> toTimeInterval(Instant.ofEpochMilli(tx.getTime()))))
|
||||||
.entrySet()
|
.entrySet()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(entry -> predicate.test(entry.getKey()))
|
.filter(entry -> predicate.test(entry.getKey()))
|
||||||
|
@ -125,8 +139,8 @@ public class DaoEconomyDataProvider {
|
||||||
// as adjuster would be more complicate (though could be done in future).
|
// as adjuster would be more complicate (though could be done in future).
|
||||||
public Map<Long, Long> getIssuedBsqByMonth(Set<Issuance> issuanceSet, Predicate<Long> predicate) {
|
public Map<Long, Long> getIssuedBsqByMonth(Set<Issuance> issuanceSet, Predicate<Long> predicate) {
|
||||||
return issuanceSet.stream()
|
return issuanceSet.stream()
|
||||||
.collect(Collectors.groupingBy(blockHeightToEpochSeconds.compose(issuance ->
|
.collect(Collectors.groupingBy(issuance ->
|
||||||
daoStateService.getStartHeightOfCurrentCycle(issuance.getChainHeight()).orElse(0))))
|
toTimeInterval(Instant.ofEpochMilli(blockTimeOfIssuanceFunction.apply(issuance)))))
|
||||||
.entrySet()
|
.entrySet()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(entry -> predicate.test(entry.getKey()))
|
.filter(entry -> predicate.test(entry.getKey()))
|
||||||
|
@ -165,18 +179,13 @@ public class DaoEconomyDataProvider {
|
||||||
// as we have clearly separated that now. In case we have duplicate data for a months we use the static data.
|
// as we have clearly separated that now. In case we have duplicate data for a months we use the static data.
|
||||||
return historicalData.entrySet().stream()
|
return historicalData.entrySet().stream()
|
||||||
.filter(e -> predicate.test(e.getKey()))
|
.filter(e -> predicate.test(e.getKey()))
|
||||||
.collect(Collectors.toMap(e -> toStartOfMonth(Instant.ofEpochSecond(e.getKey())),
|
.collect(Collectors.toMap(e -> toTimeInterval(Instant.ofEpochSecond(e.getKey())),
|
||||||
Map.Entry::getValue));
|
Map.Entry::getValue,
|
||||||
|
(a, b) -> a + b));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long toStartOfMonth(Instant instant) {
|
public long toTimeInterval(Instant instant) {
|
||||||
return instant
|
return TemporalAdjusterUtil.toTimeInterval(instant, temporalAdjuster);
|
||||||
.atZone(ZONE_ID)
|
|
||||||
.toLocalDate()
|
|
||||||
.with(FIRST_DAY_OF_MONTH)
|
|
||||||
.atStartOfDay(ZONE_ID)
|
|
||||||
.toInstant()
|
|
||||||
.getEpochSecond();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -44,8 +44,6 @@ import javafx.scene.layout.VBox;
|
||||||
|
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
|
import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
|
||||||
import static bisq.desktop.util.FormBuilder.addTopLabelReadOnlyTextField;
|
import static bisq.desktop.util.FormBuilder.addTopLabelReadOnlyTextField;
|
||||||
|
|
||||||
|
@ -104,6 +102,7 @@ public class SupplyView extends ActivatableView<GridPane, Void> implements DaoSt
|
||||||
protected void deactivate() {
|
protected void deactivate() {
|
||||||
daoEconomyChartView.removeListener(this);
|
daoEconomyChartView.removeListener(this);
|
||||||
daoFacade.removeBsqStateListener(this);
|
daoFacade.removeBsqStateListener(this);
|
||||||
|
daoEconomyChartView.deactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -115,8 +114,6 @@ public class SupplyView extends ActivatableView<GridPane, Void> implements DaoSt
|
||||||
public void onDateFilterChanged(long fromDate, long toDate) {
|
public void onDateFilterChanged(long fromDate, long toDate) {
|
||||||
this.fromDate = fromDate;
|
this.fromDate = fromDate;
|
||||||
this.toDate = toDate;
|
this.toDate = toDate;
|
||||||
log.error(new Date(fromDate).toString());
|
|
||||||
log.error(new Date(toDate).toString());
|
|
||||||
updateEconomicsData();
|
updateEconomicsData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,9 @@ import javax.inject.Inject;
|
||||||
|
|
||||||
import javafx.scene.chart.XYChart;
|
import javafx.scene.chart.XYChart;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.temporal.TemporalAdjuster;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
@ -47,11 +50,21 @@ public class DaoEconomyChartModel extends ChartModel {
|
||||||
@Inject
|
@Inject
|
||||||
public DaoEconomyChartModel(DaoStateService daoStateService, DaoEconomyDataProvider daoEconomyDataProvider) {
|
public DaoEconomyChartModel(DaoStateService daoStateService, DaoEconomyDataProvider daoEconomyDataProvider) {
|
||||||
super();
|
super();
|
||||||
this.daoStateService = daoStateService;
|
|
||||||
|
|
||||||
|
this.daoStateService = daoStateService;
|
||||||
this.daoEconomyDataProvider = daoEconomyDataProvider;
|
this.daoEconomyDataProvider = daoEconomyDataProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void applyTemporalAdjuster(TemporalAdjuster temporalAdjuster) {
|
||||||
|
daoEconomyDataProvider.setTemporalAdjuster(temporalAdjuster);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TemporalAdjuster getTemporalAdjuster() {
|
||||||
|
return daoEconomyDataProvider.getTemporalAdjuster();
|
||||||
|
}
|
||||||
|
|
||||||
List<XYChart.Data<Number, Number>> getBsqTradeFeeChartData(Predicate<Long> predicate) {
|
List<XYChart.Data<Number, Number>> getBsqTradeFeeChartData(Predicate<Long> predicate) {
|
||||||
return toChartData(daoEconomyDataProvider.getBurnedBsqByMonth(daoStateService.getTradeFeeTxs(), predicate));
|
return toChartData(daoEconomyDataProvider.getBurnedBsqByMonth(daoStateService.getTradeFeeTxs(), predicate));
|
||||||
}
|
}
|
||||||
|
@ -91,6 +104,10 @@ public class DaoEconomyChartModel extends ChartModel {
|
||||||
upperBound = Math.max(xMinMaxTradeFee.second, xMinMaxCompensationRequest.second);
|
upperBound = Math.max(xMinMaxTradeFee.second, xMinMaxCompensationRequest.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long toTimeInterval(Instant ofEpochSecond) {
|
||||||
|
return daoEconomyDataProvider.toTimeInterval(ofEpochSecond);
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Utils
|
// Utils
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
package bisq.desktop.main.dao.economy.supply.chart;
|
package bisq.desktop.main.dao.economy.supply.chart;
|
||||||
|
|
||||||
import bisq.desktop.components.chart.ChartView;
|
import bisq.desktop.components.chart.ChartView;
|
||||||
import bisq.desktop.main.dao.economy.supply.DaoEconomyDataProvider;
|
|
||||||
import bisq.desktop.util.DisplayUtils;
|
import bisq.desktop.util.DisplayUtils;
|
||||||
|
|
||||||
import bisq.core.locale.Res;
|
import bisq.core.locale.Res;
|
||||||
|
@ -32,7 +31,6 @@ import javafx.scene.Node;
|
||||||
import javafx.scene.chart.LineChart;
|
import javafx.scene.chart.LineChart;
|
||||||
import javafx.scene.chart.NumberAxis;
|
import javafx.scene.chart.NumberAxis;
|
||||||
import javafx.scene.chart.XYChart;
|
import javafx.scene.chart.XYChart;
|
||||||
import javafx.scene.control.Tooltip;
|
|
||||||
import javafx.scene.text.Text;
|
import javafx.scene.text.Text;
|
||||||
|
|
||||||
import javafx.geometry.Side;
|
import javafx.geometry.Side;
|
||||||
|
@ -145,8 +143,8 @@ public class DaoEconomyChartView extends ChartView<DaoEconomyChartModel> {
|
||||||
return new StringConverter<>() {
|
return new StringConverter<>() {
|
||||||
@Override
|
@Override
|
||||||
public String toString(Number epochSeconds) {
|
public String toString(Number epochSeconds) {
|
||||||
Date date = new Date(DaoEconomyDataProvider.toStartOfMonth(Instant.ofEpochSecond(epochSeconds.longValue())) * 1000);
|
Date date = new Date(model.toTimeInterval(Instant.ofEpochSecond(epochSeconds.longValue())) * 1000);
|
||||||
return DisplayUtils.formatDateAxis(date, "dd/MMM\nyyyy");
|
return DisplayUtils.formatDateAxis(date, dateFormatPatters);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -171,6 +169,11 @@ public class DaoEconomyChartView extends ChartView<DaoEconomyChartModel> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getTooltipValueConverter(Number value) {
|
||||||
|
return bsqFormatter.formatBSQSatoshisWithCode(value.longValue());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addSeries() {
|
protected void addSeries() {
|
||||||
seriesTotalIssued = new XYChart.Series<>();
|
seriesTotalIssued = new XYChart.Series<>();
|
||||||
|
@ -241,7 +244,9 @@ public class DaoEconomyChartView extends ChartView<DaoEconomyChartModel> {
|
||||||
seriesCompensation.getData().setAll(model.getCompensationChartData(predicate));
|
seriesCompensation.getData().setAll(model.getCompensationChartData(predicate));
|
||||||
|
|
||||||
updateOtherSeries(predicate);
|
updateOtherSeries(predicate);
|
||||||
|
|
||||||
applyTooltip();
|
applyTooltip();
|
||||||
|
applySeriesStyles();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateOtherSeries(Predicate<Long> predicate) {
|
private void updateOtherSeries(Predicate<Long> predicate) {
|
||||||
|
@ -250,22 +255,4 @@ public class DaoEconomyChartView extends ChartView<DaoEconomyChartModel> {
|
||||||
seriesTotalIssued.getData().setAll(model.getTotalIssuedChartData(predicate));
|
seriesTotalIssued.getData().setAll(model.getTotalIssuedChartData(predicate));
|
||||||
seriesTotalBurned.getData().setAll(model.getTotalBurnedChartData(predicate));
|
seriesTotalBurned.getData().setAll(model.getTotalBurnedChartData(predicate));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void applyTooltip() {
|
|
||||||
chart.getData().forEach(series -> {
|
|
||||||
String format = series == seriesCompensation || series == seriesReimbursement || series == seriesTotalIssued ?
|
|
||||||
"dd MMM yyyy" :
|
|
||||||
"MMM yyyy";
|
|
||||||
series.getData().forEach(data -> {
|
|
||||||
String xValue = DisplayUtils.formatDateAxis(new Date(data.getXValue().longValue() * 1000), format);
|
|
||||||
String yValue = bsqFormatter.formatBSQSatoshisWithCode(data.getYValue().longValue());
|
|
||||||
Node node = data.getNode();
|
|
||||||
if (node == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Tooltip.install(node, new Tooltip(Res.get("dao.factsAndFigures.supply.chart.tradeFee.toolTip", yValue, xValue)));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,16 +135,16 @@
|
||||||
-bs-white: white;
|
-bs-white: white;
|
||||||
-bs-prompt-text: -bs-color-gray-3;
|
-bs-prompt-text: -bs-color-gray-3;
|
||||||
-bs-decimals: #db6300;
|
-bs-decimals: #db6300;
|
||||||
-bs-soft-red: #680000;
|
-bs-soft-red: #aa4c3b;
|
||||||
-bs-turquoise-light: #BEDB39;
|
-bs-turquoise-light: #00dcdd;
|
||||||
|
|
||||||
/* dao chart colors */
|
/* dao chart colors */
|
||||||
-bs-chart-dao-line1: -bs-color-green-5;
|
-bs-chart-dao-line1: -bs-color-blue-5;
|
||||||
-bs-chart-dao-line2: -bs-color-blue-2;
|
-bs-chart-dao-line2: -bs-color-green-3;
|
||||||
-bs-chart-dao-line3: -bs-turquoise;
|
-bs-chart-dao-line3: -bs-turquoise;
|
||||||
-bs-chart-dao-line4: -bs-yellow;
|
-bs-chart-dao-line4: -bs-turquoise-light;
|
||||||
-bs-chart-dao-line5: -bs-soft-red;
|
-bs-chart-dao-line5: -bs-yellow;
|
||||||
-bs-chart-dao-line6: -bs-turquoise-light;
|
-bs-chart-dao-line6: -bs-soft-red;
|
||||||
|
|
||||||
/* Monero orange color code */
|
/* Monero orange color code */
|
||||||
-xmr-orange: #f26822;
|
-xmr-orange: #f26822;
|
||||||
|
|
|
@ -102,16 +102,16 @@
|
||||||
-bs-progress-bar-track: #e0e0e0;
|
-bs-progress-bar-track: #e0e0e0;
|
||||||
-bs-white: white;
|
-bs-white: white;
|
||||||
-bs-prompt-text: -fx-control-inner-background;
|
-bs-prompt-text: -fx-control-inner-background;
|
||||||
-bs-soft-red: #E74C3B;
|
-bs-soft-red: #aa4c3b;
|
||||||
-bs-turquoise-light: #00DCFF;
|
-bs-turquoise-light: #00dcdd;
|
||||||
|
|
||||||
/* dao chart colors */
|
/* dao chart colors */
|
||||||
-bs-chart-dao-line1: -bs-color-green-3;
|
-bs-chart-dao-line1: -bs-color-blue-5;
|
||||||
-bs-chart-dao-line2: -bs-color-blue-5;
|
-bs-chart-dao-line2: -bs-color-green-3;
|
||||||
-bs-chart-dao-line3: -bs-turquoise;
|
-bs-chart-dao-line3: -bs-turquoise;
|
||||||
-bs-chart-dao-line4: -bs-yellow;
|
-bs-chart-dao-line4: -bs-turquoise-light;
|
||||||
-bs-chart-dao-line5: -bs-soft-red;
|
-bs-chart-dao-line5: -bs-yellow;
|
||||||
-bs-chart-dao-line6: -bs-turquoise-light;
|
-bs-chart-dao-line6: -bs-soft-red;
|
||||||
|
|
||||||
/* Monero orange color code */
|
/* Monero orange color code */
|
||||||
-xmr-orange: #f26822;
|
-xmr-orange: #f26822;
|
||||||
|
|
Loading…
Add table
Reference in a new issue