From de1daa3e025a34b8bae8cd33fb8bd58d5629ab88 Mon Sep 17 00:00:00 2001 From: crschnick Date: Sun, 30 Mar 2025 10:49:28 +0000 Subject: [PATCH] Race condition fixes [stage] --- .../BrowserFileChooserSessionComp.java | 10 +++-- .../app/browser/BrowserFullSessionComp.java | 35 +++++++++------- .../file/BrowserConnectionListFilterComp.java | 7 ++-- .../xpipe/app/comp/base/DelayedInitComp.java | 38 +++++++++++++++++ .../xpipe/app/comp/store/StoreLayoutComp.java | 41 ++++++++----------- .../io/xpipe/app/prefs/TerminalCategory.java | 15 ++++--- version | 2 +- 7 files changed, 94 insertions(+), 54 deletions(-) create mode 100644 app/src/main/java/io/xpipe/app/comp/base/DelayedInitComp.java diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserFileChooserSessionComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserFileChooserSessionComp.java index cbbd878c8..bfd81f2f3 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserFileChooserSessionComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserFileChooserSessionComp.java @@ -8,6 +8,7 @@ import io.xpipe.app.browser.file.BrowserFileSystemTabModel; import io.xpipe.app.comp.Comp; import io.xpipe.app.comp.base.*; import io.xpipe.app.comp.store.StoreEntryWrapper; +import io.xpipe.app.comp.store.StoreViewState; import io.xpipe.app.core.AppFontSizes; import io.xpipe.app.core.AppLayoutModel; import io.xpipe.app.ext.ShellStore; @@ -19,6 +20,7 @@ import io.xpipe.app.util.ThreadHelper; import io.xpipe.core.store.FileSystemStore; import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; import javafx.collections.ListChangeListener; import javafx.scene.layout.Region; @@ -101,14 +103,16 @@ public class BrowserFileChooserSessionComp extends ModalOverlayContentComp { }); }; - var bookmarkTopBar = new BrowserConnectionListFilterComp(); + var category = new SimpleObjectProperty<>(StoreViewState.get().getActiveCategory().getValue()); + var filter = new SimpleStringProperty(); + var bookmarkTopBar = new BrowserConnectionListFilterComp(category, filter); var bookmarksList = new BrowserConnectionListComp( BindingsHelper.map( model.getSelectedEntry(), v -> v != null ? v.getEntry().get() : null), applicable, action, - bookmarkTopBar.getCategory(), - bookmarkTopBar.getFilter()); + category, + filter); var bookmarksContainer = new StackComp(List.of(bookmarksList)).styleClass("bookmarks-container"); bookmarksContainer .apply(struc -> { diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserFullSessionComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserFullSessionComp.java index 2b83c689d..a7f81bca5 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserFullSessionComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserFullSessionComp.java @@ -6,15 +6,13 @@ import io.xpipe.app.browser.file.BrowserTransferComp; import io.xpipe.app.comp.Comp; import io.xpipe.app.comp.CompStructure; import io.xpipe.app.comp.SimpleComp; -import io.xpipe.app.comp.base.AnchorComp; -import io.xpipe.app.comp.base.LeftSplitPaneComp; -import io.xpipe.app.comp.base.LoadingOverlayComp; -import io.xpipe.app.comp.base.StackComp; -import io.xpipe.app.comp.base.VerticalComp; +import io.xpipe.app.comp.base.*; import io.xpipe.app.comp.store.StoreEntryWrapper; +import io.xpipe.app.comp.store.StoreViewState; import io.xpipe.app.core.AppLayoutModel; import io.xpipe.app.ext.ShellStore; import io.xpipe.app.util.BindingsHelper; +import io.xpipe.app.util.GlobalTimer; import io.xpipe.app.util.PlatformThread; import io.xpipe.app.util.ThreadHelper; @@ -22,12 +20,16 @@ import javafx.application.Platform; import javafx.beans.binding.Bindings; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleDoubleProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; import javafx.geometry.Insets; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import javafx.scene.shape.Rectangle; +import java.time.Duration; import java.util.HashMap; import java.util.List; import java.util.function.BiConsumer; @@ -43,7 +45,7 @@ public class BrowserFullSessionComp extends SimpleComp { @Override protected Region createSimple() { - var vertical = createLeftSide(); + var left = Comp.of(() -> createLeftSide()); var leftSplit = new SimpleDoubleProperty(); var rightSplit = new SimpleDoubleProperty(); @@ -57,7 +59,7 @@ public class BrowserFullSessionComp extends SimpleComp { AnchorPane.setRightAnchor(struc.get(), 0.0); }); - vertical.apply(struc -> { + left.apply(struc -> { struc.get() .paddingProperty() .bind(Bindings.createObjectBinding( @@ -74,7 +76,8 @@ public class BrowserFullSessionComp extends SimpleComp { var loadingStack = new AnchorComp(List.of(tabs, pinnedStack, loadingIndicator)); loadingStack.apply(struc -> struc.get().setPickOnBounds(false)); - var splitPane = new LeftSplitPaneComp(vertical, loadingStack) + var delayedStack = new DelayedInitComp(left, () -> StoreViewState.get() != null && StoreViewState.get().isInitialized()); + var splitPane = new LeftSplitPaneComp(delayedStack, loadingStack) .withInitialWidth(AppLayoutModel.get().getSavedState().getBrowserConnectionsWidth()) .withOnDividerChange(d -> { AppLayoutModel.get().getSavedState().setBrowserConnectionsWidth(d); @@ -104,7 +107,7 @@ public class BrowserFullSessionComp extends SimpleComp { return r; } - private Comp> createLeftSide() { + private Region createLeftSide() { Predicate applicable = storeEntryWrapper -> { if (!storeEntryWrapper.getEntry().getValidity().isUsable()) { return false; @@ -131,7 +134,10 @@ public class BrowserFullSessionComp extends SimpleComp { }); }; - var bookmarkTopBar = new BrowserConnectionListFilterComp(); + + var category = new SimpleObjectProperty<>(StoreViewState.get().getActiveCategory().getValue()); + var filter = new SimpleStringProperty(); + var bookmarkTopBar = new BrowserConnectionListFilterComp(category, filter); var bookmarksList = new BrowserConnectionListComp( BindingsHelper.map( model.getSelectedEntry(), @@ -140,8 +146,8 @@ public class BrowserFullSessionComp extends SimpleComp { : null), applicable, action, - bookmarkTopBar.getCategory(), - bookmarkTopBar.getFilter()); + category, + filter); var bookmarksContainer = new StackComp(List.of(bookmarksList)).styleClass("bookmarks-container"); bookmarksContainer .apply(struc -> { @@ -166,9 +172,8 @@ public class BrowserFullSessionComp extends SimpleComp { model.getSelectedEntry()))); localDownloadStage.prefHeight(200); localDownloadStage.maxHeight(200); - var vertical = - new VerticalComp(List.of(bookmarkTopBar, bookmarksContainer, localDownloadStage)).styleClass("left"); - return vertical; + var vertical = new VerticalComp(List.of(bookmarkTopBar, bookmarksContainer, localDownloadStage)).styleClass("left"); + return vertical.createRegion(); } private StackComp createSplitStack(SimpleDoubleProperty rightSplit, BrowserSessionTabsComp tabs) { diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserConnectionListFilterComp.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserConnectionListFilterComp.java index 428457d20..93475f38f 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserConnectionListFilterComp.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserConnectionListFilterComp.java @@ -14,16 +14,17 @@ import javafx.beans.property.SimpleStringProperty; import javafx.scene.layout.Region; import atlantafx.base.theme.Styles; +import lombok.AllArgsConstructor; import lombok.Getter; import java.util.List; @Getter +@AllArgsConstructor public final class BrowserConnectionListFilterComp extends SimpleComp { - private final Property category = - new SimpleObjectProperty<>(StoreViewState.get().getActiveCategory().getValue()); - private final Property filter = new SimpleStringProperty(); + private final Property category; + private final Property filter; @Override protected Region createSimple() { diff --git a/app/src/main/java/io/xpipe/app/comp/base/DelayedInitComp.java b/app/src/main/java/io/xpipe/app/comp/base/DelayedInitComp.java new file mode 100644 index 000000000..5643140a4 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/comp/base/DelayedInitComp.java @@ -0,0 +1,38 @@ +package io.xpipe.app.comp.base; + +import io.xpipe.app.comp.Comp; +import io.xpipe.app.comp.SimpleComp; +import io.xpipe.app.comp.store.StoreViewState; +import io.xpipe.app.util.GlobalTimer; +import javafx.application.Platform; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import lombok.AllArgsConstructor; + +import java.time.Duration; +import java.util.function.Supplier; + +@AllArgsConstructor +public class DelayedInitComp extends SimpleComp { + + private final Comp comp; + private final Supplier condition; + + @Override + protected Region createSimple() { + var stack = new StackPane(); + GlobalTimer.scheduleUntil(Duration.ofMillis(10), () -> { + if (!condition.get()) { + return false; + } + + Platform.runLater(() -> { + var r = comp.createRegion(); + stack.getChildren().add(r); + }); + return true; + }); + return stack; + } + +} diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreLayoutComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreLayoutComp.java index 85f696e19..680154a11 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreLayoutComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreLayoutComp.java @@ -1,6 +1,8 @@ package io.xpipe.app.comp.store; +import io.xpipe.app.comp.Comp; import io.xpipe.app.comp.SimpleComp; +import io.xpipe.app.comp.base.DelayedInitComp; import io.xpipe.app.comp.base.LeftSplitPaneComp; import io.xpipe.app.core.AppActionLinkDetector; import io.xpipe.app.core.AppLayoutModel; @@ -20,36 +22,27 @@ public class StoreLayoutComp extends SimpleComp { @Override protected Region createSimple() { - var stack = new StackPane(); - GlobalTimer.scheduleUntil(Duration.ofMillis(10), () -> { - if (StoreViewState.get() == null || !StoreViewState.get().isInitialized()) { - return false; - } - - Platform.runLater(() -> { - var r = createContent(); - stack.getChildren().add(r); - }); - return true; - }); - return stack; + var delayed = new DelayedInitComp(Comp.of(() -> createContent()), () -> StoreViewState.get() != null && StoreViewState.get().isInitialized()); + return delayed.createRegion(); } private Region createContent() { - var struc = new LeftSplitPaneComp(new StoreSidebarComp(), new StoreEntryListComp()) + var left = new StoreSidebarComp(); + left.minWidth(270); + left.maxWidth(500); + var comp = new LeftSplitPaneComp(left, new StoreEntryListComp()) .withInitialWidth(AppLayoutModel.get().getSavedState().getSidebarWidth()) .withOnDividerChange(aDouble -> { AppLayoutModel.get().getSavedState().setSidebarWidth(aDouble); - }) - .createStructure(); - struc.getLeft().setMinWidth(270); - struc.getLeft().setMaxWidth(500); - struc.get().getStyleClass().add("store-layout"); - InputHelper.onKeyCombination( - struc.get(), new KeyCodeCombination(KeyCode.V, KeyCombination.SHORTCUT_DOWN), true, keyEvent -> { - AppActionLinkDetector.detectOnPaste(); - keyEvent.consume(); }); - return struc.get(); + comp.styleClass("store-layout"); + comp.apply(struc -> { + InputHelper.onKeyCombination( + struc.get(), new KeyCodeCombination(KeyCode.V, KeyCombination.SHORTCUT_DOWN), true, keyEvent -> { + AppActionLinkDetector.detectOnPaste(); + keyEvent.consume(); + }); + }); + return comp.createRegion(); } } diff --git a/app/src/main/java/io/xpipe/app/prefs/TerminalCategory.java b/app/src/main/java/io/xpipe/app/prefs/TerminalCategory.java index 34df65821..df0bf0996 100644 --- a/app/src/main/java/io/xpipe/app/prefs/TerminalCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/TerminalCategory.java @@ -165,17 +165,16 @@ public class TerminalCategory extends AppPrefsCategory { ref.addListener((observable, oldValue, newValue) -> { prefs.terminalProxy.setValue(newValue != null ? newValue.get().getUuid() : null); }); + var proxyChoice = new DelayedInitComp(Comp.of(() -> { + var comp = new StoreChoiceComp<>(StoreChoiceComp.Mode.PROXY, null, ref, ShellStore.class, + r -> TerminalProxyManager.canUseAsProxy(r), StoreViewState.get().getAllConnectionsCategory()); + return comp.createRegion(); + }), () -> StoreViewState.get() != null && StoreViewState.get().isInitialized()); + proxyChoice.maxWidth(getCompWidth()); return new OptionsBuilder() .nameAndDescription("terminalEnvironment") .addComp( - new StoreChoiceComp<>( - StoreChoiceComp.Mode.PROXY, - null, - ref, - ShellStore.class, - r -> TerminalProxyManager.canUseAsProxy(r), - StoreViewState.get().getAllConnectionsCategory()) - .maxWidth(getCompWidth()), + proxyChoice, ref) .hide(OsType.getLocal() != OsType.WINDOWS); } diff --git a/version b/version index c1e288da9..25f696b11 100644 --- a/version +++ b/version @@ -1 +1 @@ -16.0-4 +16.0-5