mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-21 23:20:23 +00:00
Rework categories
This commit is contained in:
parent
a65a0bd1b0
commit
be684d7b72
19 changed files with 228 additions and 109 deletions
|
@ -364,9 +364,7 @@ public class BrowserSessionTabsComp extends SimpleComp {
|
||||||
|
|
||||||
StackPane c = (StackPane) tabs.lookup("#" + id + " .tab-container");
|
StackPane c = (StackPane) tabs.lookup("#" + id + " .tab-container");
|
||||||
c.getStyleClass().add("color-box");
|
c.getStyleClass().add("color-box");
|
||||||
var color = DataStorage.get()
|
var color = DataStorage.get().getEffectiveColor(model.getEntry().get());
|
||||||
.getRootForEntry(model.getEntry().get())
|
|
||||||
.getColor();
|
|
||||||
if (color != null) {
|
if (color != null) {
|
||||||
c.getStyleClass().add(color.getId());
|
c.getStyleClass().add(color.getId());
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package io.xpipe.app.comp.base;
|
||||||
|
|
||||||
import io.xpipe.app.fxcomps.Comp;
|
import io.xpipe.app.fxcomps.Comp;
|
||||||
import io.xpipe.app.fxcomps.CompStructure;
|
import io.xpipe.app.fxcomps.CompStructure;
|
||||||
|
import io.xpipe.app.fxcomps.SimpleCompStructure;
|
||||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||||
|
|
||||||
import javafx.beans.property.Property;
|
import javafx.beans.property.Property;
|
||||||
|
@ -15,7 +16,7 @@ import lombok.Value;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class LazyTextFieldComp extends Comp<LazyTextFieldComp.Structure> {
|
public class LazyTextFieldComp extends Comp<CompStructure<TextField>> {
|
||||||
|
|
||||||
private final Property<String> currentValue;
|
private final Property<String> currentValue;
|
||||||
private final Property<String> appliedValue;
|
private final Property<String> appliedValue;
|
||||||
|
@ -26,8 +27,7 @@ public class LazyTextFieldComp extends Comp<LazyTextFieldComp.Structure> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LazyTextFieldComp.Structure createBase() {
|
public CompStructure<TextField> createBase() {
|
||||||
var sp = new StackPane();
|
|
||||||
var r = new TextField();
|
var r = new TextField();
|
||||||
|
|
||||||
r.setOnKeyPressed(ke -> {
|
r.setOnKeyPressed(ke -> {
|
||||||
|
@ -48,23 +48,14 @@ public class LazyTextFieldComp extends Comp<LazyTextFieldComp.Structure> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
sp.focusedProperty().addListener((c, o, n) -> {
|
|
||||||
if (n) {
|
|
||||||
r.setDisable(false);
|
|
||||||
r.requestFocus();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Handles external updates
|
// Handles external updates
|
||||||
PlatformThread.sync(appliedValue).addListener((observable, oldValue, n) -> {
|
PlatformThread.sync(appliedValue).addListener((observable, oldValue, n) -> {
|
||||||
currentValue.setValue(n);
|
currentValue.setValue(n);
|
||||||
});
|
});
|
||||||
|
|
||||||
r.setPrefWidth(0);
|
r.setMinWidth(0);
|
||||||
sp.getChildren().add(r);
|
|
||||||
sp.prefWidthProperty().bind(r.prefWidthProperty());
|
|
||||||
sp.prefHeightProperty().bind(r.prefHeightProperty());
|
|
||||||
r.setDisable(true);
|
r.setDisable(true);
|
||||||
|
r.prefWidthProperty().bind(r.minWidthProperty());
|
||||||
|
|
||||||
currentValue.subscribe(n -> {
|
currentValue.subscribe(n -> {
|
||||||
PlatformThread.runLaterIfNeeded(() -> {
|
PlatformThread.runLaterIfNeeded(() -> {
|
||||||
|
@ -86,7 +77,7 @@ public class LazyTextFieldComp extends Comp<LazyTextFieldComp.Structure> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
r.getStyleClass().add("lazy-text-field-comp");
|
r.getStyleClass().add("lazy-text-field-comp");
|
||||||
return new Structure(sp, r);
|
return new SimpleCompStructure<>(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Value
|
@Value
|
||||||
|
|
|
@ -6,6 +6,7 @@ import io.xpipe.app.prefs.AppPrefs;
|
||||||
import io.xpipe.app.storage.DataStorage;
|
import io.xpipe.app.storage.DataStorage;
|
||||||
import io.xpipe.app.storage.DataStoreCategory;
|
import io.xpipe.app.storage.DataStoreCategory;
|
||||||
|
|
||||||
|
import io.xpipe.app.storage.DataColor;
|
||||||
import javafx.beans.property.*;
|
import javafx.beans.property.*;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
|
@ -29,6 +30,7 @@ public class StoreCategoryWrapper {
|
||||||
private final ObservableList<StoreCategoryWrapper> children;
|
private final ObservableList<StoreCategoryWrapper> children;
|
||||||
private final ObservableList<StoreEntryWrapper> containedEntries;
|
private final ObservableList<StoreEntryWrapper> containedEntries;
|
||||||
private final BooleanProperty expanded = new SimpleBooleanProperty();
|
private final BooleanProperty expanded = new SimpleBooleanProperty();
|
||||||
|
private final Property<DataColor> color = new SimpleObjectProperty<>();
|
||||||
|
|
||||||
public StoreCategoryWrapper(DataStoreCategory category) {
|
public StoreCategoryWrapper(DataStoreCategory category) {
|
||||||
var d = 0;
|
var d = 0;
|
||||||
|
@ -51,6 +53,7 @@ public class StoreCategoryWrapper {
|
||||||
this.share = new SimpleObjectProperty<>(category.isShare());
|
this.share = new SimpleObjectProperty<>(category.isShare());
|
||||||
this.children = FXCollections.observableArrayList();
|
this.children = FXCollections.observableArrayList();
|
||||||
this.containedEntries = FXCollections.observableArrayList();
|
this.containedEntries = FXCollections.observableArrayList();
|
||||||
|
this.color.setValue(category.getColor());
|
||||||
setupListeners();
|
setupListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,6 +133,7 @@ public class StoreCategoryWrapper {
|
||||||
sortMode.setValue(category.getSortMode());
|
sortMode.setValue(category.getSortMode());
|
||||||
share.setValue(category.isShare());
|
share.setValue(category.isShare());
|
||||||
expanded.setValue(category.isExpanded());
|
expanded.setValue(category.isExpanded());
|
||||||
|
color.setValue(category.getColor());
|
||||||
|
|
||||||
containedEntries.setAll(StoreViewState.get().getAllEntries().getList().stream()
|
containedEntries.setAll(StoreViewState.get().getAllEntries().getList().stream()
|
||||||
.filter(entry -> {
|
.filter(entry -> {
|
||||||
|
|
|
@ -17,7 +17,7 @@ import io.xpipe.app.fxcomps.util.DerivedObservableList;
|
||||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||||
import io.xpipe.app.prefs.AppPrefs;
|
import io.xpipe.app.prefs.AppPrefs;
|
||||||
import io.xpipe.app.storage.DataStorage;
|
import io.xpipe.app.storage.DataStorage;
|
||||||
import io.xpipe.app.storage.DataStoreColor;
|
import io.xpipe.app.storage.DataColor;
|
||||||
import io.xpipe.app.storage.DataStoreEntry;
|
import io.xpipe.app.storage.DataStoreEntry;
|
||||||
import io.xpipe.app.update.XPipeDistributionType;
|
import io.xpipe.app.update.XPipeDistributionType;
|
||||||
import io.xpipe.app.util.*;
|
import io.xpipe.app.util.*;
|
||||||
|
@ -345,7 +345,7 @@ public abstract class StoreEntryComp extends SimpleComp {
|
||||||
event.consume();
|
event.consume();
|
||||||
});
|
});
|
||||||
color.getItems().add(none);
|
color.getItems().add(none);
|
||||||
Arrays.stream(DataStoreColor.values()).forEach(dataStoreColor -> {
|
Arrays.stream(DataColor.values()).forEach(dataStoreColor -> {
|
||||||
MenuItem m = new MenuItem(DataStoreFormatter.capitalize(dataStoreColor.getId()));
|
MenuItem m = new MenuItem(DataStoreFormatter.capitalize(dataStoreColor.getId()));
|
||||||
m.setOnAction(event -> {
|
m.setOnAction(event -> {
|
||||||
getWrapper().getEntry().setColor(dataStoreColor);
|
getWrapper().getEntry().setColor(dataStoreColor);
|
||||||
|
|
|
@ -6,7 +6,7 @@ import io.xpipe.app.issue.ErrorEvent;
|
||||||
import io.xpipe.app.prefs.AppPrefs;
|
import io.xpipe.app.prefs.AppPrefs;
|
||||||
import io.xpipe.app.storage.DataStorage;
|
import io.xpipe.app.storage.DataStorage;
|
||||||
import io.xpipe.app.storage.DataStoreCategory;
|
import io.xpipe.app.storage.DataStoreCategory;
|
||||||
import io.xpipe.app.storage.DataStoreColor;
|
import io.xpipe.app.storage.DataColor;
|
||||||
import io.xpipe.app.storage.DataStoreEntry;
|
import io.xpipe.app.storage.DataStoreEntry;
|
||||||
import io.xpipe.app.util.ThreadHelper;
|
import io.xpipe.app.util.ThreadHelper;
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ public class StoreEntryWrapper {
|
||||||
private final BooleanProperty expanded = new SimpleBooleanProperty();
|
private final BooleanProperty expanded = new SimpleBooleanProperty();
|
||||||
private final Property<Object> persistentState = new SimpleObjectProperty<>();
|
private final Property<Object> persistentState = new SimpleObjectProperty<>();
|
||||||
private final Property<Map<String, Object>> cache = new SimpleObjectProperty<>(Map.of());
|
private final Property<Map<String, Object>> cache = new SimpleObjectProperty<>(Map.of());
|
||||||
private final Property<DataStoreColor> color = new SimpleObjectProperty<>();
|
private final Property<DataColor> color = new SimpleObjectProperty<>();
|
||||||
private final Property<StoreCategoryWrapper> category = new SimpleObjectProperty<>();
|
private final Property<StoreCategoryWrapper> category = new SimpleObjectProperty<>();
|
||||||
private final Property<String> summary = new SimpleObjectProperty<>();
|
private final Property<String> summary = new SimpleObjectProperty<>();
|
||||||
private final Property<StoreNotes> notes;
|
private final Property<StoreNotes> notes;
|
||||||
|
|
|
@ -7,7 +7,7 @@ import io.xpipe.app.fxcomps.augment.GrowAugment;
|
||||||
import io.xpipe.app.fxcomps.impl.HorizontalComp;
|
import io.xpipe.app.fxcomps.impl.HorizontalComp;
|
||||||
import io.xpipe.app.fxcomps.impl.IconButtonComp;
|
import io.xpipe.app.fxcomps.impl.IconButtonComp;
|
||||||
import io.xpipe.app.fxcomps.impl.VerticalComp;
|
import io.xpipe.app.fxcomps.impl.VerticalComp;
|
||||||
import io.xpipe.app.storage.DataStoreColor;
|
import io.xpipe.app.storage.DataColor;
|
||||||
import io.xpipe.app.util.ThreadHelper;
|
import io.xpipe.app.util.ThreadHelper;
|
||||||
|
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
|
@ -175,7 +175,7 @@ public class StoreSectionComp extends Comp<CompStructure<VBox>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
var newList = new ArrayList<>(struc.get().getStyleClass());
|
var newList = new ArrayList<>(struc.get().getStyleClass());
|
||||||
newList.removeIf(s -> Arrays.stream(DataStoreColor.values())
|
newList.removeIf(s -> Arrays.stream(DataColor.values())
|
||||||
.anyMatch(
|
.anyMatch(
|
||||||
dataStoreColor -> dataStoreColor.getId().equals(s)));
|
dataStoreColor -> dataStoreColor.getId().equals(s)));
|
||||||
newList.remove("gray");
|
newList.remove("gray");
|
||||||
|
|
|
@ -8,7 +8,7 @@ import io.xpipe.app.fxcomps.impl.HorizontalComp;
|
||||||
import io.xpipe.app.fxcomps.impl.IconButtonComp;
|
import io.xpipe.app.fxcomps.impl.IconButtonComp;
|
||||||
import io.xpipe.app.fxcomps.impl.PrettyImageHelper;
|
import io.xpipe.app.fxcomps.impl.PrettyImageHelper;
|
||||||
import io.xpipe.app.fxcomps.impl.VerticalComp;
|
import io.xpipe.app.fxcomps.impl.VerticalComp;
|
||||||
import io.xpipe.app.storage.DataStoreColor;
|
import io.xpipe.app.storage.DataColor;
|
||||||
|
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.BooleanProperty;
|
import javafx.beans.property.BooleanProperty;
|
||||||
|
@ -168,7 +168,7 @@ public class StoreSectionMiniComp extends Comp<CompStructure<VBox>> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struc.get().getStyleClass().removeIf(s -> Arrays.stream(DataStoreColor.values())
|
struc.get().getStyleClass().removeIf(s -> Arrays.stream(DataColor.values())
|
||||||
.anyMatch(dataStoreColor ->
|
.anyMatch(dataStoreColor ->
|
||||||
dataStoreColor.getId().equals(s)));
|
dataStoreColor.getId().equals(s)));
|
||||||
struc.get().getStyleClass().remove("gray");
|
struc.get().getStyleClass().remove("gray");
|
||||||
|
|
|
@ -214,8 +214,9 @@ public class AppWindowHelper {
|
||||||
var r = scene.getRoot();
|
var r = scene.getRoot();
|
||||||
if (r != null) {
|
if (r != null) {
|
||||||
var acc = Platform.isAccessibilityActive();
|
var acc = Platform.isAccessibilityActive();
|
||||||
r.pseudoClassStateChanged(PseudoClass.getPseudoClass("key-navigation"), kb && !acc);
|
// This property is broken on some systems
|
||||||
r.pseudoClassStateChanged(PseudoClass.getPseudoClass("normal-navigation"), !kb && !acc);
|
r.pseudoClassStateChanged(PseudoClass.getPseudoClass("key-navigation"), kb);
|
||||||
|
r.pseudoClassStateChanged(PseudoClass.getPseudoClass("normal-navigation"), !kb);
|
||||||
r.pseudoClassStateChanged(PseudoClass.getPseudoClass("accessibility-navigation"), acc);
|
r.pseudoClassStateChanged(PseudoClass.getPseudoClass("accessibility-navigation"), acc);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -223,7 +224,8 @@ public class AppWindowHelper {
|
||||||
Platform.accessibilityActiveProperty().addListener((observable, oldValue, newValue) -> {
|
Platform.accessibilityActiveProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
var r = scene.getRoot();
|
var r = scene.getRoot();
|
||||||
if (r != null) {
|
if (r != null) {
|
||||||
r.pseudoClassStateChanged(PseudoClass.getPseudoClass("key-navigation"), false);
|
// This property is broken on some systems
|
||||||
|
r.pseudoClassStateChanged(PseudoClass.getPseudoClass("key-navigation"), true);
|
||||||
r.pseudoClassStateChanged(PseudoClass.getPseudoClass("normal-navigation"), false);
|
r.pseudoClassStateChanged(PseudoClass.getPseudoClass("normal-navigation"), false);
|
||||||
r.pseudoClassStateChanged(PseudoClass.getPseudoClass("accessibility-navigation"), true);
|
r.pseudoClassStateChanged(PseudoClass.getPseudoClass("accessibility-navigation"), true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,25 +12,30 @@ import io.xpipe.app.fxcomps.Comp;
|
||||||
import io.xpipe.app.fxcomps.SimpleComp;
|
import io.xpipe.app.fxcomps.SimpleComp;
|
||||||
import io.xpipe.app.fxcomps.augment.ContextMenuAugment;
|
import io.xpipe.app.fxcomps.augment.ContextMenuAugment;
|
||||||
import io.xpipe.app.fxcomps.util.DerivedObservableList;
|
import io.xpipe.app.fxcomps.util.DerivedObservableList;
|
||||||
|
import io.xpipe.app.storage.DataColor;
|
||||||
import io.xpipe.app.storage.DataStorage;
|
import io.xpipe.app.storage.DataStorage;
|
||||||
import io.xpipe.app.storage.DataStoreCategory;
|
import io.xpipe.app.storage.DataStoreCategory;
|
||||||
import io.xpipe.app.util.ContextMenuHelper;
|
import io.xpipe.app.util.ContextMenuHelper;
|
||||||
|
import io.xpipe.app.util.DataStoreFormatter;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.SimpleBooleanProperty;
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
import javafx.css.PseudoClass;
|
import javafx.css.PseudoClass;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.control.ContextMenu;
|
import javafx.scene.control.ContextMenu;
|
||||||
|
import javafx.scene.control.Menu;
|
||||||
import javafx.scene.control.MenuItem;
|
import javafx.scene.control.MenuItem;
|
||||||
|
import javafx.scene.control.SeparatorMenuItem;
|
||||||
import javafx.scene.input.KeyCode;
|
import javafx.scene.input.KeyCode;
|
||||||
|
import javafx.scene.input.KeyCodeCombination;
|
||||||
|
import javafx.scene.input.KeyEvent;
|
||||||
import javafx.scene.input.MouseButton;
|
import javafx.scene.input.MouseButton;
|
||||||
import javafx.scene.layout.Region;
|
import javafx.scene.layout.Region;
|
||||||
|
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
import org.kordamp.ikonli.javafx.FontIcon;
|
import org.kordamp.ikonli.javafx.FontIcon;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
@ -45,43 +50,60 @@ public class StoreCategoryComp extends SimpleComp {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Region createSimple() {
|
protected Region createSimple() {
|
||||||
var i = Bindings.createStringBinding(
|
var name = new LazyTextFieldComp(category.nameProperty())
|
||||||
|
.styleClass("name")
|
||||||
|
.createRegion();
|
||||||
|
var showing = new SimpleBooleanProperty();
|
||||||
|
|
||||||
|
var expandIcon = Bindings.createStringBinding(
|
||||||
() -> {
|
() -> {
|
||||||
|
var exp = category.getExpanded().get() && category.getChildren().size() > 0;
|
||||||
|
return exp ? "mdal-keyboard_arrow_down" : "mdal-keyboard_arrow_right";
|
||||||
|
},
|
||||||
|
category.getExpanded(), category.getChildren());
|
||||||
|
var expandButton = new IconButtonComp(expandIcon, () -> {
|
||||||
|
category.toggleExpanded();
|
||||||
|
})
|
||||||
|
.apply(struc -> AppFont.medium(struc.get()))
|
||||||
|
.apply(struc -> {
|
||||||
|
struc.get().setAlignment(Pos.CENTER);
|
||||||
|
struc.get().setPadding(new Insets(-2, 0, 0, 0));
|
||||||
|
struc.get().setFocusTraversable(false);
|
||||||
|
})
|
||||||
|
.styleClass("expand-button")
|
||||||
|
.tooltipKey("expand", new KeyCodeCombination(KeyCode.SPACE));
|
||||||
|
|
||||||
|
var hover = new SimpleBooleanProperty();
|
||||||
|
var statusIcon = Bindings.createStringBinding(
|
||||||
|
() -> {
|
||||||
|
if (hover.get()) {
|
||||||
|
return "mdomz-settings";
|
||||||
|
}
|
||||||
|
|
||||||
if (!DataStorage.get().supportsSharing()
|
if (!DataStorage.get().supportsSharing()
|
||||||
|| !category.getCategory().canShare()) {
|
|| !category.getCategory().canShare()) {
|
||||||
var exp = category.getExpanded().get() && category.getChildren().size() > 0;
|
return "mdi2a-account-lock";
|
||||||
return exp ? "mdal-keyboard_arrow_down" : "mdal-keyboard_arrow_right";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return category.getShare().getValue() ? "mdi2g-git" : "mdi2a-account-cancel";
|
return category.getShare().getValue() ? "mdi2g-git" : "mdi2a-account-cancel";
|
||||||
},
|
},
|
||||||
category.getShare(), category.getExpanded(), category.getChildren());
|
category.getShare(), hover);
|
||||||
var icon = new IconButtonComp(i, () -> {
|
var statusButton = new IconButtonComp(statusIcon)
|
||||||
category.toggleExpanded();
|
|
||||||
})
|
|
||||||
.apply(struc -> AppFont.small(struc.get()))
|
.apply(struc -> AppFont.small(struc.get()))
|
||||||
.apply(struc -> {
|
.apply(struc -> {
|
||||||
struc.get().setAlignment(Pos.CENTER);
|
struc.get().setAlignment(Pos.CENTER);
|
||||||
struc.get().setPadding(new Insets(0, 0, 6, 0));
|
struc.get().setPadding(new Insets(0, 0, 7, 0));
|
||||||
struc.get().setFocusTraversable(false);
|
struc.get().setFocusTraversable(false);
|
||||||
});
|
hover.bind(struc.get().hoverProperty());
|
||||||
var name = new LazyTextFieldComp(category.nameProperty())
|
|
||||||
.apply(struc -> {
|
|
||||||
struc.get().prefWidthProperty().unbind();
|
|
||||||
struc.get().setPrefWidth(150);
|
|
||||||
struc.getTextField().minWidthProperty().bind(struc.get().widthProperty());
|
|
||||||
})
|
})
|
||||||
.styleClass("name")
|
|
||||||
.createRegion();
|
|
||||||
var showing = new SimpleBooleanProperty();
|
|
||||||
var settings = new IconButtonComp("mdomz-settings")
|
|
||||||
.styleClass("settings")
|
|
||||||
.apply(new ContextMenuAugment<>(
|
.apply(new ContextMenuAugment<>(
|
||||||
mouseEvent -> mouseEvent.getButton() == MouseButton.PRIMARY, null, () -> {
|
mouseEvent -> mouseEvent.getButton() == MouseButton.PRIMARY, null, () -> {
|
||||||
var cm = createContextMenu(name);
|
var cm = createContextMenu(name);
|
||||||
showing.bind(cm.showingProperty());
|
showing.bind(cm.showingProperty());
|
||||||
return cm;
|
return cm;
|
||||||
}));
|
}))
|
||||||
|
.styleClass("status-button");
|
||||||
|
|
||||||
var shownList = new DerivedObservableList<>(category.getContainedEntries(), true)
|
var shownList = new DerivedObservableList<>(category.getContainedEntries(), true)
|
||||||
.filtered(
|
.filtered(
|
||||||
storeEntryWrapper -> {
|
storeEntryWrapper -> {
|
||||||
|
@ -91,18 +113,21 @@ public class StoreCategoryComp extends SimpleComp {
|
||||||
StoreViewState.get().getFilterString())
|
StoreViewState.get().getFilterString())
|
||||||
.getList();
|
.getList();
|
||||||
var count = new CountComp<>(shownList, category.getContainedEntries(), string -> "(" + string + ")");
|
var count = new CountComp<>(shownList, category.getContainedEntries(), string -> "(" + string + ")");
|
||||||
var hover = new SimpleBooleanProperty();
|
|
||||||
|
var showStatus = hover.or(new SimpleBooleanProperty(DataStorage.get().supportsSharing())).or(showing);
|
||||||
var focus = new SimpleBooleanProperty();
|
var focus = new SimpleBooleanProperty();
|
||||||
var h = new HorizontalComp(List.of(
|
var h = new HorizontalComp(List.of(
|
||||||
icon,
|
expandButton,
|
||||||
Comp.hspacer(4),
|
Comp.hspacer(1),
|
||||||
Comp.of(() -> name),
|
Comp.of(() -> name).hgrow(),
|
||||||
Comp.hspacer(),
|
Comp.hspacer(2),
|
||||||
count.hide(hover.or(showing).or(focus)),
|
count,
|
||||||
settings.hide(hover.not().and(showing.not()).and(focus.not()))));
|
Comp.hspacer(7),
|
||||||
|
statusButton.hide(showStatus.not())));
|
||||||
h.padding(new Insets(0, 10, 0, (category.getDepth() * 10)));
|
h.padding(new Insets(0, 10, 0, (category.getDepth() * 10)));
|
||||||
|
|
||||||
var categoryButton = new ButtonComp(null, h.createRegion(), category::select)
|
var categoryButton = new ButtonComp(null, h.createRegion(), category::select)
|
||||||
|
.focusTraversable()
|
||||||
.styleClass("category-button")
|
.styleClass("category-button")
|
||||||
.apply(struc -> hover.bind(struc.get().hoverProperty()))
|
.apply(struc -> hover.bind(struc.get().hoverProperty()))
|
||||||
.apply(struc -> focus.bind(struc.get().focusedProperty()))
|
.apply(struc -> focus.bind(struc.get().focusedProperty()))
|
||||||
|
@ -112,12 +137,21 @@ public class StoreCategoryComp extends SimpleComp {
|
||||||
mouseEvent -> mouseEvent.getButton() == MouseButton.SECONDARY,
|
mouseEvent -> mouseEvent.getButton() == MouseButton.SECONDARY,
|
||||||
keyEvent -> keyEvent.getCode() == KeyCode.SPACE,
|
keyEvent -> keyEvent.getCode() == KeyCode.SPACE,
|
||||||
() -> createContextMenu(name)));
|
() -> createContextMenu(name)));
|
||||||
|
categoryButton.apply(struc -> {
|
||||||
|
struc.get().addEventFilter(KeyEvent.KEY_PRESSED, event -> {
|
||||||
|
if (event.getCode() == KeyCode.SPACE) {
|
||||||
|
category.toggleExpanded();
|
||||||
|
event.consume();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
var l = category.getChildren()
|
var l = category.getChildren()
|
||||||
.sorted(Comparator.comparing(storeCategoryWrapper ->
|
.sorted(Comparator.comparing(storeCategoryWrapper ->
|
||||||
storeCategoryWrapper.nameProperty().getValue().toLowerCase(Locale.ROOT)));
|
storeCategoryWrapper.nameProperty().getValue().toLowerCase(Locale.ROOT)));
|
||||||
var children =
|
var children =
|
||||||
new ListBoxViewComp<>(l, l, storeCategoryWrapper -> new StoreCategoryComp(storeCategoryWrapper), false);
|
new ListBoxViewComp<>(l, l, storeCategoryWrapper -> new StoreCategoryComp(storeCategoryWrapper), false);
|
||||||
|
children.styleClass("children");
|
||||||
|
|
||||||
var hide = Bindings.createBooleanBinding(() -> {
|
var hide = Bindings.createBooleanBinding(() -> {
|
||||||
return !category.getExpanded().get() || category.getChildren().isEmpty();
|
return !category.getExpanded().get() || category.getChildren().isEmpty();
|
||||||
|
@ -128,6 +162,10 @@ public class StoreCategoryComp extends SimpleComp {
|
||||||
StoreViewState.get().getActiveCategory().subscribe(val -> {
|
StoreViewState.get().getActiveCategory().subscribe(val -> {
|
||||||
struc.get().pseudoClassStateChanged(SELECTED, val.equals(category));
|
struc.get().pseudoClassStateChanged(SELECTED, val.equals(category));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
category.getColor().subscribe((c) -> {
|
||||||
|
DataColor.applyStyleClasses(c, struc.get());
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return v.createRegion();
|
return v.createRegion();
|
||||||
|
@ -135,6 +173,7 @@ public class StoreCategoryComp extends SimpleComp {
|
||||||
|
|
||||||
private ContextMenu createContextMenu(Region text) {
|
private ContextMenu createContextMenu(Region text) {
|
||||||
var contextMenu = ContextMenuHelper.create();
|
var contextMenu = ContextMenuHelper.create();
|
||||||
|
AppFont.normal(contextMenu.getStyleableNode());
|
||||||
|
|
||||||
var newCategory = new MenuItem(AppI18n.get("newCategory"), new FontIcon("mdi2p-plus-thick"));
|
var newCategory = new MenuItem(AppI18n.get("newCategory"), new FontIcon("mdi2p-plus-thick"));
|
||||||
newCategory.setOnAction(event -> {
|
newCategory.setOnAction(event -> {
|
||||||
|
@ -144,6 +183,25 @@ public class StoreCategoryComp extends SimpleComp {
|
||||||
});
|
});
|
||||||
contextMenu.getItems().add(newCategory);
|
contextMenu.getItems().add(newCategory);
|
||||||
|
|
||||||
|
contextMenu.getItems().add(new SeparatorMenuItem());
|
||||||
|
|
||||||
|
var color = new Menu(AppI18n.get("color"), new FontIcon("mdi2f-format-color-fill"));
|
||||||
|
var none = new MenuItem("None");
|
||||||
|
none.setOnAction(event -> {
|
||||||
|
category.getCategory().setColor(null);
|
||||||
|
event.consume();
|
||||||
|
});
|
||||||
|
color.getItems().add(none);
|
||||||
|
Arrays.stream(DataColor.values()).forEach(dataStoreColor -> {
|
||||||
|
MenuItem m = new MenuItem(DataStoreFormatter.capitalize(dataStoreColor.getId()));
|
||||||
|
m.setOnAction(event -> {
|
||||||
|
category.getCategory().setColor(dataStoreColor);
|
||||||
|
event.consume();
|
||||||
|
});
|
||||||
|
color.getItems().add(m);
|
||||||
|
});
|
||||||
|
contextMenu.getItems().add(color);
|
||||||
|
|
||||||
if (DataStorage.get().supportsSharing() && category.getCategory().canShare()) {
|
if (DataStorage.get().supportsSharing() && category.getCategory().canShare()) {
|
||||||
var share = new MenuItem();
|
var share = new MenuItem();
|
||||||
share.textProperty()
|
share.textProperty()
|
||||||
|
@ -162,7 +220,7 @@ public class StoreCategoryComp extends SimpleComp {
|
||||||
if (category.getShare().getValue()) {
|
if (category.getShare().getValue()) {
|
||||||
return new FontIcon("mdi2b-block-helper");
|
return new FontIcon("mdi2b-block-helper");
|
||||||
} else {
|
} else {
|
||||||
return new FontIcon("mdi2s-share");
|
return new FontIcon("mdi2g-git");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
category.getShare()));
|
category.getShare()));
|
||||||
|
@ -174,10 +232,13 @@ public class StoreCategoryComp extends SimpleComp {
|
||||||
|
|
||||||
var rename = new MenuItem(AppI18n.get("rename"), new FontIcon("mdal-edit"));
|
var rename = new MenuItem(AppI18n.get("rename"), new FontIcon("mdal-edit"));
|
||||||
rename.setOnAction(event -> {
|
rename.setOnAction(event -> {
|
||||||
|
text.setDisable(false);
|
||||||
text.requestFocus();
|
text.requestFocus();
|
||||||
});
|
});
|
||||||
contextMenu.getItems().add(rename);
|
contextMenu.getItems().add(rename);
|
||||||
|
|
||||||
|
contextMenu.getItems().add(new SeparatorMenuItem());
|
||||||
|
|
||||||
var del = new MenuItem(AppI18n.get("remove"), new FontIcon("mdal-delete_outline"));
|
var del = new MenuItem(AppI18n.get("remove"), new FontIcon("mdal-delete_outline"));
|
||||||
del.setOnAction(event -> {
|
del.setOnAction(event -> {
|
||||||
category.delete();
|
category.delete();
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
package io.xpipe.app.storage;
|
package io.xpipe.app.storage;
|
||||||
|
|
||||||
import javafx.scene.paint.Color;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public enum DataStoreColor {
|
public enum DataColor {
|
||||||
@JsonProperty("red")
|
@JsonProperty("red")
|
||||||
RED("red", "\uD83D\uDD34", Color.DARKRED),
|
RED("red", "\uD83D\uDD34", Color.DARKRED),
|
||||||
|
|
||||||
|
@ -23,7 +26,7 @@ public enum DataStoreColor {
|
||||||
private final String emoji;
|
private final String emoji;
|
||||||
private final Color terminalColor;
|
private final Color terminalColor;
|
||||||
|
|
||||||
DataStoreColor(String id, String emoji, Color terminalColor) {
|
DataColor(String id, String emoji, Color terminalColor) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.emoji = emoji;
|
this.emoji = emoji;
|
||||||
this.terminalColor = terminalColor;
|
this.terminalColor = terminalColor;
|
||||||
|
@ -38,4 +41,18 @@ public enum DataStoreColor {
|
||||||
var value = terminalColor;
|
var value = terminalColor;
|
||||||
return "#" + (format(value.getRed()) + format(value.getGreen()) + format(value.getBlue())).toUpperCase();
|
return "#" + (format(value.getRed()) + format(value.getGreen()) + format(value.getBlue())).toUpperCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void applyStyleClasses(DataColor color, Node node) {
|
||||||
|
var newList = new ArrayList<>(node.getStyleClass());
|
||||||
|
newList.removeIf(s -> Arrays.stream(DataColor.values())
|
||||||
|
.anyMatch(
|
||||||
|
dataStoreColor -> dataStoreColor.getId().equals(s)));
|
||||||
|
newList.remove("gray");
|
||||||
|
if (color != null) {
|
||||||
|
newList.add(color.getId());
|
||||||
|
} else {
|
||||||
|
newList.add("gray");
|
||||||
|
}
|
||||||
|
node.getStyleClass().setAll(newList);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -172,6 +172,7 @@ public abstract class DataStorage {
|
||||||
"Default",
|
"Default",
|
||||||
Instant.now(),
|
Instant.now(),
|
||||||
Instant.now(),
|
Instant.now(),
|
||||||
|
null,
|
||||||
true,
|
true,
|
||||||
ALL_CONNECTIONS_CATEGORY_UUID,
|
ALL_CONNECTIONS_CATEGORY_UUID,
|
||||||
StoreSortMode.getDefault(),
|
StoreSortMode.getDefault(),
|
||||||
|
@ -693,6 +694,22 @@ public abstract class DataStorage {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DataColor getEffectiveColor(DataStoreEntry entry) {
|
||||||
|
var root = getRootForEntry(entry);
|
||||||
|
if (root.getColor() != null) {
|
||||||
|
return root.getColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
var cats = getCategoryParentHierarchy(getStoreCategoryIfPresent(entry.getCategoryUuid()).orElseThrow());
|
||||||
|
for (DataStoreCategory cat : cats.reversed()) {
|
||||||
|
if (cat.getColor() != null) {
|
||||||
|
return cat.getColor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public DataStoreEntry getRootForEntry(DataStoreEntry entry) {
|
public DataStoreEntry getRootForEntry(DataStoreEntry entry) {
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package io.xpipe.app.storage;
|
package io.xpipe.app.storage;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import io.xpipe.app.comp.store.StoreSortMode;
|
import io.xpipe.app.comp.store.StoreSortMode;
|
||||||
import io.xpipe.core.util.JacksonMapper;
|
import io.xpipe.core.util.JacksonMapper;
|
||||||
|
|
||||||
|
@ -38,12 +39,13 @@ public class DataStoreCategory extends StorageElement {
|
||||||
String name,
|
String name,
|
||||||
Instant lastUsed,
|
Instant lastUsed,
|
||||||
Instant lastModified,
|
Instant lastModified,
|
||||||
|
DataColor color,
|
||||||
boolean dirty,
|
boolean dirty,
|
||||||
UUID parentCategory,
|
UUID parentCategory,
|
||||||
StoreSortMode sortMode,
|
StoreSortMode sortMode,
|
||||||
boolean share,
|
boolean share,
|
||||||
boolean expanded) {
|
boolean expanded) {
|
||||||
super(directory, uuid, name, lastUsed, lastModified, expanded, dirty);
|
super(directory, uuid, name, lastUsed, lastModified, color, expanded, dirty);
|
||||||
this.parentCategory = parentCategory;
|
this.parentCategory = parentCategory;
|
||||||
this.sortMode = sortMode;
|
this.sortMode = sortMode;
|
||||||
this.share = share;
|
this.share = share;
|
||||||
|
@ -56,6 +58,7 @@ public class DataStoreCategory extends StorageElement {
|
||||||
name,
|
name,
|
||||||
Instant.now(),
|
Instant.now(),
|
||||||
Instant.now(),
|
Instant.now(),
|
||||||
|
null,
|
||||||
true,
|
true,
|
||||||
parentCategory,
|
parentCategory,
|
||||||
StoreSortMode.getDefault(),
|
StoreSortMode.getDefault(),
|
||||||
|
@ -70,6 +73,7 @@ public class DataStoreCategory extends StorageElement {
|
||||||
name,
|
name,
|
||||||
Instant.now(),
|
Instant.now(),
|
||||||
Instant.now(),
|
Instant.now(),
|
||||||
|
null,
|
||||||
true,
|
true,
|
||||||
parentCategory,
|
parentCategory,
|
||||||
StoreSortMode.getDefault(),
|
StoreSortMode.getDefault(),
|
||||||
|
@ -95,8 +99,17 @@ public class DataStoreCategory extends StorageElement {
|
||||||
.filter(jsonNode -> !jsonNode.isNull())
|
.filter(jsonNode -> !jsonNode.isNull())
|
||||||
.map(jsonNode -> UUID.fromString(jsonNode.textValue()))
|
.map(jsonNode -> UUID.fromString(jsonNode.textValue()))
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
|
var color = Optional.ofNullable(json.get("color"))
|
||||||
|
.map(node -> {
|
||||||
|
try {
|
||||||
|
return mapper.treeToValue(node, DataColor.class);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.orElse(null);
|
||||||
var name = json.required("name").textValue();
|
var name = json.required("name").textValue();
|
||||||
|
|
||||||
var sortMode = Optional.ofNullable(stateJson.get("sortMode"))
|
var sortMode = Optional.ofNullable(stateJson.get("sortMode"))
|
||||||
.map(JsonNode::asText)
|
.map(JsonNode::asText)
|
||||||
.flatMap(string -> StoreSortMode.fromId(string))
|
.flatMap(string -> StoreSortMode.fromId(string))
|
||||||
|
@ -116,7 +129,7 @@ public class DataStoreCategory extends StorageElement {
|
||||||
.orElse(true);
|
.orElse(true);
|
||||||
|
|
||||||
return Optional.of(
|
return Optional.of(
|
||||||
new DataStoreCategory(dir, uuid, name, lastUsed, lastModified, false, parentUuid, sortMode, share, expanded));
|
new DataStoreCategory(dir, uuid, name, lastUsed, lastModified, color, false, parentUuid, sortMode, share, expanded));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSortMode(StoreSortMode sortMode) {
|
public void setSortMode(StoreSortMode sortMode) {
|
||||||
|
@ -180,6 +193,7 @@ public class DataStoreCategory extends StorageElement {
|
||||||
obj.put("uuid", uuid.toString());
|
obj.put("uuid", uuid.toString());
|
||||||
obj.put("name", name);
|
obj.put("name", name);
|
||||||
obj.put("share", share);
|
obj.put("share", share);
|
||||||
|
obj.set("color", mapper.valueToTree(color));
|
||||||
stateObj.put("lastUsed", lastUsed.toString());
|
stateObj.put("lastUsed", lastUsed.toString());
|
||||||
stateObj.put("lastModified", lastModified.toString());
|
stateObj.put("lastModified", lastModified.toString());
|
||||||
stateObj.put("sortMode", sortMode.getId());
|
stateObj.put("sortMode", sortMode.getId());
|
||||||
|
|
|
@ -59,9 +59,6 @@ public class DataStoreEntry extends StorageElement {
|
||||||
@NonFinal
|
@NonFinal
|
||||||
JsonNode storePersistentStateNode;
|
JsonNode storePersistentStateNode;
|
||||||
|
|
||||||
@NonFinal
|
|
||||||
DataStoreColor color;
|
|
||||||
|
|
||||||
@NonFinal
|
@NonFinal
|
||||||
@Setter
|
@Setter
|
||||||
Set<DataStoreEntry> childrenCache = null;
|
Set<DataStoreEntry> childrenCache = null;
|
||||||
|
@ -86,16 +83,15 @@ public class DataStoreEntry extends StorageElement {
|
||||||
Configuration configuration,
|
Configuration configuration,
|
||||||
JsonNode storePersistentState,
|
JsonNode storePersistentState,
|
||||||
boolean expanded,
|
boolean expanded,
|
||||||
DataStoreColor color,
|
DataColor color,
|
||||||
String notes,
|
String notes,
|
||||||
Order explicitOrder) {
|
Order explicitOrder) {
|
||||||
super(directory, uuid, name, lastUsed, lastModified, expanded, dirty);
|
super(directory, uuid, name, lastUsed, lastModified, color, expanded, dirty);
|
||||||
this.categoryUuid = categoryUuid;
|
this.categoryUuid = categoryUuid;
|
||||||
this.store = store;
|
this.store = store;
|
||||||
this.storeNode = storeNode;
|
this.storeNode = storeNode;
|
||||||
this.validity = validity;
|
this.validity = validity;
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
this.color = color;
|
|
||||||
this.explicitOrder = explicitOrder;
|
this.explicitOrder = explicitOrder;
|
||||||
this.provider = store != null ? DataStoreProviders.byStore(store) : null;
|
this.provider = store != null ? DataStoreProviders.byStore(store) : null;
|
||||||
this.storePersistentStateNode = storePersistentState;
|
this.storePersistentStateNode = storePersistentState;
|
||||||
|
@ -111,7 +107,7 @@ public class DataStoreEntry extends StorageElement {
|
||||||
Instant lastModified,
|
Instant lastModified,
|
||||||
DataStore store,
|
DataStore store,
|
||||||
Order explicitOrder) {
|
Order explicitOrder) {
|
||||||
super(directory, uuid, name, lastUsed, lastModified, false,false);
|
super(directory, uuid, name, lastUsed, lastModified, null, false,false);
|
||||||
this.categoryUuid = categoryUuid;
|
this.categoryUuid = categoryUuid;
|
||||||
this.store = store;
|
this.store = store;
|
||||||
this.explicitOrder = explicitOrder;
|
this.explicitOrder = explicitOrder;
|
||||||
|
@ -119,7 +115,6 @@ public class DataStoreEntry extends StorageElement {
|
||||||
this.validity = Validity.INCOMPLETE;
|
this.validity = Validity.INCOMPLETE;
|
||||||
this.configuration = Configuration.defaultConfiguration();
|
this.configuration = Configuration.defaultConfiguration();
|
||||||
this.expanded = false;
|
this.expanded = false;
|
||||||
this.color = null;
|
|
||||||
this.provider = null;
|
this.provider = null;
|
||||||
this.storePersistentStateNode = null;
|
this.storePersistentStateNode = null;
|
||||||
}
|
}
|
||||||
|
@ -225,7 +220,7 @@ public class DataStoreEntry extends StorageElement {
|
||||||
var color = Optional.ofNullable(stateJson.get("color"))
|
var color = Optional.ofNullable(stateJson.get("color"))
|
||||||
.map(node -> {
|
.map(node -> {
|
||||||
try {
|
try {
|
||||||
return mapper.treeToValue(node, DataStoreColor.class);
|
return mapper.treeToValue(node, DataColor.class);
|
||||||
} catch (JsonProcessingException e) {
|
} catch (JsonProcessingException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -372,9 +367,9 @@ public class DataStoreEntry extends StorageElement {
|
||||||
obj.put("uuid", uuid.toString());
|
obj.put("uuid", uuid.toString());
|
||||||
obj.put("name", name);
|
obj.put("name", name);
|
||||||
obj.put("categoryUuid", categoryUuid.toString());
|
obj.put("categoryUuid", categoryUuid.toString());
|
||||||
|
obj.set("color", mapper.valueToTree(color));
|
||||||
stateObj.put("lastUsed", lastUsed.toString());
|
stateObj.put("lastUsed", lastUsed.toString());
|
||||||
stateObj.put("lastModified", lastModified.toString());
|
stateObj.put("lastModified", lastModified.toString());
|
||||||
stateObj.set("color", mapper.valueToTree(color));
|
|
||||||
stateObj.set("persistentState", storePersistentStateNode);
|
stateObj.set("persistentState", storePersistentStateNode);
|
||||||
obj.set("configuration", mapper.valueToTree(configuration));
|
obj.set("configuration", mapper.valueToTree(configuration));
|
||||||
stateObj.put("expanded", expanded);
|
stateObj.put("expanded", expanded);
|
||||||
|
@ -405,14 +400,6 @@ public class DataStoreEntry extends StorageElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setColor(DataStoreColor newColor) {
|
|
||||||
var changed = !Objects.equals(color, newColor);
|
|
||||||
this.color = newColor;
|
|
||||||
if (changed) {
|
|
||||||
notifyUpdate(false, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDisabled() {
|
public boolean isDisabled() {
|
||||||
return validity == Validity.LOAD_FAILED;
|
return validity == Validity.LOAD_FAILED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ public class ImpersistentStorage extends DataStorage {
|
||||||
"Default",
|
"Default",
|
||||||
Instant.now(),
|
Instant.now(),
|
||||||
Instant.now(),
|
Instant.now(),
|
||||||
|
null,
|
||||||
true,
|
true,
|
||||||
ALL_CONNECTIONS_CATEGORY_UUID,
|
ALL_CONNECTIONS_CATEGORY_UUID,
|
||||||
StoreSortMode.getDefault(),
|
StoreSortMode.getDefault(),
|
||||||
|
|
|
@ -223,7 +223,7 @@ public class StandardStorage extends DataStorage {
|
||||||
|
|
||||||
var local = DataStorage.get().getStoreEntry(LOCAL_ID);
|
var local = DataStorage.get().getStoreEntry(LOCAL_ID);
|
||||||
if (storeEntriesSet.stream().noneMatch(entry -> entry.getColor() != null)) {
|
if (storeEntriesSet.stream().noneMatch(entry -> entry.getColor() != null)) {
|
||||||
local.setColor(DataStoreColor.BLUE);
|
local.setColor(DataColor.BLUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reload stores, this time with all entry refs present
|
// Reload stores, this time with all entry refs present
|
||||||
|
|
|
@ -13,6 +13,7 @@ import java.nio.file.Path;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public abstract class StorageElement {
|
public abstract class StorageElement {
|
||||||
|
@ -42,13 +43,18 @@ public abstract class StorageElement {
|
||||||
@Getter
|
@Getter
|
||||||
protected boolean expanded;
|
protected boolean expanded;
|
||||||
|
|
||||||
|
protected @NonFinal
|
||||||
|
@Getter DataColor color;
|
||||||
|
|
||||||
|
|
||||||
public StorageElement(
|
public StorageElement(
|
||||||
Path directory, UUID uuid, String name, Instant lastUsed, Instant lastModified, boolean expanded, boolean dirty) {
|
Path directory, UUID uuid, String name, Instant lastUsed, Instant lastModified, DataColor color, boolean expanded, boolean dirty) {
|
||||||
this.directory = directory;
|
this.directory = directory;
|
||||||
this.uuid = uuid;
|
this.uuid = uuid;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.lastUsed = lastUsed;
|
this.lastUsed = lastUsed;
|
||||||
this.lastModified = lastModified;
|
this.lastModified = lastModified;
|
||||||
|
this.color = color;
|
||||||
this.expanded = expanded;
|
this.expanded = expanded;
|
||||||
this.dirty = dirty;
|
this.dirty = dirty;
|
||||||
}
|
}
|
||||||
|
@ -83,6 +89,14 @@ public abstract class StorageElement {
|
||||||
FileUtils.deleteDirectory(directory.toFile());
|
FileUtils.deleteDirectory(directory.toFile());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setColor(DataColor newColor) {
|
||||||
|
var changed = !Objects.equals(color, newColor);
|
||||||
|
this.color = newColor;
|
||||||
|
if (changed) {
|
||||||
|
notifyUpdate(false, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public abstract void writeDataToDisk() throws Exception;
|
public abstract void writeDataToDisk() throws Exception;
|
||||||
|
|
||||||
public synchronized Instant getLastAccess() {
|
public synchronized Instant getLastAccess() {
|
||||||
|
|
|
@ -7,7 +7,7 @@ import io.xpipe.app.core.window.AppWindowHelper;
|
||||||
import io.xpipe.app.ext.PrefsChoiceValue;
|
import io.xpipe.app.ext.PrefsChoiceValue;
|
||||||
import io.xpipe.app.issue.ErrorEvent;
|
import io.xpipe.app.issue.ErrorEvent;
|
||||||
import io.xpipe.app.prefs.ExternalApplicationType;
|
import io.xpipe.app.prefs.ExternalApplicationType;
|
||||||
import io.xpipe.app.storage.DataStoreColor;
|
import io.xpipe.app.storage.DataColor;
|
||||||
import io.xpipe.app.util.*;
|
import io.xpipe.app.util.*;
|
||||||
import io.xpipe.core.process.*;
|
import io.xpipe.core.process.*;
|
||||||
import io.xpipe.core.store.FilePath;
|
import io.xpipe.core.store.FilePath;
|
||||||
|
@ -1103,7 +1103,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
||||||
|
|
||||||
@Value
|
@Value
|
||||||
class LaunchConfiguration {
|
class LaunchConfiguration {
|
||||||
DataStoreColor color;
|
DataColor color;
|
||||||
String coloredTitle;
|
String coloredTitle;
|
||||||
String cleanTitle;
|
String cleanTitle;
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ public class TerminalLauncher {
|
||||||
throw ErrorEvent.expected(new IllegalStateException(AppI18n.get("noTerminalSet")));
|
throw ErrorEvent.expected(new IllegalStateException(AppI18n.get("noTerminalSet")));
|
||||||
}
|
}
|
||||||
|
|
||||||
var color = entry != null ? DataStorage.get().getRootForEntry(entry).getColor() : null;
|
var color = entry != null ? DataStorage.get().getEffectiveColor(entry) : null;
|
||||||
var prefix = entry != null && color != null && type.supportsColoredTitle() ? color.getEmoji() + " " : "";
|
var prefix = entry != null && color != null && type.supportsColoredTitle() ? color.getEmoji() + " " : "";
|
||||||
var cleanTitle = (title != null ? title : entry != null ? entry.getName() : "?");
|
var cleanTitle = (title != null ? title : entry != null ? entry.getName() : "?");
|
||||||
var adjustedTitle = prefix + cleanTitle;
|
var adjustedTitle = prefix + cleanTitle;
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
.category-button {
|
.category-button {
|
||||||
-fx-opacity: 0.8;
|
|
||||||
-fx-border-width: 0;
|
|
||||||
-fx-background-color: transparent;
|
-fx-background-color: transparent;
|
||||||
|
-fx-background-radius: 4px;
|
||||||
|
-fx-border-radius: 4px;
|
||||||
|
-fx-border-width: 1px;
|
||||||
-fx-padding: 0 0 0 2;
|
-fx-padding: 0 0 0 2;
|
||||||
-fx-background-insets: 0;
|
-fx-background-insets: 0;
|
||||||
}
|
}
|
||||||
|
@ -10,31 +11,43 @@
|
||||||
-fx-background-color: transparent;
|
-fx-background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.category-button .settings {
|
|
||||||
-fx-opacity: 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-button:hover, .root:key-navigation .category-button:focused {
|
.category-button:hover, .root:key-navigation .category-button:focused {
|
||||||
-fx-background-color: -color-bg-default;
|
-fx-background-color: -color-bg-default;
|
||||||
}
|
}
|
||||||
|
|
||||||
.category:selected .category-button {
|
.category:selected .category-button {
|
||||||
-fx-opacity: 1.0;
|
|
||||||
-fx-background-radius: 4px;
|
|
||||||
-fx-border-radius: 4px;
|
|
||||||
-fx-border-width: 1px;
|
|
||||||
-fx-border-color: -color-border-default;
|
-fx-border-color: -color-border-default;
|
||||||
-fx-background-color: -color-bg-default;
|
-fx-background-color: -color-bg-default;
|
||||||
}
|
}
|
||||||
|
|
||||||
.category .separator {
|
.root:light .category.yellow > .category-button .expand-button .ikonli-font-icon {
|
||||||
-fx-padding: 0 5 0 5;
|
-fx-icon-color: #888800;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.root:light .category.green > .category-button .expand-button .ikonli-font-icon {
|
||||||
.category .separator .line {
|
-fx-icon-color: #0d770d;
|
||||||
-fx-pref-height: 1;
|
|
||||||
-fx-background-color: -color-fg-default;
|
|
||||||
-fx-opacity: 0.5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.root:light .category.blue > .category-button .expand-button .ikonli-font-icon {
|
||||||
|
-fx-icon-color: #1c62be;
|
||||||
|
}
|
||||||
|
|
||||||
|
.root:light .category.red > .category-button .expand-button .ikonli-font-icon {
|
||||||
|
-fx-icon-color: #a40000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.root:dark .category.yellow > .category-button .expand-button .ikonli-font-icon {
|
||||||
|
-fx-icon-color: yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
.root:dark .category.green > .category-button .expand-button .ikonli-font-icon {
|
||||||
|
-fx-icon-color: green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.root:dark .category.blue > .category-button .expand-button .ikonli-font-icon {
|
||||||
|
-fx-icon-color: #397fd5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.root:dark .category.red > .category-button .expand-button .ikonli-font-icon {
|
||||||
|
-fx-icon-color: red;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue