make the view depend on state, not on another view

This commit is contained in:
Sebastian Stenzel
2021-07-21 10:43:10 +02:00
parent 7a1b1292ae
commit 9f7c69388c
4 changed files with 57 additions and 37 deletions

View File

@@ -21,8 +21,8 @@ public class FontAwesome5IconView extends Text {
private static final String FONT_PATH = "/css/fontawesome5-free-solid.otf";
private static final Font FONT;
private final ObjectProperty<FontAwesome5Icon> glyph = new SimpleObjectProperty<>(this, "glyph", DEFAULT_GLYPH);
private final DoubleProperty glyphSize = new SimpleDoubleProperty(this, "glyphSize", DEFAULT_GLYPH_SIZE);
protected final ObjectProperty<FontAwesome5Icon> glyph = new SimpleObjectProperty<>(this, "glyph", DEFAULT_GLYPH);
protected final DoubleProperty glyphSize = new SimpleDoubleProperty(this, "glyphSize", DEFAULT_GLYPH_SIZE);
static {
try {

View File

@@ -2,48 +2,62 @@ package org.cryptomator.ui.health;
import com.tobiasdiez.easybind.EasyBind;
import com.tobiasdiez.easybind.Subscription;
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.binding.Bindings;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableObjectValue;
import java.util.List;
import java.util.Optional;
/**
* A {@link FontAwesome5IconView} that automatically sets the glyph depending on
* the {@link Check#stateProperty() state} and {@link Check#highestResultSeverityProperty() severity} of a HealthCheck.
*/
public class CheckStateIconView extends FontAwesome5IconView {
private final static List<FontAwesome5Icon> ATTENTION_ICONS = List.of(FontAwesome5Icon.CHECK, FontAwesome5Icon.EXCLAMATION_TRIANGLE, FontAwesome5Icon.TIMES);
private final ObjectProperty<Check> check = new SimpleObjectProperty<>();
private final OptionalBinding<Check.CheckState> state;
private final OptionalBinding<DiagnosticResult.Severity> severity;
private List<Subscription> subscriptions;
private final ObservableObjectValue<Check.CheckState> state;
private final ObservableObjectValue<DiagnosticResult.Severity> severity;
private final List<Subscription> subscriptions;
public CheckStateIconView() {
super();
this.state = EasyBind.wrapNullable(check).mapObservable(Check::stateProperty);
this.severity = EasyBind.wrapNullable(check).mapObservable(Check::highestResultSeverityProperty);
glyphProperty().bind(EasyBind.combine(state, severity, this::glyphForState)); //TODO: does the binding need to be stored?
this.state = EasyBind.wrapNullable(check).mapObservable(Check::stateProperty).asOrdinary();
this.severity = EasyBind.wrapNullable(check).mapObservable(Check::highestResultSeverityProperty).asOrdinary();
this.glyph.bind(Bindings.createObjectBinding(this::glyphForState, state, severity));
this.subscriptions = List.of(
EasyBind.includeWhen(getStyleClass(), "glyph-icon-muted", EasyBind.map(glyphProperty(), glyph -> glyph == null || !ATTENTION_ICONS.contains(glyph))),
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))
//EasyBind.includeWhen(getStyleClass(), "glyph-icon-muted", Bindings.notEqual(state, Check.CheckState.ERROR).and(Bindings.isNull(severity))), // TODO not really needed, right?
EasyBind.includeWhen(getStyleClass(), "glyph-icon-primary", Bindings.equal(severity, DiagnosticResult.Severity.GOOD)), //
EasyBind.includeWhen(getStyleClass(), "glyph-icon-orange", Bindings.equal(severity, DiagnosticResult.Severity.WARN)), //
EasyBind.includeWhen(getStyleClass(), "glyph-icon-red", Bindings.equal(severity, DiagnosticResult.Severity.CRITICAL).or(Bindings.equal(state, Check.CheckState.ERROR))) //
);
}
private FontAwesome5Icon glyphForState(Optional<Check.CheckState> state, Optional<DiagnosticResult.Severity> severity) {
return state.map(s -> switch (s) {
private FontAwesome5Icon glyphForState() {
if (state.getValue() == null) {
return null;
}
return switch (state.getValue()) {
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);
case SUCCEEDED -> glyphIconForSeverity();
};
}
private FontAwesome5Icon glyphIconForSeverity() {
if (severity.getValue() == null) {
return null;
}
return switch (severity.getValue()) {
case GOOD, INFO -> FontAwesome5Icon.CHECK;
case WARN, CRITICAL -> FontAwesome5Icon.EXCLAMATION_TRIANGLE;
};
}
public ObjectProperty<Check> checkProperty() {

View File

@@ -2,7 +2,7 @@ package org.cryptomator.ui.health;
import com.tobiasdiez.easybind.EasyBind;
import com.tobiasdiez.easybind.Subscription;
import com.tobiasdiez.easybind.optional.OptionalBinding;
import org.cryptomator.cryptofs.health.api.DiagnosticResult;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.controls.FontAwesome5Icon;
import org.cryptomator.ui.controls.FontAwesome5IconView;
@@ -17,6 +17,7 @@ import javafx.beans.binding.BooleanBinding;
import javafx.beans.binding.ObjectBinding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableObjectValue;
import javafx.fxml.FXML;
import javafx.scene.control.Tooltip;
import javafx.util.Duration;
@@ -35,9 +36,10 @@ public class ResultListCellController implements FxController {
private final Logger LOG = LoggerFactory.getLogger(ResultListCellController.class);
private final ObjectProperty<Result> result;
private final ObservableObjectValue<DiagnosticResult.Severity> severity;
private final Binding<String> description;
private final ResultFixApplier fixApplier;
private final OptionalBinding<Result.FixState> fixState;
private final ObservableObjectValue<Result.FixState> fixState;
private final ObjectBinding<FontAwesome5Icon> severityGlyph;
private final ObjectBinding<FontAwesome5Icon> fixGlyph;
private final BooleanBinding fixable;
@@ -56,9 +58,10 @@ public class ResultListCellController implements FxController {
@Inject
public ResultListCellController(ResultFixApplier fixApplier, ResourceBundle resourceBundle) {
this.result = new SimpleObjectProperty<>(null);
this.severity = EasyBind.wrapNullable(result).map(r -> r.diagnosis().getSeverity()).asOrdinary();
this.description = EasyBind.wrapNullable(result).map(Result::getDescription).orElse("");
this.fixApplier = fixApplier;
this.fixState = EasyBind.wrapNullable(result).mapObservable(Result::fixState);
this.fixState = EasyBind.wrapNullable(result).mapObservable(Result::fixState).asOrdinary();
this.severityGlyph = Bindings.createObjectBinding(this::getSeverityGlyph, result);
this.fixGlyph = Bindings.createObjectBinding(this::getFixGlyph, fixState);
this.fixable = Bindings.createBooleanBinding(this::isFixable, fixState);
@@ -76,12 +79,12 @@ public class ResultListCellController implements FxController {
@FXML
public void initialize() {
// see getGlyph() for relevant glyphs:
subscriptions.addAll(List.of(EasyBind.includeWhen(severityView.getStyleClass(), "glyph-icon-muted", severityView.glyphProperty().isEqualTo(INFO_ICON)), //
EasyBind.includeWhen(severityView.getStyleClass(), "glyph-icon-primary", severityView.glyphProperty().isEqualTo(GOOD_ICON)), //
EasyBind.includeWhen(severityView.getStyleClass(), "glyph-icon-orange", severityView.glyphProperty().isEqualTo(WARN_ICON)), //
EasyBind.includeWhen(severityView.getStyleClass(), "glyph-icon-red", severityView.glyphProperty().isEqualTo(CRIT_ICON)), //
EasyBind.includeWhen(fixView.getStyleClass(), "glyph-icon-muted", fixView.glyphProperty().isNotNull())) //
);
subscriptions.addAll(List.of(EasyBind.includeWhen(severityView.getStyleClass(), "glyph-icon-muted", Bindings.equal(severity, DiagnosticResult.Severity.INFO)), //
EasyBind.includeWhen(severityView.getStyleClass(), "glyph-icon-primary", Bindings.equal(severity, DiagnosticResult.Severity.GOOD)), //
EasyBind.includeWhen(severityView.getStyleClass(), "glyph-icon-orange", Bindings.equal(severity, DiagnosticResult.Severity.WARN)), //
EasyBind.includeWhen(severityView.getStyleClass(), "glyph-icon-red", Bindings.equal(severity, DiagnosticResult.Severity.CRITICAL)) //
// EasyBind.includeWhen(fixView.getStyleClass(), "glyph-icon-muted", fixView.glyphProperty().isNotNull())) // TODO not really needed, right?
));
}
@FXML
@@ -146,12 +149,15 @@ public class ResultListCellController implements FxController {
}
public FontAwesome5Icon getFixGlyph() {
return fixState.get().map(s -> switch (s) {
if (fixState.getValue() == null) {
return null;
}
return switch (fixState.getValue()) {
case NOT_FIXABLE, FIXABLE -> null;
case FIXING -> FontAwesome5Icon.SPINNER;
case FIXED -> FontAwesome5Icon.CHECK;
case FIX_FAILED -> FontAwesome5Icon.TIMES;
}).orElse(null);
};
}
public BooleanBinding fixableProperty() {
@@ -159,7 +165,7 @@ public class ResultListCellController implements FxController {
}
public boolean isFixable() {
return fixState.get().map(Result.FixState.FIXABLE::equals).orElse(false);
return Result.FixState.FIXABLE.equals(fixState.get());
}
public BooleanBinding fixingProperty() {
@@ -167,7 +173,7 @@ public class ResultListCellController implements FxController {
}
public boolean isFixing() {
return fixState.get().map(Result.FixState.FIXING::equals).orElse(false);
return Result.FixState.FIXING.equals(fixState.get());
}
public BooleanBinding fixedProperty() {
@@ -175,7 +181,7 @@ public class ResultListCellController implements FxController {
}
public boolean isFixed() {
return fixState.get().map(Result.FixState.FIXED::equals).orElse(false);
return Result.FixState.FIXED.equals(fixState.get());
}
public BooleanBinding fixFailedProperty() {
@@ -183,7 +189,7 @@ public class ResultListCellController implements FxController {
}
public Boolean isFixFailed() {
return fixState.get().map(Result.FixState.FIX_FAILED::equals).orElse(false);
return Result.FixState.FIX_FAILED.equals(fixState.get());
}
public BooleanBinding fixRunningOrDoneProperty() {