mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-21 04:01:27 +00:00
make the view depend on state, not on another view
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user