mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-18 18:51:26 +00:00
Updated Graph to use Timeline + minor UI changes + wording
This commit is contained in:
@@ -1,13 +1,16 @@
|
||||
package org.cryptomator.ui.vaultstatistics;
|
||||
|
||||
import javafx.beans.property.LongProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||
import javafx.beans.property.SimpleLongProperty;
|
||||
import javafx.animation.Animation;
|
||||
import javafx.animation.KeyFrame;
|
||||
import javafx.animation.Timeline;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.chart.LineChart;
|
||||
import javafx.scene.chart.XYChart;
|
||||
import javafx.scene.chart.XYChart.Data;
|
||||
import javafx.scene.chart.XYChart.Series;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.util.Duration;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
|
||||
@@ -16,54 +19,85 @@ import javax.inject.Inject;
|
||||
@VaultStatisticsScoped
|
||||
public class VaultStatisticsController implements FxController {
|
||||
|
||||
private static final int IO_SAMPLING_STEPS = 100;
|
||||
private static final double IO_SAMPLING_INTERVAL = 0.5;
|
||||
|
||||
private final Stage window;
|
||||
private final ReadOnlyObjectProperty<Vault> vault;
|
||||
private final Vault vault;
|
||||
@FXML
|
||||
private LineChart<Double, Double> lineGraph;
|
||||
private final LongProperty currentReadData;
|
||||
private final LongProperty currentWriteData;
|
||||
private final XYChart.Series<Double, Double> readData;
|
||||
private final XYChart.Series<Double, Double> writeData;
|
||||
private long timeAtStartOfTracking;
|
||||
private LineChart<Number, Number> lineGraph;
|
||||
private final Series<Number, Number> readData;
|
||||
private final Series<Number, Number> writeData;
|
||||
private Timeline ioAnimation;
|
||||
|
||||
|
||||
@Inject
|
||||
public VaultStatisticsController(@VaultStatisticsWindow Stage window, ObjectProperty<Vault> vault) {
|
||||
public VaultStatisticsController(@VaultStatisticsWindow Stage window, @VaultStatisticsWindow Vault vault) {
|
||||
this.window = window;
|
||||
this.vault = vault;
|
||||
|
||||
readData = new XYChart.Series<>();
|
||||
readData = new Series<>();
|
||||
readData.setName("Read Data"); // For Legend
|
||||
//TODO Add Name to strings.properties
|
||||
writeData = new XYChart.Series<>();
|
||||
writeData = new Series<>();
|
||||
writeData.setName("Write Data");
|
||||
//TODO Add Name to strings.properties
|
||||
|
||||
|
||||
currentReadData = new SimpleLongProperty();
|
||||
currentReadData.bind(getVault().getStats().bytesPerSecondReadProperty());
|
||||
currentReadData.addListener((observable, oldValue, newValue) -> updateReadWriteData());
|
||||
|
||||
currentWriteData = new SimpleLongProperty();
|
||||
currentWriteData.bind(getVault().getStats().bytesPerSecondWrittenProperty());
|
||||
currentWriteData.addListener((observable, oldValue, newValue) -> updateReadWriteData());
|
||||
ioAnimation = new Timeline(); //TODO Research better timer
|
||||
ioAnimation.getKeyFrames().add(new KeyFrame(Duration.seconds(IO_SAMPLING_INTERVAL), new IoSamplingAnimationHandler(readData, writeData)));
|
||||
ioAnimation.setCycleCount(Animation.INDEFINITE);
|
||||
ioAnimation.play();
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
window.setTitle(window.getTitle() + " - " + vault.get().getDisplayableName());
|
||||
lineGraph.getData().addAll(writeData, readData);
|
||||
lineGraph.getData().addAll(readData, writeData);
|
||||
}
|
||||
|
||||
private class IoSamplingAnimationHandler implements EventHandler<ActionEvent> {
|
||||
|
||||
private static final double BYTES_TO_MEGABYTES_FACTOR = 1.0 / IO_SAMPLING_INTERVAL / 1024.0 / 1024.0;
|
||||
private final Series<Number, Number> decryptedBytesRead;
|
||||
private final Series<Number, Number> encryptedBytesWrite;
|
||||
|
||||
public IoSamplingAnimationHandler(Series<Number, Number> readData, Series<Number, Number> writeData) {
|
||||
this.decryptedBytesRead = readData;
|
||||
this.encryptedBytesWrite = writeData;
|
||||
|
||||
// initialize data once and change value of datapoints later:
|
||||
for (int i = 0; i < IO_SAMPLING_STEPS; i++) {
|
||||
decryptedBytesRead.getData().add(new Data<>(i, 0));
|
||||
encryptedBytesWrite.getData().add(new Data<>(i, 0));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(ActionEvent event) {
|
||||
// move all values one step:
|
||||
for (int i = 0; i < IO_SAMPLING_STEPS - 1; i++) {
|
||||
int j = i + 1;
|
||||
Number tmp = decryptedBytesRead.getData().get(j).getYValue();
|
||||
decryptedBytesRead.getData().get(i).setYValue(tmp);
|
||||
|
||||
tmp = encryptedBytesWrite.getData().get(j).getYValue();
|
||||
encryptedBytesWrite.getData().get(i).setYValue(tmp);
|
||||
}
|
||||
|
||||
// add latest value:
|
||||
final long decBytes = vault.getStats().bytesPerSecondReadProperty().get();
|
||||
final double decMb = decBytes * BYTES_TO_MEGABYTES_FACTOR;
|
||||
final long encBytes = vault.getStats().bytesPerSecondWrittenProperty().get();
|
||||
final double encMb = encBytes * BYTES_TO_MEGABYTES_FACTOR;
|
||||
decryptedBytesRead.getData().get(IO_SAMPLING_STEPS - 1).setYValue(decMb);
|
||||
encryptedBytesWrite.getData().get(IO_SAMPLING_STEPS - 1).setYValue(encMb);
|
||||
}
|
||||
}
|
||||
|
||||
public Vault getVault() {
|
||||
return vault.get();
|
||||
}
|
||||
|
||||
private void updateReadWriteData() {
|
||||
//So the graphs start at x = 0
|
||||
if (timeAtStartOfTracking == 0) {
|
||||
timeAtStartOfTracking = System.currentTimeMillis();
|
||||
}
|
||||
readData.getData().add(new XYChart.Data<Double, Double>((System.currentTimeMillis() - timeAtStartOfTracking) / 1000.0, ((getVault().getStats().bytesPerSecondReadProperty().get()) / 1024.0)));
|
||||
writeData.getData().add(new XYChart.Data<Double, Double>((System.currentTimeMillis() - timeAtStartOfTracking) / 1000.0, ((getVault().getStats().bytesPerSecondWrittenProperty().get()) / 1024.0)));
|
||||
return vault;
|
||||
}
|
||||
/*
|
||||
public ReadOnlyObjectProperty<Vault> vaultProperty() {
|
||||
return vault;
|
||||
}*/
|
||||
}
|
||||
|
||||
@@ -4,9 +4,12 @@ import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.common.vaults.VaultState;
|
||||
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||
import org.cryptomator.ui.common.FXMLLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
@@ -14,7 +17,6 @@ import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.common.StageFactory;
|
||||
import org.cryptomator.ui.mainwindow.MainWindow;
|
||||
|
||||
import javax.inject.Provider;
|
||||
import java.util.Map;
|
||||
@@ -33,12 +35,19 @@ abstract class VaultStatisticsModule {
|
||||
@Provides
|
||||
@VaultStatisticsWindow
|
||||
@VaultStatisticsScoped
|
||||
static Stage provideStage(StageFactory factory, @MainWindow Stage owner, ResourceBundle resourceBundle) {
|
||||
static Stage provideStage(StageFactory factory, ResourceBundle resourceBundle, @VaultStatisticsWindow Vault vault) {
|
||||
Stage stage = factory.create();
|
||||
stage.setTitle(resourceBundle.getString("vaultstatistics.title"));
|
||||
stage.setTitle(String.format(resourceBundle.getString("vaultstatistics.title"), vault.getDisplayableName()));
|
||||
stage.setResizable(false);
|
||||
stage.initModality(Modality.NONE);
|
||||
stage.initOwner(owner);
|
||||
vault.stateProperty().addListener(new ChangeListener<>() {
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends VaultState> observable, VaultState oldValue, VaultState newValue) {
|
||||
if (newValue != VaultState.UNLOCKED) {
|
||||
stage.hide();
|
||||
observable.removeListener(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
return stage;
|
||||
}
|
||||
|
||||
|
||||
@@ -869,3 +869,56 @@
|
||||
-fx-background-color: PROGRESS_BAR_BG;
|
||||
-fx-background-radius: 4px;
|
||||
}
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* I/O Statistics *
|
||||
* *
|
||||
******************************************************************************/
|
||||
.chart {
|
||||
-fx-padding: 10px;
|
||||
}
|
||||
|
||||
.chart-plot-background {
|
||||
-fx-background-color: MAIN_BG;
|
||||
-fx-padding: 20px;
|
||||
}
|
||||
/*
|
||||
.default-color0.chart-line-symbol { -fx-background-color: #00FFFF; }
|
||||
.default-color1.chart-line-symbol { -fx-background-color: #00FF00; }
|
||||
*/
|
||||
/* content */
|
||||
|
||||
.chart-content {
|
||||
-fx-padding: 10px;
|
||||
}
|
||||
.chart-horizontal-grid-lines {
|
||||
-fx-stroke: #FFFFFF;
|
||||
}
|
||||
.chart-vertical-zero-line,
|
||||
.chart-horizontal-zero-line {
|
||||
-fx-stroke: #FFFFFF;
|
||||
}
|
||||
.chart-series-line {
|
||||
-fx-stroke-width: 2px;
|
||||
}
|
||||
.chart-alternative-row-fill {
|
||||
-fx-fill: #E1E1E1;
|
||||
-fx-stroke: transparent;
|
||||
-fx-stroke-width: 0;
|
||||
}
|
||||
|
||||
.default-color0.chart-series-line { -fx-stroke: #FF0000; }
|
||||
.default-color1.chart-series-line { -fx-stroke: #00FF00 ; }
|
||||
|
||||
.chart-legend {
|
||||
-fx-background-color: transparent;
|
||||
-fx-padding: 20px;
|
||||
}
|
||||
|
||||
.chart-legend-item-symbol{
|
||||
-fx-background-radius: 10;
|
||||
}
|
||||
|
||||
.chart-legend-item{
|
||||
-fx-text-fill: #FFFFFF;
|
||||
}
|
||||
|
||||
@@ -870,25 +870,44 @@
|
||||
}
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Vault Statistics *
|
||||
* I/O Statistics *
|
||||
* *
|
||||
******************************************************************************/
|
||||
.chart-plot-background {
|
||||
-fx-background-color: #F7F7F7;
|
||||
.chart {
|
||||
-fx-padding: 10px;
|
||||
}
|
||||
.chart-vertical-grid-lines {
|
||||
-fx-stroke: #49B04A;
|
||||
|
||||
.chart-plot-background {
|
||||
-fx-background-color: MAIN_BG;
|
||||
-fx-padding: 20px;
|
||||
}
|
||||
/*
|
||||
.default-color0.chart-line-symbol { -fx-background-color: #00FFFF; }
|
||||
.default-color1.chart-line-symbol { -fx-background-color: #00FF00; }
|
||||
*/
|
||||
/* content */
|
||||
|
||||
.chart-content {
|
||||
-fx-padding: 10px;
|
||||
}
|
||||
.chart-horizontal-grid-lines {
|
||||
-fx-stroke: #49B04A;
|
||||
-fx-stroke: #000000;
|
||||
}
|
||||
.chart-vertical-zero-line,
|
||||
.chart-horizontal-zero-line {
|
||||
-fx-stroke: #000000;
|
||||
}
|
||||
.chart-series-line {
|
||||
-fx-stroke-width: 2px;
|
||||
}
|
||||
.chart-alternative-row-fill {
|
||||
-fx-fill: #E1E1E1;
|
||||
-fx-stroke: transparent;
|
||||
-fx-stroke-width: 0;
|
||||
}
|
||||
.default-color0.chart-series-line { -fx-stroke: #2D4D2E; }
|
||||
.default-color1.chart-series-line { -fx-stroke: #66CC68 ; }
|
||||
|
||||
.default-color0.chart-series-line { -fx-stroke: #FF0000; }
|
||||
.default-color1.chart-series-line { -fx-stroke: #00FF00 ; }
|
||||
|
||||
.chart-legend {
|
||||
-fx-background-color: transparent;
|
||||
@@ -896,9 +915,9 @@
|
||||
}
|
||||
|
||||
.chart-legend-item-symbol{
|
||||
-fx-background-radius: 0;
|
||||
-fx-background-radius: 10;
|
||||
}
|
||||
|
||||
.chart-legend-item{
|
||||
-fx-text-fill: #191970;
|
||||
-fx-text-fill: #000000;
|
||||
}
|
||||
|
||||
@@ -25,14 +25,13 @@
|
||||
</HBox>
|
||||
|
||||
<LineChart
|
||||
styleClass="chart-plot-background, chart-vertical-grid-lines, chart-horizontal-grid-lines, chart-alternative-row-fill, default-color0.chart-series-line, default-color1.chart-series-line, default-color2.chart-series-line, chart-legend, chart-legend-item-symbol, chart-legend-item"
|
||||
fx:id="lineGraph" createSymbols="true" legendVisible="true" prefHeight="372.0" prefWidth="423.0" visible="true" animated="false" horizontalGridLinesVisible="true" verticalGridLinesVisible="true"
|
||||
title="%vaultstatistics.throughputTitle">
|
||||
styleClass="chart-plot-background, chart-alternative-row-fill, default-color2.chart-series-line"
|
||||
fx:id="lineGraph" createSymbols="true" legendVisible="true" prefHeight="372.0" prefWidth="423.0" visible="true" animated="false" title="%vaultstatistics.throughputTitle" verticalZeroLineVisible="true" verticalGridLinesVisible="false" horizontalGridLinesVisible="true">
|
||||
<xAxis>
|
||||
<NumberAxis autoRanging="true" lowerBound="0" side="BOTTOM" tickUnit="1" upperBound="10" label="%vaultstatistics.xAxisTimeLabel"/>
|
||||
<NumberAxis autoRanging="false" lowerBound="0" side="BOTTOM" tickUnit="5" upperBound="100" label="%vaultstatistics.xAxisTimeLabel"/>
|
||||
</xAxis>
|
||||
<yAxis>
|
||||
<NumberAxis autoRanging="true" lowerBound="0" side="LEFT" tickUnit="1024" upperBound="100" label="%vaultstatistics.yAxisTimeLabel"/>
|
||||
<NumberAxis autoRanging="true" lowerBound="0" side="LEFT" tickUnit="1024" upperBound="100" label="%vaultstatistics.yAxisThroughputLabel" forceZeroInRange="true"/>
|
||||
</yAxis>
|
||||
<cursor>
|
||||
<Cursor fx:constant="DEFAULT"/>
|
||||
|
||||
@@ -161,9 +161,9 @@ preferences.donationKey.getDonationKey=Get a donation key
|
||||
preferences.about=About
|
||||
|
||||
# Vault Statistics
|
||||
vaultstatistics.title=Vault Statistics
|
||||
vaultstatistics.title=Statistics for %s
|
||||
vaultstatistics.xAxisTimeLabel=Seconds
|
||||
vaultstatistics.yAxisTimeLabel=Throughput in KiB
|
||||
vaultstatistics.yAxisThroughputLabel=Throughput in KiB/s
|
||||
vaultstatistics.throughputTitle=Read and Writes
|
||||
|
||||
# Main Window
|
||||
|
||||
Reference in New Issue
Block a user