Browse Source

Add CheckState icon to check detail view

Armin Schrenk 3 years ago
parent
commit
c0d552da92

+ 11 - 0
src/main/java/org/cryptomator/ui/health/CheckDetailController.java

@@ -3,6 +3,7 @@ package org.cryptomator.ui.health;
 import com.tobiasdiez.easybind.EasyBind;
 import com.tobiasdiez.easybind.EasyObservableList;
 import com.tobiasdiez.easybind.Subscription;
+import com.tobiasdiez.easybind.optional.ObservableOptionalValue;
 import com.tobiasdiez.easybind.optional.OptionalBinding;
 import org.cryptomator.cryptofs.health.api.DiagnosticResult;
 import org.cryptomator.ui.common.FxController;
@@ -21,6 +22,7 @@ import java.util.stream.Stream;
 public class CheckDetailController implements FxController {
 
 	private final EasyObservableList<Result> results;
+	private final ObjectProperty<Check> check;
 	private final OptionalBinding<Check.CheckState> checkState;
 	private final Binding<String> checkName;
 	private final Binding<Boolean> checkRunning;
@@ -34,6 +36,7 @@ public class CheckDetailController implements FxController {
 	private final Binding<Number> countOfCritSeverity;
 	private final ResultListCellFactory resultListCellFactory;
 
+	public CheckStateIconView checkStateIconView;
 	public ListView<Result> resultsListView;
 	private Subscription resultSubscription;
 
@@ -41,6 +44,7 @@ public class CheckDetailController implements FxController {
 	public CheckDetailController(ObjectProperty<Check> selectedTask, ResultListCellFactory resultListCellFactory) {
 		this.resultListCellFactory = resultListCellFactory;
 		this.results = EasyBind.wrapList(FXCollections.observableArrayList());
+		this.check = selectedTask;
 		this.checkState = EasyBind.wrapNullable(selectedTask).mapObservable(Check::stateProperty);
 		this.checkName = EasyBind.wrapNullable(selectedTask).map(Check::getLocalizedName).orElse("");
 		this.checkRunning = checkState.map(Check.CheckState.RUNNING::equals).orElse(false);
@@ -156,4 +160,11 @@ public class CheckDetailController implements FxController {
 		return checkCancelled;
 	}
 
+	public ObjectProperty<Check> checkProperty() {
+		return check;
+	}
+
+	public Check getCheck() {
+		return check.get();
+	}
 }

+ 3 - 30
src/main/java/org/cryptomator/ui/health/CheckListCell.java

@@ -1,10 +1,5 @@
 package org.cryptomator.ui.health;
 
-import com.tobiasdiez.easybind.EasyBind;
-import org.cryptomator.cryptofs.health.api.DiagnosticResult;
-import org.cryptomator.ui.controls.FontAwesome5Icon;
-import org.cryptomator.ui.controls.FontAwesome5IconView;
-
 import javafx.beans.binding.Bindings;
 import javafx.geometry.Insets;
 import javafx.geometry.Pos;
@@ -15,7 +10,7 @@ import javafx.scene.layout.StackPane;
 
 class CheckListCell extends ListCell<Check> {
 
-	private final FontAwesome5IconView stateIcon = new FontAwesome5IconView();
+	private final CheckStateIconView stateIcon = new CheckStateIconView();
 	private CheckBox checkBox = new CheckBox();
 	private final StackPane graphicContainer = new StackPane(stateIcon, checkBox);
 
@@ -27,11 +22,6 @@ class CheckListCell extends ListCell<Check> {
 		graphicContainer.minWidth(20);
 		graphicContainer.maxWidth(20);
 		graphicContainer.setAlignment(Pos.CENTER);
-
-		EasyBind.includeWhen(stateIcon.getStyleClass(), "glyph-icon-muted", stateIcon.glyphProperty().isEqualTo(FontAwesome5Icon.INFO_CIRCLE));
-		EasyBind.includeWhen(stateIcon.getStyleClass(), "glyph-icon-primary", stateIcon.glyphProperty().isEqualTo(FontAwesome5Icon.CHECK));
-		EasyBind.includeWhen(stateIcon.getStyleClass(), "glyph-icon-orange", stateIcon.glyphProperty().isEqualTo(FontAwesome5Icon.EXCLAMATION_TRIANGLE));
-		EasyBind.includeWhen(stateIcon.getStyleClass(), "glyph-icon-red", stateIcon.glyphProperty().isEqualTo(FontAwesome5Icon.TIMES));
 	}
 
 	@Override
@@ -40,36 +30,19 @@ class CheckListCell extends ListCell<Check> {
 		if (item != null) {
 			setText(item.getLocalizedName());
 			setGraphic(graphicContainer);
+			stateIcon.setCheck(item);
 			checkBox.visibleProperty().bind(Bindings.createBooleanBinding(() -> item.getState() == Check.CheckState.RUNNABLE, item.stateProperty()));
 			stateIcon.visibleProperty().bind(Bindings.createBooleanBinding(() -> item.getState() != Check.CheckState.RUNNABLE, item.stateProperty()));
-			stateIcon.glyphProperty().bind(Bindings.createObjectBinding(() -> glyphForState(item), item.stateProperty(), item.highestResultSeverityProperty()));
 			checkBox.selectedProperty().bindBidirectional(item.chosenForExecutionProperty());
 		} else {
 			graphicProperty();
 			checkBox.visibleProperty().unbind();
 			stateIcon.visibleProperty().unbind();
+			stateIcon.setCheck(null);
 			setGraphic(null);
 			setText(null);
 			checkBox.selectedProperty().unbind();
 		}
 	}
 
-	private FontAwesome5Icon glyphForState(Check item) {
-		return switch (item.getState()) {
-			case RUNNABLE -> null;
-			case SKIPPED -> FontAwesome5Icon.FAST_FORWARD;
-			case SCHEDULED -> FontAwesome5Icon.CLOCK;
-			case RUNNING -> FontAwesome5Icon.SPINNER;
-			case ERROR -> FontAwesome5Icon.TIMES;
-			case CANCELLED -> FontAwesome5Icon.BAN;
-			case SUCCEEDED -> {
-				if (item.getHighestResultSeverity() == DiagnosticResult.Severity.INFO || item.getHighestResultSeverity() == DiagnosticResult.Severity.GOOD) {
-					yield FontAwesome5Icon.CHECK;
-				} else {
-					yield FontAwesome5Icon.EXCLAMATION_TRIANGLE;
-				}
-			}
-		};
-	}
-
 }

+ 55 - 0
src/main/java/org/cryptomator/ui/health/CheckStateIconView.java

@@ -0,0 +1,55 @@
+package org.cryptomator.ui.health;
+
+import com.tobiasdiez.easybind.EasyBind;
+import com.tobiasdiez.easybind.optional.OptionalBinding;
+import org.cryptomator.cryptofs.health.api.DiagnosticResult;
+import org.cryptomator.ui.controls.FontAwesome5Icon;
+import org.cryptomator.ui.controls.FontAwesome5IconView;
+
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleObjectProperty;
+import java.util.Optional;
+
+public class CheckStateIconView extends FontAwesome5IconView {
+
+	private final ObjectProperty<Check> check = new SimpleObjectProperty<>();
+	private final OptionalBinding<Check.CheckState> state;
+	private final OptionalBinding<DiagnosticResult.Severity> severity;
+
+	public CheckStateIconView() {
+		super();
+		this.getStyleClass().remove("glyph-icon");
+		this.state = EasyBind.wrapNullable(check).mapObservable(Check::stateProperty);
+		this.severity = EasyBind.wrapNullable(check).mapObservable(Check::highestResultSeverityProperty);
+		glyphProperty().bind(EasyBind.combine(state, severity, this::glyphForState));
+		EasyBind.includeWhen(getStyleClass(), "glyph-icon-muted", glyphProperty().isEqualTo(FontAwesome5Icon.INFO_CIRCLE));
+		EasyBind.includeWhen(getStyleClass(), "glyph-icon-primary", glyphProperty().isEqualTo(FontAwesome5Icon.CHECK));
+		EasyBind.includeWhen(getStyleClass(), "glyph-icon-orange", glyphProperty().isEqualTo(FontAwesome5Icon.EXCLAMATION_TRIANGLE));
+		EasyBind.includeWhen(getStyleClass(), "glyph-icon-red", glyphProperty().isEqualTo(FontAwesome5Icon.TIMES));
+	}
+
+	private FontAwesome5Icon glyphForState(Optional<Check.CheckState> state, Optional<DiagnosticResult.Severity> severity) {
+		return state.map(s -> switch (s) {
+			case RUNNABLE -> null;
+			case SKIPPED -> FontAwesome5Icon.FAST_FORWARD;
+			case SCHEDULED -> FontAwesome5Icon.CLOCK;
+			case RUNNING -> FontAwesome5Icon.SPINNER;
+			case ERROR -> FontAwesome5Icon.TIMES;
+			case CANCELLED -> FontAwesome5Icon.BAN;
+			case SUCCEEDED -> severity.map(se -> DiagnosticResult.Severity.GOOD.compareTo(se) >= 0 ? FontAwesome5Icon.CHECK : FontAwesome5Icon.EXCLAMATION_TRIANGLE).orElse(null);
+		}).orElse(null);
+	}
+
+	public ObjectProperty<Check> checkProperty() {
+		return check;
+	}
+
+	public void setCheck(Check c) {
+		check.set(c);
+	}
+
+	public Check getCheck() {
+		return check.get();
+	}
+
+}

+ 7 - 2
src/main/resources/fxml/health_check_details.fxml

@@ -4,12 +4,17 @@
 <?import javafx.scene.control.Label?>
 <?import javafx.scene.control.ListView?>
 <?import javafx.scene.layout.VBox?>
+<?import org.cryptomator.ui.health.CheckStateIconView?>
 <VBox xmlns:fx="http://javafx.com/fxml"
 	  xmlns="http://javafx.com/javafx"
 	  fx:controller="org.cryptomator.ui.health.CheckDetailController"
 	  prefWidth="500"
 	  spacing="6">
-	<FormattedLabel fx:id="checkTitle" styleClass="label-large" format="%health.check.detail.header" arg1="${controller.checkName}"/>
+	<FormattedLabel fx:id="checkTitle" styleClass="label-large" format="%health.check.detail.header" arg1="${controller.checkName}" contentDisplay="LEFT">
+		<graphic>
+			<CheckStateIconView fx:id="checkStateIconView" check="${controller.check}" glyphSize="20"/>
+		</graphic>
+	</FormattedLabel>
 
 	<Label text="%health.check.detail.checkRunning" visible="${controller.checkRunning}" managed="${controller.checkRunning}"/>
 	<Label text="%health.check.detail.checkScheduled" visible="${controller.checkScheduled}" managed="${controller.checkScheduled}"/>
@@ -19,6 +24,6 @@
 	<Label text="%health.check.detail.checkSucceeded" visible="${controller.checkSucceeded}" managed="${controller.checkSucceeded}"/>
 
 	<FormattedLabel styleClass="label" format="%health.check.detail.problemCount" arg1="${controller.countOfWarnSeverity}" arg2="${controller.countOfCritSeverity}" visible="${!controller.checkSkipped}"
-					 managed="${!controller.checkSkipped}"	/>
+					managed="${!controller.checkSkipped}"/>
 	<ListView fx:id="resultsListView" VBox.vgrow="ALWAYS" visible="${!controller.checkSkipped}"/>
 </VBox>