Browse Source

improve health check gui:
* convert milliseconds to hours, minutes and seconds
* spelling
* adjust to dark theme

Armin Schrenk 4 years ago
parent
commit
903f55a24f

+ 28 - 7
src/main/java/org/cryptomator/ui/health/CheckDetailController.java

@@ -15,6 +15,8 @@ import javafx.collections.FXCollections;
 import javafx.concurrent.Worker;
 import javafx.fxml.FXML;
 import javafx.scene.control.ListView;
+import java.time.Duration;
+import java.util.ResourceBundle;
 import java.util.function.Function;
 import java.util.stream.Stream;
 
@@ -24,8 +26,7 @@ public class CheckDetailController implements FxController {
 	private final EasyObservableList<DiagnosticResult> results;
 	private final OptionalBinding<Worker.State> taskState;
 	private final Binding<String> taskName;
-	private final Binding<Number> taskDuration;
-	private final ResultListCellFactory resultListCellFactory;
+	private final Binding<String> taskDuration;
 	private final Binding<Boolean> taskRunning;
 	private final Binding<Boolean> taskScheduled;
 	private final Binding<Boolean> taskFinished;
@@ -35,17 +36,20 @@ public class CheckDetailController implements FxController {
 	private final Binding<Boolean> taskCancelled;
 	private final Binding<Number> countOfWarnSeverity;
 	private final Binding<Number> countOfCritSeverity;
+	private final ResultListCellFactory resultListCellFactory;
+	private final ResourceBundle resourceBundle;
 
 	public ListView<DiagnosticResult> resultsListView;
 	private Subscription resultSubscription;
 
 	@Inject
-	public CheckDetailController(ObjectProperty<HealthCheckTask> selectedTask, ResultListCellFactory resultListCellFactory) {
+	public CheckDetailController(ObjectProperty<HealthCheckTask> selectedTask, ResultListCellFactory resultListCellFactory, ResourceBundle resourceBundle) {
+		this.resultListCellFactory = resultListCellFactory;
+		this.resourceBundle = resourceBundle;
 		this.results = EasyBind.wrapList(FXCollections.observableArrayList());
 		this.taskState = EasyBind.wrapNullable(selectedTask).mapObservable(HealthCheckTask::stateProperty);
 		this.taskName = EasyBind.wrapNullable(selectedTask).map(HealthCheckTask::getTitle).orElse("");
-		this.taskDuration = EasyBind.wrapNullable(selectedTask).mapObservable(HealthCheckTask::durationInMillisProperty).orElse(-1L);
-		this.resultListCellFactory = resultListCellFactory;
+		this.taskDuration = EasyBind.wrapNullable(selectedTask).mapObservable(HealthCheckTask::durationInMillisProperty).orElse(-1L).map(this::millisToReadAbleDuration);
 		this.taskRunning = EasyBind.wrapNullable(selectedTask).mapObservable(HealthCheckTask::runningProperty).orElse(false); //TODO: DOES NOT WORK
 		this.taskScheduled = taskState.map(Worker.State.SCHEDULED::equals).orElse(false);
 		this.taskNotStarted = taskState.map(Worker.State.READY::equals).orElse(false);
@@ -87,11 +91,11 @@ public class CheckDetailController implements FxController {
 		return taskName;
 	}
 
-	public Number getTaskDuration() {
+	public String getTaskDuration() {
 		return taskDuration.getValue();
 	}
 
-	public Binding<Number> taskDurationProperty() {
+	public Binding<String> taskDurationProperty() {
 		return taskDuration;
 	}
 
@@ -167,4 +171,21 @@ public class CheckDetailController implements FxController {
 		return taskCancelled;
 	}
 
+	private String millisToReadAbleDuration(Number millis) {
+		Duration tmp = Duration.ofMillis(millis.longValue());
+		long hours = tmp.toHoursPart();
+		long minutes = tmp.toMinutesPart();
+		long seconds = tmp.toSecondsPart();
+		if (hours != 0) {
+			String hms_format = resourceBundle.getString("health.check.detail.hmsFormat");
+			return String.format(hms_format, hours, minutes, seconds);
+		} else if (minutes != 0) {
+			String ms_format = resourceBundle.getString("health.check.detail.msFormat");
+			return String.format(ms_format, minutes, seconds);
+		} else {
+			String s_format = resourceBundle.getString("health.check.detail.sFormat");
+			return String.format(s_format, seconds);
+		}
+	}
+
 }

+ 55 - 4
src/main/java/org/cryptomator/ui/health/CheckListCell.java

@@ -4,35 +4,81 @@ import org.cryptomator.ui.controls.FontAwesome5Icon;
 import org.cryptomator.ui.controls.FontAwesome5IconView;
 
 import javafx.beans.binding.Bindings;
+import javafx.beans.property.BooleanProperty;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleObjectProperty;
 import javafx.beans.value.ObservableValue;
 import javafx.concurrent.Worker;
 import javafx.geometry.Insets;
 import javafx.geometry.Pos;
 import javafx.scene.Node;
+import javafx.scene.control.CheckBox;
 import javafx.scene.control.ContentDisplay;
 import javafx.scene.control.ListCell;
+import javafx.util.Callback;
 
 class CheckListCell extends ListCell<HealthCheckTask> {
 
 	private final FontAwesome5IconView stateIcon = new FontAwesome5IconView();
+	private final Callback<HealthCheckTask, BooleanProperty> selectedGetter;
+	private final ObjectProperty<State> stateProperty;
 
-	CheckListCell() {
+	private CheckBox checkBox = new CheckBox();
+	private BooleanProperty selectedProperty;
+
+	CheckListCell(Callback<HealthCheckTask, BooleanProperty> selectedGetter, ObservableValue<Boolean> switchIndicator) {
+		this.selectedGetter = selectedGetter;
+		this.stateProperty = new SimpleObjectProperty<>(State.SELECTION);
+		switchIndicator.addListener(this::changeState);
 		setPadding(new Insets(6));
 		setAlignment(Pos.CENTER_LEFT);
 		setContentDisplay(ContentDisplay.LEFT);
+		getStyleClass().add("label");
+	}
+
+	private void changeState(ObservableValue<? extends Boolean> observableValue, boolean oldValue, boolean newValue) {
+		if (newValue) {
+			stateProperty.set(State.RUN);
+		} else {
+			stateProperty.set(State.SELECTION);
+		}
 	}
 
 	@Override
 	protected void updateItem(HealthCheckTask item, boolean empty) {
 		super.updateItem(item, empty);
+		if (item != null) {
+			setText(item.getTitle());
+		}
+		switch (stateProperty.get()) {
+			case SELECTION -> updateItemSelection(item, empty);
+			case RUN -> updateItemRun(item, empty);
+		}
+	}
 
+	private void updateItemSelection(HealthCheckTask item, boolean empty) {
+		if (!empty) {
+			setGraphic(checkBox);
+
+			if (selectedProperty != null) {
+				checkBox.selectedProperty().unbindBidirectional(selectedProperty);
+			}
+			selectedProperty = selectedGetter.call(item);
+			if (selectedProperty != null) {
+				checkBox.selectedProperty().bindBidirectional(selectedProperty);
+			}
+		} else {
+			setGraphic(null);
+			setText(null);
+		}
+	}
+
+	private void updateItemRun(HealthCheckTask item, boolean empty) {
 		if (item != null) {
-			textProperty().bind(item.titleProperty());
 			item.stateProperty().addListener(this::stateChanged);
-			graphicProperty().bind(Bindings.createObjectBinding(() -> graphicForState(item.getState()),item.stateProperty()));
+			graphicProperty().bind(Bindings.createObjectBinding(() -> graphicForState(item.getState()), item.stateProperty()));
 			stateIcon.setGlyph(glyphForState(item.getState()));
 		} else {
-			textProperty().unbind();
 			graphicProperty().unbind();
 			setGraphic(null);
 			setText(null);
@@ -61,4 +107,9 @@ class CheckListCell extends ListCell<HealthCheckTask> {
 			case SUCCEEDED -> FontAwesome5Icon.CHECK;
 		};
 	}
+
+	private enum State {
+		SELECTION,
+		RUN;
+	}
 }

+ 2 - 12
src/main/java/org/cryptomator/ui/health/CheckListController.java

@@ -84,17 +84,7 @@ public class CheckListController implements FxController {
 	@FXML
 	public void initialize() {
 		checksListView.setItems(tasks);
-		checksListView.setCellFactory(CheckBoxListCell.forListView(listPickIndicators::get, new StringConverter<HealthCheckTask>() {
-			@Override
-			public String toString(HealthCheckTask object) {
-				return object.getTitle();
-			}
-
-			@Override
-			public HealthCheckTask fromString(String string) {
-				return null;
-			}
-		}));
+		checksListView.setCellFactory(view -> new CheckListCell(listPickIndicators::get, showResultScreen));
 		selectedTask.bind(checksListView.getSelectionModel().selectedItemProperty());
 	}
 
@@ -115,7 +105,7 @@ public class CheckListController implements FxController {
 		runningTask.set(batchService);
 		showResultScreen.set(true);
 		checksListView.getSelectionModel().select(batch.get(0));
-		checksListView.setCellFactory(view -> new CheckListCell());
+		checksListView.refresh();
 		window.sizeToScene();
 	}
 

+ 5 - 2
src/main/resources/i18n/strings.properties

@@ -153,19 +153,22 @@ health.start.configValid=Reading and parsing vault configuration file was succes
 health.start.configInvalid=Error while reading and parsing the vault configuration file.
 health.checkList.header=Available Health Checks
 health.checkList.selectAllBox=Select All
-health.check.runBatchBtn=Run selected Checks
+health.check.runBatchBtn=Run Selected Checks
 ## Detail view
 health.check.detail.noSelectedCheck=For results select a finished health check in the left list.
 health.check.detail.header=Results of %s
 health.check.detail.taskNotStarted=The check was not selected to run.
 health.check.detail.taskScheduled=The check is scheduled.
 health.check.detail.taskRunning=The check is currently running…
-health.check.detail.taskSucceeded=The check finished successfully after %d milliseconds.
+health.check.detail.taskSucceeded=The check finished successfully after %s.
 health.check.detail.taskFailed=The check exited due to an error.
 health.check.detail.taskCancelled=The check was cancelled.
 health.check.detail.problemCount=Found %d problems and %d unfixable errors.
 health.check.exportBtn=Export Report
 health.check.fixBtn=Fix
+health.check.detail.hmsFormat= %d hours, %2d minutes and %2d seconds
+health.check.detail.msFormat= %d minutes and %2d seconds
+health.check.detail.sFormat= %d seconds
 ## Checks
 health.org.cryptomator.cryptofs.health.dirid.DirIdCheck=Directory Check