From 10dcdbc5e22cf31e65be1caebfb0e479470f087b Mon Sep 17 00:00:00 2001 From: crschnick Date: Wed, 27 Sep 2023 03:01:08 +0000 Subject: [PATCH] Section bug fixes --- .../app/browser/BrowserBookmarkList.java | 2 +- .../storage/store/StoreSectionMiniComp.java | 113 +++++++++--------- .../comp/storage/store/StoreViewState.java | 81 ++++++++----- .../io/xpipe/app/resources/style/bookmark.css | 4 +- .../resources/style/store-mini-section.css | 10 +- 5 files changed, 119 insertions(+), 91 deletions(-) diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserBookmarkList.java b/app/src/main/java/io/xpipe/app/browser/BrowserBookmarkList.java index 8f55b06f4..2f3a20d6d 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserBookmarkList.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserBookmarkList.java @@ -98,7 +98,7 @@ final class BrowserBookmarkList extends SimpleComp { new FilterComp(filterText).styleClass(Styles.RIGHT_PILL).hgrow().apply(struc -> {}); var top = new HorizontalComp(List.of(category, filter.hgrow())) - .styleClass("top") + .styleClass("categories") .apply(struc -> { AppFont.medium(struc.get()); struc.get().setFillHeight(true); diff --git a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreSectionMiniComp.java b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreSectionMiniComp.java index 87c24eb43..5682504e8 100644 --- a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreSectionMiniComp.java +++ b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreSectionMiniComp.java @@ -11,6 +11,7 @@ import io.xpipe.app.fxcomps.impl.VerticalComp; import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.fxcomps.util.SimpleChangeListener; import javafx.beans.binding.Bindings; +import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.css.PseudoClass; import javafx.geometry.Pos; @@ -18,6 +19,7 @@ import javafx.scene.control.Button; import javafx.scene.layout.VBox; import lombok.Builder; +import java.util.ArrayList; import java.util.List; import java.util.function.BiConsumer; @@ -25,11 +27,7 @@ import java.util.function.BiConsumer; public class StoreSectionMiniComp extends Comp> { public static Comp createList(StoreSection top, BiConsumer>> augment) { - var content = new ListBoxViewComp<>(top.getShownChildren(), top.getAllChildren(), (StoreSection e) -> { - var custom = StoreSectionMiniComp.builder().section(e).augment(augment).build().hgrow(); - return new HorizontalComp(List.of(custom)).styleClass("top"); - }); - return content.styleClass("store-mini-list-comp"); + return new StoreSectionMiniComp(top, augment); } private static final PseudoClass ODD = PseudoClass.getPseudoClass("odd-depth"); @@ -43,59 +41,66 @@ public class StoreSectionMiniComp extends Comp> { @Override public CompStructure createBase() { - var root = new ButtonComp(section.getWrapper().nameProperty(), () -> {}) - .apply(struc -> struc.get() - .setGraphic(PrettyImageHelper.ofFixedSmallSquare(section.getWrapper() - .getEntry() - .getProvider() - .getDisplayIconFileName(section.getWrapper() - .getEntry() - .getStore())) - .createRegion())) - .apply(struc -> { - struc.get().setAlignment(Pos.CENTER_LEFT); - }) - .grow(true, false) - .styleClass("item"); - augment.accept(section, root); - - var expanded = new SimpleBooleanProperty(section.getWrapper().getExpanded().get() - && section.getAllChildren().size() > 0); - var button = new IconButtonComp( - Bindings.createStringBinding( - () -> expanded.get() - ? "mdal-keyboard_arrow_down" - : "mdal-keyboard_arrow_right", - expanded), - () -> { - expanded.set(!expanded.get()); - }) - .apply(struc -> struc.get().setMinWidth(20)) - .apply(struc -> struc.get().setPrefWidth(20)) - .focusTraversable() - .accessibleText("Expand") - .disable(BindingsHelper.persist( - Bindings.size(section.getAllChildren()).isEqualTo(0))) - .grow(false, true) - .styleClass("expand-button"); - List> topEntryList = List.of(button, root); - var content = new ListBoxViewComp<>(section.getShownChildren(), section.getAllChildren(), (StoreSection e) -> { - return StoreSectionMiniComp.builder().section(e).augment(this.augment).build(); - }) + return StoreSectionMiniComp.builder().section(e).augment(this.augment).build(); + }) .hgrow(); - return new VerticalComp(List.of( - new HorizontalComp(topEntryList) - .apply(struc -> struc.get().setFillHeight(true)), - Comp.separator().visible(expanded), - new HorizontalComp(List.of(content)) - .styleClass("content") - .apply(struc -> struc.get().setFillHeight(true)) - .hide(BindingsHelper.persist(Bindings.or( - Bindings.not(expanded), - Bindings.size(section.getAllChildren()).isEqualTo(0)))))) + var list = new ArrayList>(); + BooleanProperty expanded; + if (section.getWrapper() != null) { + var root = new ButtonComp(section.getWrapper().nameProperty(), () -> {}) + .apply(struc -> struc.get() + .setGraphic(PrettyImageHelper.ofFixedSmallSquare(section.getWrapper() + .getEntry() + .getProvider() + .getDisplayIconFileName(section.getWrapper() + .getEntry() + .getStore())) + .createRegion())) + .apply(struc -> { + struc.get().setAlignment(Pos.CENTER_LEFT); + }) + .grow(true, false) + .styleClass("item"); + augment.accept(section, root); + + expanded = + new SimpleBooleanProperty(section.getWrapper().getExpanded().get() + && section.getAllChildren().size() > 0); + var button = new IconButtonComp( + Bindings.createStringBinding( + () -> expanded.get() ? "mdal-keyboard_arrow_down" : "mdal-keyboard_arrow_right", + expanded), + () -> { + expanded.set(!expanded.get()); + }) + .apply(struc -> struc.get().setMinWidth(20)) + .apply(struc -> struc.get().setPrefWidth(20)) + .focusTraversable() + .accessibleText("Expand") + .disable(BindingsHelper.persist( + Bindings.size(section.getAllChildren()).isEqualTo(0))) + .grow(false, true) + .styleClass("expand-button"); + List> topEntryList = List.of(button, root); + list.add(new HorizontalComp(topEntryList) + .apply(struc -> struc.get().setFillHeight(true))); + list.add(Comp.separator().visible(expanded)); + } else { + expanded = new SimpleBooleanProperty(true); + } + + list.add(new HorizontalComp(List.of(content)) + .styleClass("content") + .apply(struc -> struc.get().setFillHeight(true)) + .hide(BindingsHelper.persist(Bindings.or( + Bindings.not(expanded), + Bindings.size(section.getAllChildren()).isEqualTo(0))))); + + return new VerticalComp(list) .styleClass("store-section-mini-comp") + .styleClass(section.getWrapper() != null ? "sub" : "top") .apply(struc -> { struc.get().setFillWidth(true); SimpleChangeListener.apply(expanded, val -> { diff --git a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreViewState.java b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreViewState.java index cfb972004..404de65be 100644 --- a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreViewState.java +++ b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreViewState.java @@ -15,9 +15,7 @@ import javafx.collections.FXCollections; import javafx.collections.ObservableList; import lombok.Getter; -import java.util.Arrays; -import java.util.Comparator; -import java.util.UUID; +import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; import java.util.stream.Collectors; @@ -134,40 +132,54 @@ public class StoreViewState { } private void addStorageListeners() { + // Watch out for synchronizing all calls to the entries and categories list! DataStorage.get().addListener(new StorageListener() { @Override public void onStoreAdd(DataStoreEntry... entry) { var l = Arrays.stream(entry).map(StoreEntryWrapper::new).toList(); Platform.runLater(() -> { - allEntries.addAll(l); - categories.stream() - .filter(storeCategoryWrapper -> allEntries.stream() - .anyMatch(storeEntryWrapper -> storeEntryWrapper - .getEntry() - .getCategoryUuid() - .equals(storeCategoryWrapper - .getCategory() - .getUuid()))) - .forEach(storeCategoryWrapper -> storeCategoryWrapper.update()); + synchronized (allEntries) { + allEntries.addAll(l); + } + synchronized (categories) { + categories.stream() + .filter(storeCategoryWrapper -> allEntries.stream() + .anyMatch(storeEntryWrapper -> storeEntryWrapper + .getEntry() + .getCategoryUuid() + .equals(storeCategoryWrapper + .getCategory() + .getUuid()))) + .forEach(storeCategoryWrapper -> storeCategoryWrapper.update()); + } }); } @Override public void onStoreRemove(DataStoreEntry... entry) { var a = Arrays.stream(entry).collect(Collectors.toSet()); - var l = StoreViewState.get().getAllEntries().stream() - .filter(storeEntryWrapper -> a.contains(storeEntryWrapper.getEntry())) - .toList(); - var cats = categories.stream() - .filter(storeCategoryWrapper -> allEntries.stream() - .anyMatch(storeEntryWrapper -> storeEntryWrapper - .getEntry() - .getCategoryUuid() - .equals(storeCategoryWrapper - .getCategory() - .getUuid()))).toList(); + List l; + synchronized (allEntries) { + l = allEntries.stream() + .filter(storeEntryWrapper -> a.contains(storeEntryWrapper.getEntry())) + .toList(); + } + List cats; + synchronized (categories) { + cats = categories.stream() + .filter(storeCategoryWrapper -> allEntries.stream() + .anyMatch(storeEntryWrapper -> storeEntryWrapper + .getEntry() + .getCategoryUuid() + .equals(storeCategoryWrapper + .getCategory() + .getUuid()))) + .toList(); + } Platform.runLater(() -> { - allEntries.removeAll(l); + synchronized (allEntries) { + allEntries.removeAll(l); + } cats.forEach(storeCategoryWrapper -> storeCategoryWrapper.update()); }); } @@ -176,23 +188,30 @@ public class StoreViewState { public void onCategoryAdd(DataStoreCategory category) { var l = new StoreCategoryWrapper(category); Platform.runLater(() -> { - categories.add(l); + synchronized (categories) { + categories.add(l); + } l.update(); }); } @Override public void onCategoryRemove(DataStoreCategory category) { - var found = categories.stream() - .filter(storeCategoryWrapper -> - storeCategoryWrapper.getCategory().equals(category)) - .findFirst(); + Optional found; + synchronized (categories) { + found = categories.stream() + .filter(storeCategoryWrapper -> + storeCategoryWrapper.getCategory().equals(category)) + .findFirst(); + } if (found.isEmpty()) { return; } Platform.runLater(() -> { - categories.remove(found.get()); + synchronized (categories) { + categories.remove(found.get()); + } var p = found.get().getParent(); if (p != null) { p.update(); diff --git a/app/src/main/resources/io/xpipe/app/resources/style/bookmark.css b/app/src/main/resources/io/xpipe/app/resources/style/bookmark.css index b80b07667..be92da67b 100644 --- a/app/src/main/resources/io/xpipe/app/resources/style/bookmark.css +++ b/app/src/main/resources/io/xpipe/app/resources/style/bookmark.css @@ -1,6 +1,6 @@ -.bookmark-list > .top { --fx-padding: 0.5em 1em 0.5em 1em; +.bookmark-list > .categories { +-fx-padding: 0.7em 1em 0.7em 1em; -fx-background-color: -color-neutral-subtle; } diff --git a/app/src/main/resources/io/xpipe/app/resources/style/store-mini-section.css b/app/src/main/resources/io/xpipe/app/resources/style/store-mini-section.css index 606f18a2f..af4a54f29 100644 --- a/app/src/main/resources/io/xpipe/app/resources/style/store-mini-section.css +++ b/app/src/main/resources/io/xpipe/app/resources/style/store-mini-section.css @@ -26,12 +26,12 @@ -fx-background-color: -color-accent-subtle; } -.root:light .store-section-mini-comp:expanded:even-depth { +.root:light .store-section-mini-comp.sub:expanded:even-depth { -fx-background-color: #9991; -fx-border-color: -color-border-subtle; } -.root:dark .store-section-mini-comp:expanded:even-depth { +.root:dark .store-section-mini-comp.sub:expanded:even-depth { -fx-background-color: #0002; -fx-border-color: -color-border-subtle; } @@ -54,6 +54,10 @@ -fx-padding: 5px 0 5px 15px; } +.store-section-mini-comp.top > .content { + -fx-padding: 0; +} + .store-section-mini-comp .separator .line { -fx-padding: 0; -fx-border-insets: 0px; @@ -70,7 +74,7 @@ -fx-background-color: #0001; } -.store-section-mini-comp:expanded { +.store-section-mini-comp.sub:expanded { -fx-border-radius: 2px; -fx-border-width: 1px 0 1px 1px; -fx-border-color: -color-border-default;