diff --git a/app/src/main/java/io/xpipe/app/comp/base/OptionsComp.java b/app/src/main/java/io/xpipe/app/comp/base/OptionsComp.java index c744cc8cc..13c8b140e 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/OptionsComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/OptionsComp.java @@ -11,6 +11,7 @@ import javafx.beans.Observable; import javafx.beans.binding.Bindings; import javafx.beans.property.SimpleStringProperty; import javafx.beans.value.ObservableValue; +import javafx.geometry.Insets; import javafx.geometry.Orientation; import javafx.geometry.Pos; import javafx.scene.control.Button; @@ -38,9 +39,7 @@ public class OptionsComp extends Comp> { @Override public CompStructure createBase() { - Pane pane; - var content = new VBox(); - pane = content; + Pane pane = new VBox(); pane.getStyleClass().add("options-comp"); var nameRegions = new ArrayList(); @@ -76,6 +75,7 @@ public class OptionsComp extends Comp> { name.managedProperty().bind(PlatformThread.sync(compRegion.managedProperty())); } line.getChildren().add(name); + VBox.setMargin(name, new Insets(0, 0, 0, 1)); if (entry.description() != null) { var description = new Label(); @@ -132,6 +132,7 @@ public class OptionsComp extends Comp> { HBox.setHgrow(descriptionBox, Priority.ALWAYS); descriptionBox.setAlignment(Pos.CENTER_LEFT); line.getChildren().add(descriptionBox); + VBox.setMargin(descriptionBox, new Insets(0, 0, 0, 1)); if (compRegion != null) { descriptionBox.visibleProperty().bind(PlatformThread.sync(compRegion.visibleProperty())); @@ -140,6 +141,7 @@ public class OptionsComp extends Comp> { } else { line.getChildren().add(description); line.getChildren().add(new Spacer(2, Orientation.VERTICAL)); + VBox.setMargin(description, new Insets(0, 0, 0, 1)); } } @@ -187,7 +189,7 @@ public class OptionsComp extends Comp> { var last = entry.equals(entries.getLast()); if (!last) { Spacer spacer = new Spacer(7, Orientation.VERTICAL); - content.getChildren().add(spacer); + pane.getChildren().add(spacer); if (compRegion != null) { spacer.visibleProperty().bind(PlatformThread.sync(compRegion.visibleProperty())); spacer.managedProperty().bind(PlatformThread.sync(compRegion.managedProperty())); diff --git a/app/src/main/java/io/xpipe/app/comp/base/ScrollComp.java b/app/src/main/java/io/xpipe/app/comp/base/ScrollComp.java index 680cd36dd..bb9197a88 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/ScrollComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/ScrollComp.java @@ -8,6 +8,7 @@ import javafx.beans.binding.Bindings; import javafx.scene.control.ScrollBar; import javafx.scene.control.ScrollPane; import javafx.scene.control.skin.ScrollPaneSkin; +import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; public class ScrollComp extends Comp> { @@ -20,7 +21,8 @@ public class ScrollComp extends Comp> { @Override public CompStructure createBase() { - var stack = new StackPane(content.createRegion()); + var r = content.createRegion(); + var stack = new StackPane(r); stack.getStyleClass().add("scroll-comp-content"); var sp = new ScrollPane(stack); @@ -29,7 +31,6 @@ public class ScrollComp extends Comp> { sp.setVbarPolicy(ScrollPane.ScrollBarPolicy.ALWAYS); sp.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); sp.setSkin(new ScrollPaneSkin(sp)); - sp.prefHeightProperty().bind(stack.heightProperty()); ScrollBar bar = (ScrollBar) sp.lookup(".scroll-bar:vertical"); bar.opacityProperty() diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreCategoryConfigComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreCategoryConfigComp.java index b957e81a1..8bfc04bed 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreCategoryConfigComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreCategoryConfigComp.java @@ -15,7 +15,9 @@ import javafx.beans.property.Property; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ObservableValue; +import javafx.scene.control.ScrollPane; import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; import lombok.AllArgsConstructor; import java.util.Arrays; @@ -26,7 +28,7 @@ public class StoreCategoryConfigComp extends SimpleComp { public static void show(StoreCategoryWrapper wrapper) { var config = new SimpleObjectProperty<>(wrapper.getCategory().getConfig()); - var comp = new ScrollComp(new StoreCategoryConfigComp(wrapper, config)); + var comp = new StoreCategoryConfigComp(wrapper, config); comp.prefWidth(600); var modal = ModalOverlay.of(AppI18n.observable("categoryConfigTitle", wrapper.getName().getValue()), comp, null); modal.addButton(ModalButton.cancel()); @@ -74,6 +76,10 @@ public class StoreCategoryConfigComp extends SimpleComp { return new DataStoreCategoryConfig(color.get() > 0 ? DataStoreColor.values()[color.get() - 1] : null, scripts.get(), confirm.get(), sync.get(), ref.get() != null ? ref.get().get().getUuid() : null); }, config) .buildComp(); - return options.createRegion(); + var r = options.createRegion(); + var sp = new ScrollPane(r); + sp.setFitToWidth(true); + sp.prefHeightProperty().bind(r.heightProperty()); + return sp; } } diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreChoiceComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreChoiceComp.java index f17229f66..66ffdf969 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreChoiceComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreChoiceComp.java @@ -2,25 +2,27 @@ package io.xpipe.app.comp.store; import io.xpipe.app.comp.Comp; import io.xpipe.app.comp.SimpleComp; -import io.xpipe.app.comp.base.ButtonComp; -import io.xpipe.app.comp.base.FilterComp; -import io.xpipe.app.comp.base.HorizontalComp; -import io.xpipe.app.comp.base.PrettyImageHelper; +import io.xpipe.app.comp.base.*; import io.xpipe.app.core.AppFontSizes; import io.xpipe.app.core.AppI18n; +import io.xpipe.app.core.window.AppDialog; import io.xpipe.app.ext.LocalStore; import io.xpipe.app.ext.ShellStore; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.storage.DataStoreEntryRef; +import io.xpipe.app.util.BindingsHelper; import io.xpipe.app.util.DataStoreCategoryChoiceComp; +import io.xpipe.app.util.LabelGraphic; import io.xpipe.core.store.DataStore; import javafx.beans.binding.Bindings; +import javafx.beans.binding.StringBinding; import javafx.beans.property.Property; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; +import javafx.collections.ListChangeListener; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.control.MenuButton; @@ -128,6 +130,7 @@ public class StoreChoiceComp extends SimpleComp { } }, initialExpanded); + var category = new DataStoreCategoryChoiceComp( initialCategory != null ? initialCategory.getRoot() : null, StoreViewState.get().getActiveCategory(), @@ -174,11 +177,24 @@ public class StoreChoiceComp extends SimpleComp { }) .createStructure() .get(); - var r = section.vgrow().createRegion(); + + var emptyText = Bindings.createStringBinding(() -> { + var count = StoreViewState.get().getAllEntries().getList().stream().filter(applicable).count(); + return count == 0 ? AppI18n.get("noCompatibleConnection") : null; + }, StoreViewState.get().getAllEntries().getList()); + var emptyLabel = new LabelComp(emptyText, new SimpleObjectProperty<>(new LabelGraphic.IconGraphic("mdi2f-filter"))); + emptyLabel.apply(struc -> AppFontSizes.sm(struc.get())); + emptyLabel.hide(BindingsHelper.map(emptyText, s -> s == null)); + emptyLabel.minHeight(80); + + var listStack = new StackComp(List.of(emptyLabel, section)); + listStack.vgrow(); + + var r = listStack.createRegion(); var content = new VBox(top, r); content.setFillWidth(true); content.getStyleClass().add("choice-comp-content"); - content.setPrefWidth(500); + content.setPrefWidth(480); content.setMaxHeight(550); popover.setContentNode(content); @@ -188,6 +204,11 @@ public class StoreChoiceComp extends SimpleComp { popover.setDetachable(true); popover.setTitle(AppI18n.get("selectConnection")); AppFontSizes.xs(popover.getContentNode()); + + // Hide on connection creation dialog + AppDialog.getModalOverlays().addListener((ListChangeListener) c -> { + popover.hide(); + }); } return popover; diff --git a/app/src/main/java/io/xpipe/app/prefs/AboutCategory.java b/app/src/main/java/io/xpipe/app/prefs/AboutCategory.java index 0408086ba..01b3fb5c8 100644 --- a/app/src/main/java/io/xpipe/app/prefs/AboutCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/AboutCategory.java @@ -26,16 +26,16 @@ public class AboutCategory extends AppPrefsCategory { @Override protected Comp create() { - var props = createProperties().padding(new Insets(0, 0, 0, 5)); + var props = createProperties(); var update = new UpdateCheckComp().prefWidth(600); return new VerticalComp(List.of( props, - Comp.hspacer(8), + Comp.hspacer(3), update, Comp.hspacer(13), Comp.hseparator().padding(Insets.EMPTY).maxWidth(600))) .apply(s -> s.get().setFillWidth(true)) - .apply(struc -> struc.get().setSpacing(15)) + .apply(struc -> struc.get().setSpacing(12)) .styleClass("information") .styleClass("about-tab") .apply(struc -> struc.get().maxWidth(600)); @@ -55,18 +55,16 @@ public class AboutCategory extends AppPrefsCategory { } var section = new OptionsBuilder() - .addComp(Comp.vspacer(45)) + .addComp(Comp.vspacer(40)) .addComp(title, null) .addComp(Comp.vspacer(10)) .name("build") .addComp(new LabelComp(AppProperties.get().getBuild()), null) .name("distribution") .addComp(new LabelComp(AppDistributionType.get().toTranslatedString())) - .name("runtimeVersion") - .addComp(new LabelComp(System.getProperty("java.vm.version")), null) .name("virtualMachine") .addComp( - new LabelComp(System.getProperty("java.vm.vendor") + " " + System.getProperty("java.vm.name")), + new LabelComp(System.getProperty("java.vm.vendor") + " " + System.getProperty("java.vm.name") + " " + System.getProperty("java.vm.version")), null) .buildComp(); return section.styleClass("properties-comp"); 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 45b5c1cd1..2ae9718ca 100644 --- a/app/src/main/java/io/xpipe/app/prefs/TerminalCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/TerminalCategory.java @@ -236,7 +236,12 @@ public class TerminalCategory extends AppPrefsCategory { .build(); var choice = choiceBuilder.build().buildComp(); choice.maxWidth(getCompWidth()); - return new OptionsBuilder().nameAndDescription("terminalMultiplexer").addComp(choice); + var options = new OptionsBuilder().name("terminalMultiplexer").description( + OsType.getLocal() == OsType.WINDOWS ? "terminalMultiplexerWindowsDescription" : "terminalMultiplexerDescription").addComp(choice); + if (OsType.getLocal() == OsType.WINDOWS) { + options.disable(BindingsHelper.map(prefs.terminalProxy(), uuid -> uuid == null)); + } + return options; } private OptionsBuilder terminalPrompt() { diff --git a/app/src/main/java/io/xpipe/app/terminal/TerminalProxyManager.java b/app/src/main/java/io/xpipe/app/terminal/TerminalProxyManager.java index 66ca9424b..d540107ff 100644 --- a/app/src/main/java/io/xpipe/app/terminal/TerminalProxyManager.java +++ b/app/src/main/java/io/xpipe/app/terminal/TerminalProxyManager.java @@ -28,10 +28,6 @@ public class TerminalProxyManager { return false; } - if (ref.get().equals(DataStorage.get().local())) { - return true; - } - var parent = DataStorage.get().getDefaultDisplayParent(ref.get()); if (parent.isEmpty()) { return false; diff --git a/app/src/main/resources/io/xpipe/app/resources/style/about.css b/app/src/main/resources/io/xpipe/app/resources/style/about.css index ff42efae2..1af30f325 100644 --- a/app/src/main/resources/io/xpipe/app/resources/style/about.css +++ b/app/src/main/resources/io/xpipe/app/resources/style/about.css @@ -14,10 +14,6 @@ } -.properties-comp { - -fx-spacing: 0.4em; -} - .properties-comp .header { -fx-graphic-text-gap: 0.8em; } diff --git a/lang/strings/translations_en.properties b/lang/strings/translations_en.properties index 156fa892c..dd3f4c43d 100644 --- a/lang/strings/translations_en.properties +++ b/lang/strings/translations_en.properties @@ -1381,7 +1381,9 @@ terminalEnvironmentDescription=In case you want to use features of a local Linux terminalInitScript=Terminal init script terminalInitScriptDescription=Commands to run in the terminal environment prior to the connection being launched. You can use this to configure the terminal environment on startup. terminalMultiplexer=Terminal multiplexer -terminalMultiplexerDescription=The terminal multiplexer to use as an alternative to tabs in a terminal.\n\nThis will replace certain terminal handling characteristics, e.g. tab handling, with the multiplexer functionality. Requires the respective multiplexer executable to be installed on the system. +#force +terminalMultiplexerDescription=The terminal multiplexer to use as an alternative to tabs in a terminal. This will replace certain terminal handling characteristics, e.g. tab handling, with the multiplexer functionality.\n\nRequires the respective multiplexer executable to be installed on the system. +terminalMultiplexerWindowsDescription=The terminal multiplexer to use as an alternative to tabs in a terminal. This will replace certain terminal handling characteristics, e.g. tab handling, with the multiplexer functionality.\n\nRequires the usage of a WSL terminal environment on Windows and the multiplexer executable to be installed on the WSL system. terminalPromptForRestart=Prompt for restart terminalPromptForRestartDescription=When enabled, exiting a terminal session will prompt you to either restart or close the session instead of just closing the terminal session instantly. #context: verb, database query @@ -1417,3 +1419,4 @@ categoryDefaultIdentityDescription=If you frequently use a certain identity on m categoryConfigTitle=$NAME$ configuration configure=Configure addConnection=Add connection +noCompatibleConnection=No compatible connection found