mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-22 15:40:23 +00:00
Implement sorting
This commit is contained in:
parent
202f9e4939
commit
473974ada9
7 changed files with 209 additions and 16 deletions
|
@ -12,7 +12,7 @@ import javafx.scene.control.ScrollPane;
|
|||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
@ -34,7 +34,7 @@ public class ListBoxViewComp<T> extends Comp<CompStructure<ScrollPane>> {
|
|||
|
||||
@Override
|
||||
public CompStructure<ScrollPane> createBase() {
|
||||
Map<T, Region> cache = new HashMap<>();
|
||||
Map<T, Region> cache = new IdentityHashMap<>();
|
||||
|
||||
VBox vbox = new VBox();
|
||||
vbox.getStyleClass().add("content");
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
package io.xpipe.app.comp.storage.store;
|
||||
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.SimpleComp;
|
||||
import io.xpipe.app.fxcomps.impl.FancyTooltipAugment;
|
||||
import io.xpipe.app.fxcomps.impl.HorizontalComp;
|
||||
import io.xpipe.app.fxcomps.impl.IconButtonComp;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyCodeCombination;
|
||||
import javafx.scene.input.KeyCombination;
|
||||
import javafx.scene.layout.Region;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class StoreOrganizationComp extends SimpleComp {
|
||||
|
||||
private final Property<StoreSortMode> sortMode;
|
||||
|
||||
public StoreOrganizationComp() {
|
||||
this.sortMode = StoreViewState.get().getSortMode();
|
||||
}
|
||||
|
||||
private Comp<?> createAlphabeticalSortButton() {
|
||||
var icon = Bindings.createStringBinding(
|
||||
() -> {
|
||||
if (sortMode.getValue() == StoreSortMode.ALPHABETICAL_ASC) {
|
||||
return "mdi2s-sort-alphabetical-descending";
|
||||
}
|
||||
if (sortMode.getValue() == StoreSortMode.ALPHABETICAL_DESC) {
|
||||
return "mdi2s-sort-alphabetical-ascending";
|
||||
}
|
||||
return "mdi2s-sort-alphabetical-descending";
|
||||
},
|
||||
sortMode);
|
||||
var alphabetical = new IconButtonComp(icon, () -> {
|
||||
if (sortMode.getValue() == StoreSortMode.ALPHABETICAL_ASC) {
|
||||
sortMode.setValue(StoreSortMode.ALPHABETICAL_DESC);
|
||||
} else if (sortMode.getValue() == StoreSortMode.ALPHABETICAL_DESC) {
|
||||
sortMode.setValue(StoreSortMode.ALPHABETICAL_ASC);
|
||||
} else {
|
||||
sortMode.setValue(StoreSortMode.ALPHABETICAL_ASC);
|
||||
}
|
||||
});
|
||||
alphabetical.apply(alphabeticalR -> {
|
||||
alphabeticalR
|
||||
.get()
|
||||
.opacityProperty()
|
||||
.bind(Bindings.createDoubleBinding(
|
||||
() -> {
|
||||
if (sortMode.getValue() == StoreSortMode.ALPHABETICAL_ASC
|
||||
|| sortMode.getValue() == StoreSortMode.ALPHABETICAL_DESC) {
|
||||
return 1.0;
|
||||
}
|
||||
return 0.4;
|
||||
},
|
||||
sortMode));
|
||||
});
|
||||
alphabetical.apply(new FancyTooltipAugment<>("sortAlphabetical"));
|
||||
alphabetical.shortcut(new KeyCodeCombination(KeyCode.P, KeyCombination.SHORTCUT_DOWN));
|
||||
return alphabetical;
|
||||
}
|
||||
|
||||
private Comp<?> createDateSortButton() {
|
||||
var icon = Bindings.createStringBinding(
|
||||
() -> {
|
||||
if (sortMode.getValue() == StoreSortMode.DATE_ASC) {
|
||||
return "mdi2s-sort-clock-ascending-outline";
|
||||
}
|
||||
if (sortMode.getValue() == StoreSortMode.DATE_DESC) {
|
||||
return "mdi2s-sort-clock-descending-outline";
|
||||
}
|
||||
return "mdi2s-sort-clock-ascending-outline";
|
||||
},
|
||||
sortMode);
|
||||
var date = new IconButtonComp(icon, () -> {
|
||||
if (sortMode.getValue() == StoreSortMode.DATE_ASC) {
|
||||
sortMode.setValue(StoreSortMode.DATE_DESC);
|
||||
} else if (sortMode.getValue() == StoreSortMode.DATE_DESC) {
|
||||
sortMode.setValue(StoreSortMode.DATE_ASC);
|
||||
} else {
|
||||
sortMode.setValue(StoreSortMode.DATE_ASC);
|
||||
}
|
||||
});
|
||||
date.apply(dateR -> {
|
||||
dateR.get()
|
||||
.opacityProperty()
|
||||
.bind(Bindings.createDoubleBinding(
|
||||
() -> {
|
||||
if (sortMode.getValue() == StoreSortMode.DATE_ASC
|
||||
|| sortMode.getValue() == StoreSortMode.DATE_DESC) {
|
||||
return 1.0;
|
||||
}
|
||||
return 0.4;
|
||||
},
|
||||
sortMode));
|
||||
});
|
||||
date.apply(new FancyTooltipAugment<>("sortLastUsed"));
|
||||
date.shortcut(new KeyCodeCombination(KeyCode.L, KeyCombination.SHORTCUT_DOWN));
|
||||
return date;
|
||||
}
|
||||
|
||||
private Comp<?> createSortButtonBar() {
|
||||
return new HorizontalComp(List.of(createDateSortButton(), createAlphabeticalSortButton()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Region createSimple() {
|
||||
return createSortButtonBar().styleClass("bar").prefHeight(40).createRegion();
|
||||
}
|
||||
}
|
|
@ -8,11 +8,11 @@ import io.xpipe.app.storage.DataStoreEntry;
|
|||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.value.ObservableBooleanValue;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import lombok.Value;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Comparator;
|
||||
|
||||
@Value
|
||||
|
@ -32,6 +32,12 @@ public class StoreSection implements StorageFilter.Filterable {
|
|||
int depth;
|
||||
ObservableBooleanValue showDetails;
|
||||
|
||||
|
||||
static ObservableValue<Comparator<StoreSection>> sortMode = Bindings.createObjectBinding(() -> {
|
||||
return Comparator.<StoreSection>comparingInt(value -> value.getWrapper().getEntry().getState().isUsable() ? 1 : -1)
|
||||
.thenComparing(StoreViewState.get().getSortMode().getValue().comparator());
|
||||
}, StoreViewState.get().getSortMode());
|
||||
|
||||
public StoreSection(StoreEntryWrapper wrapper, ObservableList<StoreSection> children, int depth) {
|
||||
this.wrapper = wrapper;
|
||||
this.children = children;
|
||||
|
@ -48,14 +54,6 @@ public class StoreSection implements StorageFilter.Filterable {
|
|||
}
|
||||
}
|
||||
|
||||
private static final Comparator<StoreSection> COMPARATOR = Comparator.<StoreSection, Instant>comparing(
|
||||
o -> o.wrapper.getEntry().getState().isUsable()
|
||||
? o.wrapper.getEntry().getLastModified()
|
||||
: Instant.EPOCH)
|
||||
.reversed()
|
||||
.thenComparing(
|
||||
storeEntrySection -> storeEntrySection.wrapper.getEntry().getName());
|
||||
|
||||
public static StoreSection createTopLevel() {
|
||||
var topLevel = BindingsHelper.cachedMappedContentBinding(
|
||||
StoreViewState.get().getAllEntries(), storeEntryWrapper -> create(storeEntryWrapper, 1));
|
||||
|
@ -64,7 +62,7 @@ public class StoreSection implements StorageFilter.Filterable {
|
|||
.getParent(section.getWrapper().getEntry(), true)
|
||||
.isEmpty();
|
||||
});
|
||||
var ordered = BindingsHelper.orderedContentBinding(filtered, COMPARATOR);
|
||||
var ordered = BindingsHelper.orderedContentBinding(filtered, sortMode);
|
||||
return new StoreSection(null, ordered, 0);
|
||||
}
|
||||
|
||||
|
@ -81,7 +79,7 @@ public class StoreSection implements StorageFilter.Filterable {
|
|||
.orElse(false);
|
||||
});
|
||||
var children = BindingsHelper.cachedMappedContentBinding(filtered, entry1 -> create(entry1, depth + 1));
|
||||
var ordered = BindingsHelper.orderedContentBinding(children, COMPARATOR);
|
||||
var ordered = BindingsHelper.orderedContentBinding(children, sortMode);
|
||||
return new StoreSection(e, ordered, depth);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,13 +10,15 @@ import javafx.scene.layout.VBox;
|
|||
import java.util.List;
|
||||
|
||||
public class StoreSidebarComp extends SimpleComp {
|
||||
|
||||
@Override
|
||||
protected Region createSimple() {
|
||||
var sideBar = new VerticalComp(List.of(
|
||||
new StoreEntryListHeaderComp(),
|
||||
new StoreCreationBarComp(),
|
||||
new StoreOrganizationComp(),
|
||||
Comp.of(() -> new Region()).styleClass("bar").styleClass("filler-bar")));
|
||||
sideBar.apply(s -> VBox.setVgrow(s.get().getChildren().get(2), Priority.ALWAYS));
|
||||
sideBar.apply(s -> VBox.setVgrow(s.get().getChildren().get(3), Priority.ALWAYS));
|
||||
sideBar.styleClass("sidebar");
|
||||
return sideBar.createRegion();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
package io.xpipe.app.comp.storage.store;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Comparator;
|
||||
import java.util.Locale;
|
||||
|
||||
public interface StoreSortMode {
|
||||
|
||||
static StoreSortMode ALPHABETICAL_DESC = new StoreSortMode() {
|
||||
@Override
|
||||
public String getId() {
|
||||
return "alphabetical-desc";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Comparator<StoreSection> comparator() {
|
||||
return Comparator.<StoreSection, String>comparing(
|
||||
e -> e.getWrapper().getName().toLowerCase(Locale.ROOT));
|
||||
}
|
||||
};
|
||||
|
||||
static StoreSortMode ALPHABETICAL_ASC = new StoreSortMode() {
|
||||
@Override
|
||||
public String getId() {
|
||||
return "alphabetical-asc";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Comparator<StoreSection> comparator() {
|
||||
return Comparator.<StoreSection, String>comparing(
|
||||
e -> e.getWrapper().getName().toLowerCase(Locale.ROOT))
|
||||
.reversed();
|
||||
}
|
||||
};
|
||||
|
||||
static StoreSortMode DATE_DESC = new StoreSortMode() {
|
||||
@Override
|
||||
public String getId() {
|
||||
return "date-desc";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Comparator<StoreSection> comparator() {
|
||||
return Comparator.<StoreSection, Instant>comparing(
|
||||
e -> e.getWrapper().getLastAccess());
|
||||
}
|
||||
};
|
||||
|
||||
static StoreSortMode DATE_ASC = new StoreSortMode() {
|
||||
@Override
|
||||
public String getId() {
|
||||
return "date-asc";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Comparator<StoreSection> comparator() {
|
||||
return Comparator.<StoreSection, Instant>comparing(e -> e.getWrapper().getLastAccess())
|
||||
.reversed();
|
||||
}
|
||||
};
|
||||
|
||||
String getId();
|
||||
|
||||
Comparator<StoreSection> comparator();
|
||||
}
|
|
@ -1,15 +1,18 @@
|
|||
package io.xpipe.app.comp.storage.store;
|
||||
|
||||
import io.xpipe.app.comp.storage.StorageFilter;
|
||||
import io.xpipe.app.core.AppCache;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.storage.DataStoreEntry;
|
||||
import io.xpipe.app.storage.StorageListener;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
|
@ -28,7 +31,17 @@ public class StoreViewState {
|
|||
private final ObservableList<StoreEntryWrapper> shownEntries =
|
||||
FXCollections.observableList(new CopyOnWriteArrayList<>());
|
||||
|
||||
@Getter
|
||||
private final Property<StoreSortMode> sortMode;
|
||||
|
||||
|
||||
private StoreViewState() {
|
||||
var val = AppCache.getIfPresent("sortMode", StoreSortMode.class).orElse(StoreSortMode.ALPHABETICAL_DESC);
|
||||
this.sortMode = new SimpleObjectProperty<>(val);
|
||||
this.sortMode.addListener((observable, oldValue, newValue) -> {
|
||||
AppCache.update("sortMode", newValue.getId());
|
||||
});
|
||||
|
||||
try {
|
||||
addStorageGroupListeners();
|
||||
addShownContentChangeListeners();
|
||||
|
|
|
@ -142,15 +142,18 @@ public class BindingsHelper {
|
|||
return l1;
|
||||
}
|
||||
|
||||
public static <V> ObservableList<V> orderedContentBinding(ObservableList<V> l2, Comparator<V> comp) {
|
||||
public static <V> ObservableList<V> orderedContentBinding(ObservableList<V> l2, ObservableValue<Comparator<V>> comp) {
|
||||
ObservableList<V> l1 = FXCollections.observableList(new ArrayList<>());
|
||||
Runnable runnable = () -> {
|
||||
setContent(l1, l2.stream().sorted(comp).toList());
|
||||
setContent(l1, l2.stream().sorted(comp.getValue()).toList());
|
||||
};
|
||||
runnable.run();
|
||||
l2.addListener((ListChangeListener<? super V>) c -> {
|
||||
runnable.run();
|
||||
});
|
||||
comp.addListener((observable, oldValue, newValue) -> {
|
||||
runnable.run();
|
||||
});
|
||||
linkPersistently(l2, l1);
|
||||
return l1;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue