This commit is contained in:
crschnick
2025-12-28 23:01:31 +00:00
parent 32ab3542b8
commit b801a89bcc
80 changed files with 347 additions and 296 deletions

View File

@@ -4,7 +4,6 @@ import io.xpipe.app.beacon.mcp.AppMcpServer;
import io.xpipe.app.core.AppLocalTemp;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.process.ShellTemp;
import io.xpipe.app.util.DocumentationLink;
import io.xpipe.beacon.BeaconConfig;
import io.xpipe.beacon.BeaconInterface;

View File

@@ -2,7 +2,6 @@ package io.xpipe.app.beacon;
import io.xpipe.app.core.AppLocalTemp;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.process.ShellTemp;
import io.xpipe.beacon.BeaconClientException;
import org.apache.commons.io.FileUtils;

View File

@@ -52,7 +52,9 @@ public class AskpassExchangeImpl extends AskpassExchange {
if (msg.getRequest() == null) {
var r = AskpassAlert.queryRaw(prompt, null, true);
return Response.builder().value(r.getState() == SecretQueryState.NORMAL ? r.getSecret() : InPlaceSecretValue.of("")).build();
return Response.builder()
.value(r.getState() == SecretQueryState.NORMAL ? r.getSecret() : InPlaceSecretValue.of(""))
.build();
}
var found = msg.getSecretId() != null

View File

@@ -8,8 +8,8 @@ import io.xpipe.app.comp.base.StackComp;
import io.xpipe.app.core.App;
import io.xpipe.app.core.AppFontSizes;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.platform.MenuHelper;
import io.xpipe.app.platform.LabelGraphic;
import io.xpipe.app.platform.MenuHelper;
import io.xpipe.app.platform.PlatformThread;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.util.BooleanScope;

View File

@@ -5,9 +5,8 @@ import io.xpipe.app.browser.menu.BrowserMenuCategory;
import io.xpipe.app.browser.menu.BrowserMenuItemProvider;
import io.xpipe.app.core.AppFontSizes;
import io.xpipe.app.platform.InputHelper;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.update.AppDistributionType;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.SeparatorMenuItem;
import javafx.scene.input.KeyEvent;

View File

@@ -33,6 +33,7 @@ public class BrowserFileDuplicates {
}
var ext = target.getExtension();
return FilePath.of(target.removeTrailingSlash().getBaseName() + "_" + 1 + (ext.isPresent() ? "." + ext.get() : ""));
return FilePath.of(
target.removeTrailingSlash().getBaseName() + "_" + 1 + (ext.isPresent() ? "." + ext.get() : ""));
}
}

View File

@@ -145,7 +145,11 @@ public final class BrowserFileListComp extends SimpleComp {
var table = new TableView<BrowserEntry>();
table.setSkin(new TableViewSkin<>(table));
CompDescriptor.builder().nameKey("directoryContents").showTooltips(false).build().apply(table);
CompDescriptor.builder()
.nameKey("directoryContents")
.showTooltips(false)
.build()
.apply(table);
var placeholder = new Label();
var placeholderText = Bindings.createStringBinding(

View File

@@ -3,10 +3,7 @@ package io.xpipe.app.browser.file;
import io.xpipe.app.comp.Comp;
import io.xpipe.app.comp.CompDescriptor;
import io.xpipe.app.comp.CompStructure;
import io.xpipe.app.comp.base.ButtonComp;
import io.xpipe.app.comp.base.TextFieldComp;
import io.xpipe.app.comp.base.TooltipHelper;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.platform.InputHelper;
import io.xpipe.app.platform.PlatformThread;
@@ -15,7 +12,6 @@ import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
@@ -39,7 +35,11 @@ public class BrowserFileListFilterComp extends Comp<BrowserFileListFilterComp.St
var expanded = new SimpleBooleanProperty();
var text = new TextFieldComp(filterString, false).createStructure().get();
var button = new Button();
CompDescriptor.builder().nameKey("search").shortcut(new KeyCodeCombination(KeyCode.F, KeyCombination.SHORTCUT_DOWN)).build().apply(button);
CompDescriptor.builder()
.nameKey("search")
.shortcut(new KeyCodeCombination(KeyCode.F, KeyCombination.SHORTCUT_DOWN))
.build()
.apply(button);
button.minWidthProperty().bind(button.heightProperty());
InputHelper.onExactKeyCode(text, KeyCode.ESCAPE, true, keyEvent -> {
if (!expanded.get()) {

View File

@@ -3,8 +3,8 @@ package io.xpipe.app.browser.file;
import io.xpipe.app.comp.base.LazyTextFieldComp;
import io.xpipe.app.comp.base.PrettyImageHelper;
import io.xpipe.app.ext.FileKind;
import io.xpipe.app.platform.MenuHelper;
import io.xpipe.app.platform.InputHelper;
import io.xpipe.app.platform.MenuHelper;
import io.xpipe.app.platform.PlatformThread;
import io.xpipe.app.util.BooleanScope;
import io.xpipe.app.util.ThreadHelper;

View File

@@ -9,9 +9,7 @@ import io.xpipe.app.comp.SimpleCompStructure;
import io.xpipe.app.comp.augment.ContextMenuAugment;
import io.xpipe.app.comp.base.*;
import io.xpipe.app.core.AppFontSizes;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.platform.InputHelper;
import io.xpipe.app.platform.LabelGraphic;
import io.xpipe.app.platform.MenuHelper;
import io.xpipe.app.platform.PlatformThread;
import io.xpipe.app.util.GlobalTimer;
@@ -22,8 +20,6 @@ import javafx.beans.property.ReadOnlyBooleanWrapper;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.MenuButton;
import javafx.scene.control.Tooltip;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
@@ -61,7 +57,11 @@ public class BrowserFileSystemTabComp extends SimpleComp {
root.setMinWidth(190);
var overview = new Button(null, new FontIcon("mdi2m-monitor"));
overview.setOnAction(e -> model.cdAsync((FilePath) null));
CompDescriptor.builder().nameKey("overview").shortcut(new KeyCodeCombination(KeyCode.HOME, KeyCombination.ALT_DOWN)).build().apply(overview);
CompDescriptor.builder()
.nameKey("overview")
.shortcut(new KeyCodeCombination(KeyCode.HOME, KeyCombination.ALT_DOWN))
.build()
.apply(overview);
overview.disableProperty().bind(model.getInOverview());
InputHelper.onKeyCombination(
root, new KeyCodeCombination(KeyCode.HOME, KeyCombination.ALT_DOWN), true, keyEvent -> {

View File

@@ -154,7 +154,8 @@ public class BrowserHistoryTabComp extends SimpleComp {
});
})
.minWidth(300)
.descriptor(d -> d.name(new ReadOnlyStringWrapper(DataStorage.get().getStoreEntryDisplayName(entry.get()))))
.descriptor(
d -> d.name(new ReadOnlyStringWrapper(DataStorage.get().getStoreEntryDisplayName(entry.get()))))
.disable(disable)
.styleClass("entry-button")
.styleClass(Styles.LEFT_PILL)

View File

@@ -8,8 +8,8 @@ import io.xpipe.app.comp.base.ButtonComp;
import io.xpipe.app.comp.base.PrettyImageHelper;
import io.xpipe.app.comp.base.TextFieldComp;
import io.xpipe.app.core.AppFontSizes;
import io.xpipe.app.platform.MenuHelper;
import io.xpipe.app.platform.LabelGraphic;
import io.xpipe.app.platform.MenuHelper;
import io.xpipe.app.platform.PlatformThread;
import io.xpipe.app.util.BooleanScope;
import io.xpipe.app.util.ThreadHelper;
@@ -59,16 +59,20 @@ public class BrowserNavBarComp extends Comp<BrowserNavBarComp.Structure> {
.descriptor(d -> d.nameKey("directoryOptions"))
.apply(new ContextMenuAugment<>(event -> event.getButton() == MouseButton.PRIMARY, null, () -> {
return model.getInOverview().get() ? null : new BrowserContextMenu(model, null, false);
})).createRegion();
}))
.createRegion();
homeButton.getStyleClass().add(Styles.LEFT_PILL);
homeButton.getStyleClass().add("path-graphic-button");
AppFontSizes.sm(homeButton);
var historyButton = new ButtonComp(null, new LabelGraphic.IconGraphic("mdi2h-history"), null)
.descriptor(d -> d.nameKey("history").shortcut(new KeyCodeCombination(KeyCode.H, KeyCombination.ALT_DOWN)))
.styleClass(Styles.RIGHT_PILL)
.apply(new ContextMenuAugment<>(event -> event.getButton() == MouseButton.PRIMARY, null, this::createContextMenu))
.createStructure().get();
.descriptor(
d -> d.nameKey("history").shortcut(new KeyCodeCombination(KeyCode.H, KeyCombination.ALT_DOWN)))
.styleClass(Styles.RIGHT_PILL)
.apply(new ContextMenuAugment<>(
event -> event.getButton() == MouseButton.PRIMARY, null, this::createContextMenu))
.createStructure()
.get();
AppFontSizes.xs(historyButton);
var breadcrumbs = new BrowserBreadcrumbBar(model);
@@ -156,35 +160,34 @@ public class BrowserNavBarComp extends Comp<BrowserNavBarComp.Structure> {
new TextFieldComp(path, true).styleClass(Styles.CENTER_PILL).styleClass("path-text");
pathBar.descriptor(d -> d.nameKey("currentPath"));
pathBar.apply(struc -> {
struc.get().focusedProperty().subscribe(val -> {
struc.get()
.pseudoClassStateChanged(
INVISIBLE,
!val && !model.getInOverview().get());
struc.get().focusedProperty().subscribe(val -> {
struc.get()
.pseudoClassStateChanged(
INVISIBLE, !val && !model.getInOverview().get());
if (val) {
Platform.runLater(() -> {
struc.get().end();
});
}
if (val) {
Platform.runLater(() -> {
struc.get().end();
});
}
});
struc.get().addEventHandler(KeyEvent.KEY_PRESSED, ke -> {
if (ke.getCode().equals(KeyCode.ENTER)) {
ke.consume();
}
});
struc.get().addEventHandler(KeyEvent.KEY_PRESSED, ke -> {
if (ke.getCode().equals(KeyCode.ENTER)) {
ke.consume();
}
});
model.getInOverview().subscribe(val -> {
// Pseudo classes do not apply if set instantly before shown
// If we start a new tab with a directory set, we have to set the pseudo class one pulse later
Platform.runLater(() -> {
struc.get()
.pseudoClassStateChanged(
INVISIBLE, !val && !struc.get().isFocused());
});
});
model.getInOverview().subscribe(val -> {
// Pseudo classes do not apply if set instantly before shown
// If we start a new tab with a directory set, we have to set the pseudo class one pulse later
Platform.runLater(() -> {
struc.get()
.pseudoClassStateChanged(
INVISIBLE, !val && !struc.get().isFocused());
});
});
});
return pathBar;
}

View File

@@ -3,21 +3,17 @@ package io.xpipe.app.browser.file;
import io.xpipe.app.browser.icon.BrowserIconManager;
import io.xpipe.app.comp.base.ModalOverlay;
import io.xpipe.app.comp.base.PrettyImageHelper;
import io.xpipe.app.core.AppFontSizes;
import io.xpipe.app.core.window.AppDialog;
import io.xpipe.app.ext.FileEntry;
import io.xpipe.app.ext.FileKind;
import io.xpipe.app.platform.BooleanAnimationTimer;
import io.xpipe.app.platform.InputHelper;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.update.AppDistributionType;
import io.xpipe.app.util.BooleanScope;
import io.xpipe.app.util.ThreadHelper;
import javafx.application.Platform;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ListChangeListener;
import javafx.geometry.Side;
import javafx.scene.Node;
@@ -82,7 +78,7 @@ public class BrowserQuickAccessContextMenu extends ContextMenu {
showingProperty().addListener((observable, oldValue, newValue) -> {
if (newValue) {
AppDialog.getModalOverlays().addListener(modalListener);
} else {
} else {
AppDialog.getModalOverlays().removeListener(modalListener);
}
});

View File

@@ -8,7 +8,6 @@ import io.xpipe.app.core.mode.AppOperationMode;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.process.OsFileSystem;
import io.xpipe.app.process.ShellTemp;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.util.BooleanScope;
import io.xpipe.app.util.DesktopHelper;

View File

@@ -7,14 +7,11 @@ import io.xpipe.app.browser.action.BrowserActionProviders;
import io.xpipe.app.browser.file.BrowserEntry;
import io.xpipe.app.browser.file.BrowserFileSystemTabModel;
import io.xpipe.app.comp.CompDescriptor;
import io.xpipe.app.comp.base.ButtonComp;
import io.xpipe.app.comp.base.TooltipHelper;
import io.xpipe.app.hub.action.StoreAction;
import io.xpipe.app.storage.DataStoreEntryRef;
import javafx.scene.control.Button;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Tooltip;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Region;

View File

@@ -32,7 +32,10 @@ public class OpenTerminalInDirectoryMenuProvider implements BrowserMenuLeafProvi
for (var dir : dirs) {
var name = model.getFileSystem().supportsTerminalWorkingDirectory() && dir != null ? dir.toString() : null;
model.openTerminalAsync(
name, model.getFileSystem().supportsTerminalWorkingDirectory() ? dir : null, model.getFileSystem().getRawShellControl().orElseThrow(), dirs.size() == 1);
name,
model.getFileSystem().supportsTerminalWorkingDirectory() ? dir : null,
model.getFileSystem().getRawShellControl().orElseThrow(),
dirs.size() == 1);
}
}

View File

@@ -35,7 +35,8 @@ public class PasteMenuProvider implements BrowserMenuLeafProvider {
}
var isDuplication = files.size() == 1
&& model.getFileSystem().equals(files.getFirst().getRawFileEntry().getFileSystem())
&& model.getFileSystem()
.equals(files.getFirst().getRawFileEntry().getFileSystem())
&& target.getPath()
.equals(files.getFirst().getRawFileEntry().getPath().getParent());
if (isDuplication) {

View File

@@ -1,21 +1,16 @@
package io.xpipe.app.comp;
import io.xpipe.app.comp.augment.Augment;
import io.xpipe.app.comp.base.TooltipHelper;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.platform.BindingsHelper;
import io.xpipe.app.platform.PlatformThread;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.scene.Node;
import javafx.scene.control.Separator;
import javafx.scene.control.Tooltip;
import javafx.scene.input.KeyCombination;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;

View File

@@ -2,14 +2,15 @@ package io.xpipe.app.comp;
import io.xpipe.app.comp.base.TooltipHelper;
import io.xpipe.app.core.AppI18n;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.Tooltip;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javafx.scene.layout.Region;
import lombok.Builder;
import lombok.Value;
@@ -21,27 +22,34 @@ public class CompDescriptor {
ObservableValue<String> description;
KeyCombination shortcut;
FocusTraversal focusTraversal;
@Builder.Default
boolean showTooltips = true;
public static enum FocusTraversal {
DISABLED,
ENABLED_FOR_ACCESSIBILITY,
ENABLED;
}
public void apply(Region r) {
var accessibleText = getName() != null ? Bindings.createStringBinding(() -> {
var s = getName().getValue() + "\n\n";
if (getShortcut() != null) {
s += AppI18n.get("shortcut") + ": " + getShortcut().getDisplayText();
}
return s;
}, AppI18n.activeLanguage(), getName()) : null;
var accessibleText = getName() != null
? Bindings.createStringBinding(
() -> {
var s = getName().getValue() + "\n\n";
if (getShortcut() != null) {
s += AppI18n.get("shortcut") + ": "
+ getShortcut().getDisplayText();
}
return s;
},
AppI18n.activeLanguage(),
getName())
: null;
if (showTooltips) {
var tooltipText = Bindings.createStringBinding(() -> {
var tooltipText = Bindings.createStringBinding(
() -> {
var s = "";
if (getName() != null) {
s += getName().getValue() + "\n\n";
@@ -56,7 +64,9 @@ public class CompDescriptor {
s += AppI18n.get("shortcut") + ": " + getShortcut().getDisplayText();
}
return s.strip();
}, AppI18n.activeLanguage(), getName() != null ? getName() : new ReadOnlyObjectWrapper<>(),
},
AppI18n.activeLanguage(),
getName() != null ? getName() : new ReadOnlyObjectWrapper<>(),
getDescription() != null ? getDescription() : new ReadOnlyObjectWrapper<>());
var tt = TooltipHelper.create(tooltipText);

View File

@@ -13,7 +13,6 @@ import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.scene.control.ComboBox;
import javafx.scene.control.skin.ComboBoxListViewSkin;
import javafx.util.StringConverter;
import lombok.AccessLevel;

View File

@@ -10,7 +10,6 @@ import javafx.beans.property.Property;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
import javafx.scene.control.ComboBox;
import javafx.scene.control.skin.ComboBoxListViewSkin;
import javafx.scene.input.KeyEvent;
import lombok.AccessLevel;

View File

@@ -17,7 +17,6 @@ import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.value.ObservableDoubleValue;
import javafx.geometry.Pos;
import javafx.scene.AccessibleAttribute;
import javafx.scene.control.Button;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;

View File

@@ -12,7 +12,6 @@ import io.xpipe.app.util.Hyperlinks;
import javafx.application.Platform;
import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Insets;
@@ -106,11 +105,16 @@ public class OptionsComp extends Comp<CompStructure<VBox>> {
},
name.managedProperty()));
vbox.focusTraversableProperty().bind(Platform.accessibilityActiveProperty().and(compRegion.visibleProperty()));
vbox.focusTraversableProperty()
.bind(Platform.accessibilityActiveProperty().and(compRegion.visibleProperty()));
vbox.setAccessibleRole(AccessibleRole.TEXT);
var joined = Bindings.createStringBinding(() -> {
return entry.name.getValue() + "\n\n" + entry.description().getValue();
}, entry.name(), entry.description());
var joined = Bindings.createStringBinding(
() -> {
return entry.name.getValue() + "\n\n"
+ entry.description().getValue();
},
entry.name(),
entry.description());
vbox.accessibleTextProperty().bind(joined);
if (entry.documentationLink() != null) {
@@ -119,9 +123,14 @@ public class OptionsComp extends Comp<CompStructure<VBox>> {
link.getStyleClass().add(Styles.BUTTON_OUTLINED);
link.getStyleClass().add(Styles.ACCENT);
link.getStyleClass().add("long-description");
link.accessibleTextProperty().bind(Bindings.createStringBinding(() -> {
return AppI18n.get("helpButton", entry.name().getValue());
}, AppI18n.activeLanguage(), entry.name()));
link.accessibleTextProperty()
.bind(Bindings.createStringBinding(
() -> {
return AppI18n.get(
"helpButton", entry.name().getValue());
},
AppI18n.activeLanguage(),
entry.name()));
AppFontSizes.xl(link);
link.setOnAction(e -> {
Hyperlinks.open(entry.documentationLink());
@@ -169,7 +178,8 @@ public class OptionsComp extends Comp<CompStructure<VBox>> {
name.prefHeightProperty().bind(line.heightProperty());
name.setMinWidth(Region.USE_PREF_SIZE);
name.setAlignment(Pos.CENTER_LEFT);
name.focusTraversableProperty().bind(Platform.accessibilityActiveProperty().and(compRegion.visibleProperty()));
name.focusTraversableProperty()
.bind(Platform.accessibilityActiveProperty().and(compRegion.visibleProperty()));
name.setAccessibleRole(AccessibleRole.TEXT);
name.accessibleTextProperty().bind(entry.name());
if (compRegion != null) {

View File

@@ -66,8 +66,10 @@ public class SecretFieldComp extends Comp<SecretFieldComp.Structure> {
@Override
public Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters) {
switch (attribute) {
case TEXT: return getAccessibleText();
default: return super.queryAccessibleAttribute(attribute, parameters);
case TEXT:
return getAccessibleText();
default:
return super.queryAccessibleAttribute(attribute, parameters);
}
}
};

View File

@@ -16,17 +16,14 @@ import io.xpipe.app.util.ThreadHelper;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.Property;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.css.PseudoClass;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.util.Duration;
import lombok.AllArgsConstructor;

View File

@@ -37,13 +37,17 @@ public class ToggleSwitchComp extends Comp<CompStructure<ToggleSwitch>> {
event.consume();
}
});
s.accessibleTextProperty().bind(Bindings.createStringBinding(() -> {
if (name != null && name.getValue() != null) {
return name.getValue();
}
s.accessibleTextProperty()
.bind(Bindings.createStringBinding(
() -> {
if (name != null && name.getValue() != null) {
return name.getValue();
}
return AppI18n.get("toggleButton");
}, name != null ? name : new ReadOnlyObjectWrapper<>(), AppI18n.activeLanguage()));
return AppI18n.get("toggleButton");
},
name != null ? name : new ReadOnlyObjectWrapper<>(),
AppI18n.activeLanguage()));
s.setAlignment(Pos.CENTER);
s.getStyleClass().add("toggle-switch-comp");
s.setSelected(selected.getValue() != null ? selected.getValue() : false);

View File

@@ -1,12 +1,9 @@
package io.xpipe.app.comp.base;
import io.xpipe.app.core.AppFontSizes;
import io.xpipe.app.core.AppI18n;
import javafx.beans.binding.Bindings;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.Tooltip;
import javafx.scene.input.KeyCombination;
import javafx.stage.Window;
public class TooltipHelper {

View File

@@ -5,8 +5,8 @@ import io.xpipe.app.comp.base.ModalOverlay;
import io.xpipe.app.comp.base.ScrollComp;
import io.xpipe.app.core.window.AppDialog;
import io.xpipe.app.platform.OptionsBuilder;
import io.xpipe.app.prefs.PersonalizationCategory;
import io.xpipe.app.prefs.EditorCategory;
import io.xpipe.app.prefs.PersonalizationCategory;
import io.xpipe.app.prefs.TerminalCategory;
import io.xpipe.app.util.DocumentationLink;

View File

@@ -11,7 +11,8 @@ import java.nio.file.attribute.PosixFilePermissions;
public class AppLocalTemp {
public static Path getLocalTempDataDirectory() {
var temp = AppSystemInfo.ofCurrent().getTemp().resolve(AppNames.ofCurrent().getKebapName());
var temp =
AppSystemInfo.ofCurrent().getTemp().resolve(AppNames.ofCurrent().getKebapName());
// On Windows and macOS, we already have user specific temp directories
// Even on macOS as root we will have a unique directory (in contrast to shell controls)
if (OsType.ofLocal() == OsType.LINUX) {

View File

@@ -14,7 +14,6 @@ import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
public class AppResources {
@@ -59,7 +58,8 @@ public class AppResources {
}
try {
var fs = (ModuleFileSystem) FileSystems.newFileSystem(URI.create("module:/" + module), Map.of("layer", layer));
var fs = (ModuleFileSystem)
FileSystems.newFileSystem(URI.create("module:/" + module), Map.of("layer", layer));
if (AppExtensionManager.getInstance() != null) {
fileSystems.put(module, fs);
}

View File

@@ -70,16 +70,15 @@ public class AppRestart {
public static String getBackgroundRestartCommand(String user, ShellDialect dialect) {
var dataDir = AppProperties.get().getDataDir();
var l = new ArrayList<String>();
l.addAll(List.of("-Dio.xpipe.app.mode=gui",
l.addAll(List.of(
"-Dio.xpipe.app.mode=gui",
"-Dio.xpipe.app.acceptEula=true",
"-Dio.xpipe.app.dataDir=\"" + dataDir + "\"",
"-Dio.xpipe.app.restarted=true"));
if (user != null) {
l.add("-Dio.xpipe.app.login=\"" + user + "\"");
}
var exec = createBackgroundLaunchCommand(
l,
dialect);
var exec = createBackgroundLaunchCommand(l, dialect);
return exec;
}

View File

@@ -23,7 +23,8 @@ public abstract class AppShellChecker {
var originalErr = selfTestErrorCheck();
if (originalErr.isPresent()
&& (shouldAttemptFallbackForProcessStartFail() || !originalErr.get().isProcessSpawnIssue())) {
&& (shouldAttemptFallbackForProcessStartFail()
|| !originalErr.get().isProcessSpawnIssue())) {
var msg = formatMessage(originalErr.get().getMessage());
ErrorEventFactory.fromThrowable(new IllegalStateException(msg))
.documentationLink(DocumentationLink.LOCAL_SHELL_WARNING)

View File

@@ -375,7 +375,6 @@ public class AppMainWindow {
var h = Math.min(780, screen.getBounds().getHeight() - 10);
stage.setWidth(w);
stage.setHeight(h);
}
private void saveState() {

View File

@@ -16,7 +16,6 @@ import javafx.stage.Stage;
import java.time.Duration;
import java.time.Instant;
import java.util.List;
import java.util.function.Consumer;
public class AppWindowStyle {

View File

@@ -1,7 +1,6 @@
package io.xpipe.app.ext;
import io.xpipe.app.process.ShellControl;
import io.xpipe.app.util.LicensedFeature;
public interface ShellControlFunction {

View File

@@ -4,8 +4,6 @@ import io.xpipe.app.process.ShellControl;
import io.xpipe.core.FailableConsumer;
import io.xpipe.core.FilePath;
import lombok.Getter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

View File

@@ -2,10 +2,8 @@ package io.xpipe.app.hub.comp;
import io.xpipe.app.comp.Comp;
import io.xpipe.app.core.AppFontSizes;
import io.xpipe.app.core.AppI18n;
import io.xpipe.core.OsType;
import javafx.beans.binding.Bindings;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;

View File

@@ -7,8 +7,8 @@ import io.xpipe.app.comp.base.*;
import io.xpipe.app.core.AppFontSizes;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.platform.ClipboardHelper;
import io.xpipe.app.platform.MenuHelper;
import io.xpipe.app.platform.LabelGraphic;
import io.xpipe.app.platform.MenuHelper;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreCategory;
@@ -134,7 +134,8 @@ public class StoreCategoryComp extends SimpleComp {
count.minWidth(Region.USE_PREF_SIZE);
var showStatus = hover.or(new SimpleBooleanProperty(DataStorage.get().supportsSync()))
.or(showing).or(focus);
.or(showing)
.or(focus);
var h = new HorizontalComp(List.of(
expandButton,
Comp.hspacer(category.getCategory().getParentCategory() == null ? 3 : 0),

View File

@@ -66,9 +66,14 @@ public class StoreChoiceComp<T extends DataStore> extends SimpleComp {
},
selected),
() -> {});
button.descriptor(d -> d.name(Bindings.createStringBinding(() -> {
return selected.getValue() != null ? toName(selected.getValue().get()) : AppI18n.get("selectConnection");
}, selected, AppI18n.activeLanguage())));
button.descriptor(d -> d.name(Bindings.createStringBinding(
() -> {
return selected.getValue() != null
? toName(selected.getValue().get())
: AppI18n.get("selectConnection");
},
selected,
AppI18n.activeLanguage())));
button.apply(struc -> {
struc.get().setMaxWidth(20000);
struc.get().setAlignment(Pos.CENTER_LEFT);

View File

@@ -22,7 +22,6 @@ import javafx.beans.property.SimpleStringProperty;
import javafx.collections.ListChangeListener;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.control.MenuButton;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;

View File

@@ -4,7 +4,6 @@ import io.xpipe.app.comp.base.*;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.ext.GuiDialog;
import io.xpipe.app.platform.OptionsBuilder;
import io.xpipe.app.platform.SimpleValidator;
import io.xpipe.app.platform.Validator;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.util.ThreadHelper;
@@ -15,7 +14,6 @@ import javafx.beans.value.ObservableValue;
import javafx.geometry.Insets;
import javafx.scene.control.*;
import javafx.scene.control.skin.ScrollPaneSkin;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
@@ -71,7 +69,6 @@ public class StoreCreationComp extends ModalOverlayContentComp {
}
layout.getChildren().add(new Region());
var activeDialog = new SimpleObjectProperty<GuiDialog>();
model.getProvider().subscribe(n -> {
if (n != null) {
@@ -109,8 +106,7 @@ public class StoreCreationComp extends ModalOverlayContentComp {
full.sub(propOptions);
var comp = full.buildComp();
var region =
comp.styleClass("store-creator-options").createRegion();
var region = comp.styleClass("store-creator-options").createRegion();
valSp.getChildren().add(region);
var sp = new ScrollPane(valSp);

View File

@@ -4,8 +4,6 @@ import io.xpipe.app.action.AbstractAction;
import io.xpipe.app.comp.base.PrettyImageHelper;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.ext.*;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.update.AppDistributionType;
import io.xpipe.app.util.ScanDialog;
import javafx.application.Platform;
@@ -136,8 +134,11 @@ public class StoreCreationMenu {
Platform.runLater(() -> {
if (defaultProvider != null) {
providers.stream().filter(dataStoreProvider -> dataStoreProvider.getId().equals(defaultProvider)).findFirst().ifPresent(
dataStoreProvider -> {
providers.stream()
.filter(dataStoreProvider ->
dataStoreProvider.getId().equals(defaultProvider))
.findFirst()
.ifPresent(dataStoreProvider -> {
var index = providers.indexOf(dataStoreProvider);
menu.getItems().get(index).fire();
});

View File

@@ -136,7 +136,12 @@ public abstract class StoreEntryComp extends SimpleComp {
button.setPadding(Insets.EMPTY);
button.setMaxWidth(5000);
button.setFocusTraversable(true);
CompDescriptor.builder().name(getWrapper().getShownName()).description(getWrapper().getShownDescription()).showTooltips(false).build().apply(button);
CompDescriptor.builder()
.name(getWrapper().getShownName())
.description(getWrapper().getShownDescription())
.showTooltips(false)
.build()
.apply(button);
button.setOnAction(event -> {
if (getWrapper().getRenaming().get()) {
return;
@@ -536,8 +541,8 @@ public abstract class StoreEntryComp extends SimpleComp {
tags.getItems().add(new SeparatorMenuItem());
}
var index =
MenuHelper.createMenuItem(new LabelGraphic.IconGraphic("mdi2t-tag-plus-outline"), "createTag");
var index = MenuHelper.createMenuItem(
new LabelGraphic.IconGraphic("mdi2t-tag-plus-outline"), "createTag");
index.setOnAction(event -> {
var tagName = new SimpleStringProperty();
var modal = ModalOverlay.of(

View File

@@ -8,8 +8,8 @@ import io.xpipe.app.comp.base.*;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.ext.DataStore;
import io.xpipe.app.hub.action.BatchHubProvider;
import io.xpipe.app.platform.MenuHelper;
import io.xpipe.app.platform.DerivedObservableList;
import io.xpipe.app.platform.MenuHelper;
import io.xpipe.app.storage.DataStoreEntryRef;
import javafx.beans.binding.Bindings;

View File

@@ -1,7 +1,6 @@
package io.xpipe.app.hub.comp;
import io.xpipe.app.comp.Comp;
import io.xpipe.app.comp.CompDescriptor;
import io.xpipe.app.comp.SimpleComp;
import io.xpipe.app.comp.base.CountComp;
import io.xpipe.app.comp.base.FilterComp;
@@ -20,7 +19,6 @@ import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.control.MenuButton;
import javafx.scene.control.Separator;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;

View File

@@ -101,20 +101,20 @@ public class StoreEntryWrapper {
AppPrefs.get().censorMode(),
summary);
this.shownDescription = Bindings.createStringBinding(
() -> {
var summaryValue = shownSummary.getValue();
if (summaryValue != null) {
return summaryValue;
} else {
var provider = getEntry().getProvider();
if (provider != null) {
return AppI18n.get(provider.getId() + ".displayName");
} else {
return null;
}
}
},
shownSummary);
() -> {
var summaryValue = shownSummary.getValue();
if (summaryValue != null) {
return summaryValue;
} else {
var provider = getEntry().getProvider();
if (provider != null) {
return AppI18n.get(provider.getId() + ".displayName");
} else {
return null;
}
}
},
shownSummary);
this.shownInformation = new SimpleObjectProperty<>();
this.notes = new SimpleObjectProperty<>(new StoreNotes(entry.getNotes(), entry.getNotes()));

View File

@@ -38,7 +38,8 @@ public class StoreNotesComp extends Comp<StoreNotesComp.Structure> {
var n = wrapper.getNotes();
var button = new IconButtonComp("mdi2n-note-text-outline")
.apply(struc -> AppFontSizes.xs(struc.get()))
.descriptor(d -> d.nameKey("notes").focusTraversal(CompDescriptor.FocusTraversal.ENABLED_FOR_ACCESSIBILITY))
.descriptor(
d -> d.nameKey("notes").focusTraversal(CompDescriptor.FocusTraversal.ENABLED_FOR_ACCESSIBILITY))
.styleClass("notes-button")
.hide(BindingsHelper.map(n, s -> s.getCommited() == null && s.getCurrent() == null))
.createStructure()

View File

@@ -8,9 +8,8 @@ import io.xpipe.app.core.AppI18n;
import io.xpipe.app.ext.DataStoreProvider;
import io.xpipe.app.ext.DataStoreProviders;
import io.xpipe.app.platform.JfxHelper;
import io.xpipe.app.platform.MenuHelper;
import io.xpipe.app.process.ShellDialect;
import javafx.beans.binding.Bindings;
import javafx.beans.property.Property;
import javafx.scene.control.ComboBox;
@@ -77,9 +76,18 @@ public class StoreProviderChoiceComp extends Comp<CompStructure<ComboBox<DataSto
cb.setValue(provider.getValue());
provider.bind(cb.valueProperty());
cb.getStyleClass().add("choice-comp");
CompDescriptor.builder().nameKey("chooseConnectionType").description(Bindings.createStringBinding(() -> {
return provider.getValue() != null ? provider.getValue().displayName().getValue() : null;
}, provider, AppI18n.activeLanguage())).build().apply(cb);
CompDescriptor.builder()
.nameKey("chooseConnectionType")
.description(Bindings.createStringBinding(
() -> {
return provider.getValue() != null
? provider.getValue().displayName().getValue()
: null;
},
provider,
AppI18n.activeLanguage()))
.build()
.apply(cb);
cb.setOnKeyPressed(event -> {
if (!event.getCode().equals(KeyCode.ENTER)) {
return;

View File

@@ -4,11 +4,10 @@ import io.xpipe.app.comp.Comp;
import io.xpipe.app.comp.CompStructure;
import io.xpipe.app.comp.base.IconButtonComp;
import io.xpipe.app.comp.base.PrettyImageHelper;
import io.xpipe.app.platform.MenuHelper;
import io.xpipe.app.platform.LabelGraphic;
import io.xpipe.app.platform.MenuHelper;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.update.AppDistributionType;
import javafx.geometry.Side;
import javafx.scene.control.Button;
import javafx.scene.control.ContextMenu;

View File

@@ -61,7 +61,8 @@ public class ErrorEventFactory {
b = ErrorEvent.builder().throwable(t);
}
if (t instanceof SSLHandshakeException || (t.getClass().getName().equals("sun.security.provider.certpath.SunCertPathBuilderException"))) {
if (t instanceof SSLHandshakeException
|| (t.getClass().getName().equals("sun.security.provider.certpath.SunCertPathBuilderException"))) {
if (b.getLink() == null) {
b.documentationLink(DocumentationLink.TLS_DECRYPTION);
}

View File

@@ -3,8 +3,8 @@ package io.xpipe.app.issue;
import io.xpipe.app.comp.Comp;
import io.xpipe.app.comp.base.*;
import io.xpipe.app.core.*;
import io.xpipe.app.prefs.AppPrefs;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.geometry.Orientation;

View File

@@ -2,9 +2,8 @@ package io.xpipe.app.platform;
import io.xpipe.app.core.AppFontSizes;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.update.AppDistributionType;
import javafx.application.Platform;
import javafx.geometry.Side;
import javafx.scene.Node;
@@ -14,9 +13,8 @@ import javafx.scene.control.skin.ComboBoxPopupControl;
import javafx.scene.control.skin.MenuButtonSkin;
import javafx.scene.control.skin.MenuButtonSkinBase;
import javafx.scene.layout.Region;
import lombok.SneakyThrows;
import java.util.function.Function;
import lombok.SneakyThrows;
public class MenuHelper {

View File

@@ -63,18 +63,22 @@ public class AboutCategory extends AppPrefsCategory {
.addComp(title, null)
.addComp(Comp.vspacer(10))
.name("build")
.addComp(new LabelComp(AppProperties.get().getBuild())
.descriptor(d -> d.focusTraversal(CompDescriptor.FocusTraversal.ENABLED_FOR_ACCESSIBILITY)), null)
.addComp(
new LabelComp(AppProperties.get().getBuild())
.descriptor(
d -> d.focusTraversal(CompDescriptor.FocusTraversal.ENABLED_FOR_ACCESSIBILITY)),
null)
.name("distribution")
.addComp(new LabelComp(AppDistributionType.get().toTranslatedString())
.descriptor(d -> d.focusTraversal(CompDescriptor.FocusTraversal.ENABLED_FOR_ACCESSIBILITY)))
.name("virtualMachine")
.addComp(
new LabelComp(System.getProperty("java.vm.vendor") + " "
+ System.getProperty("java.vm.name")
+ " "
+ System.getProperty("java.vm.version"))
.descriptor(d -> d.focusTraversal(CompDescriptor.FocusTraversal.ENABLED_FOR_ACCESSIBILITY)),
+ System.getProperty("java.vm.name")
+ " "
+ System.getProperty("java.vm.version"))
.descriptor(
d -> d.focusTraversal(CompDescriptor.FocusTraversal.ENABLED_FOR_ACCESSIBILITY)),
null)
.buildComp();
return section.styleClass("properties-comp");

View File

@@ -14,7 +14,6 @@ import io.xpipe.app.process.ShellScript;
import io.xpipe.app.pwman.PasswordManager;
import io.xpipe.app.rdp.ExternalRdpClient;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStorageGroupStrategy;
import io.xpipe.app.storage.DataStorageUserHandler;
import io.xpipe.app.terminal.ExternalTerminalType;
import io.xpipe.app.terminal.TerminalMultiplexer;

View File

@@ -46,7 +46,8 @@ public class AppPrefsSidebarComp extends SimpleComp {
PseudoClass.getPseudoClass("selected"),
appPrefsCategory.equals(val));
});
}).maxWidth(2000);
})
.maxWidth(2000);
})
.collect(Collectors.toCollection(ArrayList::new));

View File

@@ -1,30 +1,16 @@
package io.xpipe.app.prefs;
import io.xpipe.app.comp.Comp;
import io.xpipe.app.comp.base.IntFieldComp;
import io.xpipe.app.platform.LabelGraphic;
import io.xpipe.app.platform.OptionsBuilder;
import io.xpipe.core.OsType;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.control.Slider;
import atlantafx.base.controls.ProgressSliderSkin;
import atlantafx.base.theme.Styles;
import io.xpipe.app.comp.Comp;
import io.xpipe.app.comp.base.ButtonComp;
import io.xpipe.app.comp.base.ChoiceComp;
import io.xpipe.app.comp.base.HorizontalComp;
import io.xpipe.app.comp.base.IntFieldComp;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppTheme;
import io.xpipe.app.platform.LabelGraphic;
import io.xpipe.app.platform.OptionsBuilder;
import io.xpipe.app.util.Hyperlinks;
import io.xpipe.core.OsType;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Pos;
import javafx.scene.control.ListCell;
import javafx.scene.control.Slider;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import org.kordamp.ikonli.javafx.FontIcon;
import java.util.Arrays;
import java.util.List;
import java.util.function.Supplier;
public class DisplayCategory extends AppPrefsCategory {

View File

@@ -512,7 +512,8 @@ public interface ExternalEditorType extends PrefsChoiceValue {
new LinuxType("app.mousepad", "mousepad", "https://docs.xfce.org/apps/mousepad/start", "org.xfce.mousepad");
LinuxPathType PLUMA = new LinuxPathType("app.pluma", "pluma", "https://github.com/mate-desktop/pluma");
LinuxPathType WESTON_EDITOR = new LinuxPathType("app.westonEditor", "weston-editor", "https://wayland.pages.freedesktop.org/weston/");
LinuxPathType WESTON_EDITOR =
new LinuxPathType("app.westonEditor", "weston-editor", "https://wayland.pages.freedesktop.org/weston/");
ExternalEditorType TEXT_EDIT =
new MacOsEditor("app.textEdit", "TextEdit", "https://support.apple.com/en-gb/guide/textedit/welcome/mac");
ExternalEditorType BBEDIT = new MacOsEditor("app.bbedit", "BBEdit", "https://www.barebones.com/products/bbedit/");

View File

@@ -18,32 +18,37 @@ public class LinksCategory extends AppPrefsCategory {
new TileButtonComp("discord", "discordDescription", "bi-discord", e -> {
Hyperlinks.open(Hyperlinks.DISCORD);
e.consume();
}).maxWidth(2000),
})
.maxWidth(2000),
null)
.addComp(
new TileButtonComp("reddit", "redditDescription", "mdi2r-reddit", e -> {
Hyperlinks.open(Hyperlinks.REDDIT);
e.consume();
}).maxWidth(2000),
})
.maxWidth(2000),
null)
.addComp(
new TileButtonComp(
"documentation", "documentationDescription", "mdi2b-book-open-variant", e -> {
Hyperlinks.open(DocumentationLink.getRoot());
e.consume();
}).maxWidth(2000),
})
.maxWidth(2000),
null)
.addComp(
new TileButtonComp("tryPtb", "tryPtbDescription", "mdoal-insights", e -> {
Hyperlinks.open(Hyperlinks.GITHUB_PTB);
e.consume();
}).maxWidth(2000),
})
.maxWidth(2000),
null)
.addComp(
new TileButtonComp("privacy", "privacyDescription", "mdomz-privacy_tip", e -> {
DocumentationLink.PRIVACY.open();
e.consume();
}).maxWidth(2000),
})
.maxWidth(2000),
null)
.addComp(
new TileButtonComp("thirdParty", "thirdPartyDescription", "mdi2o-open-source-initiative", e -> {
@@ -52,12 +57,14 @@ public class LinksCategory extends AppPrefsCategory {
.styleClass("open-source-notices");
var modal = ModalOverlay.of("openSourceNotices", comp);
modal.show();
}).maxWidth(2000))
})
.maxWidth(2000))
.addComp(
new TileButtonComp("eula", "eulaDescription", "mdi2c-card-text-outline", e -> {
DocumentationLink.EULA.open();
e.consume();
}).maxWidth(2000),
})
.maxWidth(2000),
null)
.addComp(Comp.vspacer(40))
.buildComp();

View File

@@ -97,10 +97,7 @@ public class PersonalizationCategory extends AppPrefsCategory {
protected Comp<?> create() {
return new OptionsBuilder()
.addTitle("personalization")
.sub(new OptionsBuilder()
.sub(languageChoice())
.sub(themeChoice())
)
.sub(new OptionsBuilder().sub(languageChoice()).sub(themeChoice()))
.buildComp();
}
}

View File

@@ -17,7 +17,10 @@ public class ThirdPartyDependencyListComp extends Comp<CompStructure<?>> {
private TitledPane createPane(ThirdPartyDependency t) {
var tp = new TitledPane();
CompDescriptor.builder().name(new ReadOnlyStringWrapper(t.name())).build().apply(tp);
CompDescriptor.builder()
.name(new ReadOnlyStringWrapper(t.name()))
.build()
.apply(tp);
tp.setExpanded(false);
var link = new Hyperlink(t.name() + " @ " + t.version());
link.setOnAction(e -> {

View File

@@ -64,7 +64,8 @@ public class TroubleshootCategory extends AppPrefsCategory {
}
UserReportComp.show(event.build());
e.consume();
}).maxWidth(2000),
})
.maxWidth(2000),
null)
.addComp(
new TileButtonComp("launchDebugMode", "launchDebugModeDescription", "mdmz-refresh", e -> {
@@ -78,7 +79,8 @@ public class TroubleshootCategory extends AppPrefsCategory {
.launch();
});
e.consume();
}).maxWidth(2000),
})
.maxWidth(2000),
null);
if (AppLogs.get().isWriteToFile()) {
@@ -92,7 +94,8 @@ public class TroubleshootCategory extends AppPrefsCategory {
.resolve(AppNames.ofMain().getKebapName() + ".log")
.toString());
e.consume();
}).maxWidth(2000),
})
.maxWidth(2000),
null);
}
@@ -105,7 +108,8 @@ public class TroubleshootCategory extends AppPrefsCategory {
DesktopHelper.browseFile(
AppInstallation.ofCurrent().getBaseInstallationPath());
e.consume();
}).maxWidth(2000),
})
.maxWidth(2000),
null)
.addComp(
new TileButtonComp(
@@ -137,7 +141,8 @@ public class TroubleshootCategory extends AppPrefsCategory {
});
modal.show();
e.consume();
}).maxWidth(2000),
})
.maxWidth(2000),
null)
.addComp(
new TileButtonComp("clearCaches", "clearCachesDescription", "mdi2t-trash-can-outline", e -> {
@@ -149,13 +154,15 @@ public class TroubleshootCategory extends AppPrefsCategory {
});
modal.show();
e.consume();
}).maxWidth(2000),
})
.maxWidth(2000),
null)
.addComp(
new TileButtonComp("createHeapDump", "createHeapDumpDescription", "mdi2m-memory", e -> {
heapDump();
e.consume();
}).maxWidth(2000),
})
.maxWidth(2000),
null);
if (OsType.ofLocal() == OsType.MACOS && AppDistributionType.get() == AppDistributionType.NATIVE_INSTALLATION) {
@@ -183,7 +190,8 @@ public class TroubleshootCategory extends AppPrefsCategory {
.launch();
});
e.consume();
}).maxWidth(2000),
})
.maxWidth(2000),
null);
}

View File

@@ -17,8 +17,8 @@ import io.xpipe.app.util.LicenseProvider;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import lombok.SneakyThrows;
import java.util.Arrays;
@@ -71,7 +71,8 @@ public class VaultCategory extends AppPrefsCategory {
authChoice.apply(struc -> struc.get().setOpacity(1.0));
authChoice.maxWidth(600);
var groupStrategy = new SimpleObjectProperty<>(uh.getActiveUser() != null ? uh.getGroupStrategy(uh.getActiveUser()) : null);
var groupStrategy =
new SimpleObjectProperty<>(uh.getActiveUser() != null ? uh.getGroupStrategy(uh.getActiveUser()) : null);
groupStrategy.addListener((obs, ov, nv) -> {
uh.setCurrentGroupStrategy(nv);
});

View File

@@ -1,19 +1,12 @@
package io.xpipe.app.process;
import io.xpipe.app.core.AppInstallation;
import io.xpipe.app.core.AppNames;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.core.AppSystemInfo;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.core.FilePath;
import io.xpipe.core.OsType;
import org.apache.commons.io.FileUtils;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.PosixFilePermissions;
public class ShellTemp {

View File

@@ -18,7 +18,6 @@ import io.xpipe.core.SecretValue;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.control.MenuButton;
import javafx.scene.control.MenuItem;
import com.fasterxml.jackson.annotation.JsonTypeName;

View File

@@ -4,7 +4,6 @@ import io.xpipe.app.core.AppLocalTemp;
import io.xpipe.app.ext.PrefsValue;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.process.OsFileSystem;
import io.xpipe.app.process.ShellTemp;
import io.xpipe.app.util.*;
import io.xpipe.core.OsType;

View File

@@ -29,7 +29,6 @@ import org.kordamp.ikonli.javafx.FontIcon;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
@@ -190,13 +189,16 @@ public interface DataStorageGroupStrategy {
var command = new SimpleObjectProperty<>(p.getValue().getCommand());
return new OptionsBuilder()
.nameAndDescription("commandSecretField")
.addComp(IntegratedTextAreaComp.script(new ReadOnlyObjectWrapper<>(DataStorage.get().local().ref()), command), command)
.addComp(
IntegratedTextAreaComp.script(
new ReadOnlyObjectWrapper<>(
DataStorage.get().local().ref()),
command),
command)
.nonNull()
.bind(
() -> {
return Command.builder()
.command(command.get())
.build();
return Command.builder().command(command.get()).build();
},
p);
}
@@ -210,7 +212,8 @@ public interface DataStorageGroupStrategy {
@Override
public String queryEncryptionSecret() throws Exception {
try (var sc = ProcessControlProvider.get().createLocalProcessControl(true).start()) {
try (var sc =
ProcessControlProvider.get().createLocalProcessControl(true).start()) {
try (var cc = sc.command(command).sensitive().start()) {
cc.killOnTimeout(CountDown.of().start(10_000));
var out = cc.readStdoutOrThrow();

View File

@@ -4,8 +4,8 @@ import io.xpipe.app.comp.Comp;
import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.app.platform.OptionsBuilder;
import io.xpipe.app.prefs.VaultAuthentication;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.Property;
import java.io.IOException;
import javax.crypto.SecretKey;

View File

@@ -4,7 +4,6 @@ import io.xpipe.app.core.AppLocalTemp;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.prefs.ExternalApplicationType;
import io.xpipe.app.process.CommandBuilder;
import io.xpipe.app.process.ShellTemp;
import io.xpipe.app.util.*;
import java.nio.file.Files;

View File

@@ -36,7 +36,8 @@ public class ScreenTerminalMultiplexer implements TerminalMultiplexer {
public ShellScript launchForExistingSession(ShellControl control, TerminalLaunchConfiguration config)
throws Exception {
var l = new ArrayList<String>();
var firstCommand = getCommand(control, config.single().getDialectLaunchCommand().buildSimple());
var firstCommand =
getCommand(control, config.single().getDialectLaunchCommand().buildSimple());
l.addAll(List.of("screen -S xpipe -X screen -t \"" + escape(config.getCleanTitle(), true) + "\" "
+ escape(firstCommand, false)));
return ShellScript.lines(l);
@@ -47,7 +48,8 @@ public class ScreenTerminalMultiplexer implements TerminalMultiplexer {
var list = new ArrayList<String>();
list.add("for scr in $(screen -ls | grep xpipe | awk '{print $1}'); do screen -S $scr -X quit; done");
var firstCommand = getCommand(control, config.single().getDialectLaunchCommand().buildSimple());
var firstCommand =
getCommand(control, config.single().getDialectLaunchCommand().buildSimple());
list.addAll(List.of(
"screen -S xpipe -t \"" + escape(config.getCleanTitle(), true) + "\" " + escape(firstCommand, false)));
return ShellScript.lines(list);

View File

@@ -36,20 +36,22 @@ public class TmuxTerminalMultiplexer implements TerminalMultiplexer {
public ShellScript launchForExistingSession(ShellControl control, TerminalLaunchConfiguration config)
throws Exception {
var l = new ArrayList<String>();
var firstCommand = config.getPanes().getFirst().getDialectLaunchCommand().buildSimple();
var firstCommand =
config.getPanes().getFirst().getDialectLaunchCommand().buildSimple();
l.addAll(List.of("tmux new-window -t xpipe -n \"" + escape(config.getColoredTitle(), true) + "\" "
+ escape(firstCommand, false)));
if (config.getPanes().size() > 1) {
for (int i = 1; i < config.getPanes().size(); i++) {
var iCommand = config.getPanes().get(i).getDialectLaunchCommand().buildSimple();
var iCommand =
config.getPanes().get(i).getDialectLaunchCommand().buildSimple();
l.add("tmux split-window -t xpipe " + escape(iCommand, false));
}
var splitStrategy = AppPrefs.get().terminalSplitStrategy().getValue();
var layoutName = splitStrategy == TerminalSplitStrategy.HORIZONTAL ?
"even-horizontal" :
splitStrategy == TerminalSplitStrategy.VERTICAL ? "even-vertical" : "tiled";
var layoutName = splitStrategy == TerminalSplitStrategy.HORIZONTAL
? "even-horizontal"
: splitStrategy == TerminalSplitStrategy.VERTICAL ? "even-vertical" : "tiled";
l.add("tmux select-layout -t xpipe " + layoutName);
}
@@ -59,7 +61,8 @@ public class TmuxTerminalMultiplexer implements TerminalMultiplexer {
@Override
public ShellScript launchNewSession(ShellControl control, TerminalLaunchConfiguration config) throws Exception {
var l = new ArrayList<String>();
var firstCommand = config.getPanes().getFirst().getDialectLaunchCommand().buildSimple();
var firstCommand =
config.getPanes().getFirst().getDialectLaunchCommand().buildSimple();
l.addAll(List.of(
"tmux kill-session -t xpipe >/dev/null 2>&1",
"tmux new-session -d -s xpipe",

View File

@@ -1,17 +1,14 @@
package io.xpipe.app.terminal;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.process.*;
import io.xpipe.app.util.ThreadHelper;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.xpipe.app.util.GlobalTimer;
import io.xpipe.app.util.ThreadHelper;
import lombok.Builder;
import lombok.SneakyThrows;
import lombok.extern.jackson.Jacksonized;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
@@ -49,19 +46,25 @@ public class ZellijTerminalMultiplexer implements TerminalMultiplexer {
"zellij -s xpipe action clear"));
if (config.getPanes().size() > 1) {
var splitIterator = AppPrefs.get().terminalSplitStrategy().getValue().iterator();
var splitIterator =
AppPrefs.get().terminalSplitStrategy().getValue().iterator();
splitIterator.next();
for (int i = 1; i < config.getPanes().size(); i++) {
var iCommand = config.getPanes().get(i).getDialectLaunchCommand().buildSimple();
var iCommand =
config.getPanes().get(i).getDialectLaunchCommand().buildSimple();
var direction = splitIterator.getSplitDirection();
var directionString = direction == TerminalSplitStrategy.SplitDirection.HORIZONTAL ? "--direction right" : "--direction down";
l.addAll(List.of("zellij -s xpipe action new-pane " +
directionString +
" --name \"" +
escape(config.getPanes().get(i).getTitle(), false, true) +
"\"", "zellij -s xpipe action write-chars -- " + escape(" " + iCommand, true, true) + "\\;exit",
"zellij -s xpipe action write 10", "zellij -s xpipe action clear",
var directionString = direction == TerminalSplitStrategy.SplitDirection.HORIZONTAL
? "--direction right"
: "--direction down";
l.addAll(List.of(
"zellij -s xpipe action new-pane " + directionString
+ " --name \""
+ escape(config.getPanes().get(i).getTitle(), false, true)
+ "\"",
"zellij -s xpipe action write-chars -- " + escape(" " + iCommand, true, true) + "\\;exit",
"zellij -s xpipe action write 10",
"zellij -s xpipe action clear",
"zellij -s xpipe action focus-next-pane"));
splitIterator.next();
}
@@ -82,8 +85,8 @@ public class ZellijTerminalMultiplexer implements TerminalMultiplexer {
sc.command("zellij attach --create-background xpipe").executeAndCheck();
var asyncLines = new ArrayList<String>();
asyncLines.addAll(List.of(
"sleep 0.5",
asyncLines.addAll(List.of(
"sleep 0.5",
"zellij -s xpipe action new-tab --name \"" + escape(config.getColoredTitle(), false, true) + "\"",
"zellij -s xpipe action write-chars -- " + escape(" " + firstCommand, true, true) + "\\;exit",
"zellij -s xpipe action write 10",
@@ -93,10 +96,12 @@ public class ZellijTerminalMultiplexer implements TerminalMultiplexer {
"zellij -s xpipe action close-tab"));
if (config.getPanes().size() > 1) {
var splitIterator = AppPrefs.get().terminalSplitStrategy().getValue().iterator();
var splitIterator =
AppPrefs.get().terminalSplitStrategy().getValue().iterator();
splitIterator.next();
for (int i = 1; i < config.getPanes().size(); i++) {
var iCommand = config.getPanes().get(i).getDialectLaunchCommand().buildSimple();
var iCommand =
config.getPanes().get(i).getDialectLaunchCommand().buildSimple();
var direction = splitIterator.getSplitDirection();
var directionString = direction == TerminalSplitStrategy.SplitDirection.HORIZONTAL
? "--direction right"

View File

@@ -59,8 +59,7 @@ public class AppInstaller {
public void installLocal(Path file) {
var logsDir =
AppLogs.get().getSessionLogsDirectory().getParent().toString();
var logFile =
FilePath.of(logsDir, "installer.log");
var logFile = FilePath.of(logsDir, "installer.log");
var systemWide = isSystemWide();
var cmdScript = LocalShell.getDialect() == ShellDialects.CMD && !systemWide;
var command = cmdScript

View File

@@ -23,13 +23,15 @@ public class UpdateChangelogDialog {
public static void showIfNeeded() {
var update = AppDistributionType.get().getUpdateHandler().getPerformedUpdate();
if (update != null && !AppDistributionType.get().getUpdateHandler().isUpdateSucceeded()) {
ErrorEvent.ErrorEventBuilder eventBuilder = ErrorEventFactory.fromMessage(AppI18n.get("updateFail")).documentationLink(
DocumentationLink.UPDATE_FAIL).customAction(ErrorAction.translated("updateFailAction", () -> {
Hyperlinks.open(Hyperlinks.GITHUB_LATEST);
return true;
}));
ErrorEvent.ErrorEventBuilder eventBuilder = ErrorEventFactory.fromMessage(AppI18n.get("updateFail"))
.documentationLink(DocumentationLink.UPDATE_FAIL)
.customAction(ErrorAction.translated("updateFailAction", () -> {
Hyperlinks.open(Hyperlinks.GITHUB_LATEST);
return true;
}));
if (OsType.ofLocal() == OsType.WINDOWS) {
var installerLog = AppLogs.get().getSessionLogsDirectory().getParent().resolve("installer.log");
var installerLog =
AppLogs.get().getSessionLogsDirectory().getParent().resolve("installer.log");
if (Files.exists(installerLog)) {
eventBuilder.attachment(installerLog);
}

View File

@@ -8,7 +8,6 @@ import io.xpipe.app.core.AppLocalTemp;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.process.OsFileSystem;
import io.xpipe.app.process.ShellTemp;
import io.xpipe.core.FailableFunction;
import io.xpipe.core.FailableSupplier;

View File

@@ -3,7 +3,6 @@ package io.xpipe.app.util;
import io.xpipe.app.core.AppLocalTemp;
import io.xpipe.app.process.CommandBuilder;
import io.xpipe.app.process.LocalShell;
import io.xpipe.app.process.ShellTemp;
import io.xpipe.core.JacksonMapper;
import java.io.IOException;

View File

@@ -4,7 +4,6 @@ import io.xpipe.app.core.AppLocalTemp;
import io.xpipe.app.core.window.AppMainWindow;
import io.xpipe.app.process.LocalShell;
import io.xpipe.app.process.OsFileSystem;
import io.xpipe.app.process.ShellTemp;
import io.xpipe.app.rdp.RdpLaunchConfig;
import io.xpipe.app.vnc.VncLaunchConfig;
import io.xpipe.core.SecretValue;

View File

@@ -1,6 +1,7 @@
package io.xpipe.beacon;
import io.xpipe.core.OsType;
import lombok.experimental.UtilityClass;
import java.nio.file.Path;
@@ -57,11 +58,13 @@ public class BeaconConfig {
.map(Boolean::parseBoolean)
.orElse(false);
if (OsType.ofLocal() == OsType.LINUX) {
return Path.of(System.getProperty("java.io.tmpdir"), staging ? "xpipe-ptb" : "xpipe",
System.getProperty("user.name"), "beacon-auth");
} else {
return Path.of(System.getProperty("java.io.tmpdir"), staging ? "xpipe-ptb" : "xpipe",
return Path.of(
System.getProperty("java.io.tmpdir"),
staging ? "xpipe-ptb" : "xpipe",
System.getProperty("user.name"),
"beacon-auth");
} else {
return Path.of(System.getProperty("java.io.tmpdir"), staging ? "xpipe-ptb" : "xpipe", "beacon-auth");
}
}
}

View File

@@ -4,8 +4,8 @@ import io.xpipe.app.comp.Comp;
import io.xpipe.app.comp.CompStructure;
import io.xpipe.app.comp.SimpleCompStructure;
import io.xpipe.app.comp.base.*;
import io.xpipe.app.platform.MenuHelper;
import javafx.application.Platform;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;

View File

@@ -18,8 +18,8 @@ import io.xpipe.ext.base.identity.ssh.SshIdentityStrategyChoiceConfig;
import javafx.beans.binding.Bindings;
import javafx.beans.property.*;
import javafx.beans.value.ObservableValue;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Value;
@@ -42,10 +42,15 @@ public class IdentityChoiceBuilder {
ObservableValue<String> passwordChoiceTranslationKey;
public IdentityChoiceBuilder(
ObjectProperty<IdentityValue> identity, boolean allowCustomUserInput, boolean requireUserInput, boolean requirePassword, boolean keyInput,
ObjectProperty<IdentityValue> identity,
boolean allowCustomUserInput,
boolean requireUserInput,
boolean requirePassword,
boolean keyInput,
boolean requireKeyInput,
boolean allowAgentForward, String userChoiceTranslationKey, String passwordChoiceTranslationKey
) {
boolean allowAgentForward,
String userChoiceTranslationKey,
String passwordChoiceTranslationKey) {
this.identity = identity;
this.allowCustomUserInput = allowCustomUserInput;
this.requireUserInput = requireUserInput;
@@ -121,12 +126,18 @@ public class IdentityChoiceBuilder {
.nameAndDescription(userChoiceTranslationKey)
.addComp(new IdentitySelectComp(ref, user, pass, identityStrategy, allowCustomUserInput), user)
.nonNullIf(inPlaceSelected.and(new SimpleBooleanProperty(requireUserInput)))
.name(Bindings.createStringBinding(() -> {
return AppI18n.get(passwordChoiceTranslationKey.getValue());
}, passwordChoiceTranslationKey, AppI18n.activeLanguage()))
.description(Bindings.createStringBinding(() -> {
return AppI18n.get(passwordChoiceTranslationKey.getValue() + "Description");
}, passwordChoiceTranslationKey, AppI18n.activeLanguage()))
.name(Bindings.createStringBinding(
() -> {
return AppI18n.get(passwordChoiceTranslationKey.getValue());
},
passwordChoiceTranslationKey,
AppI18n.activeLanguage()))
.description(Bindings.createStringBinding(
() -> {
return AppI18n.get(passwordChoiceTranslationKey.getValue() + "Description");
},
passwordChoiceTranslationKey,
AppI18n.activeLanguage()))
.sub(passwordChoice, pass)
.nonNullIf(inPlaceSelected.and(new SimpleBooleanProperty(requirePassword)))
.hide(refSelected)
@@ -155,10 +166,14 @@ public class IdentityChoiceBuilder {
// In case of team vaults, identities shouldn't really be specified inline anyway
// If they are, we use the vault key to make it accessible for all users
var useUserKey = DataStorageUserHandler.getInstance().getUserCount() <= 1;
var p = useUserKey ? EncryptedValue.CurrentKey.of(pass.get()) : EncryptedValue.VaultKey.of(pass.get());
EncryptedValue<SshIdentityStrategy> i = keyInput ?
(useUserKey ? EncryptedValue.CurrentKey.of(identityStrategy.get()) : EncryptedValue.VaultKey.of(identityStrategy.get())) :
null;
var p = useUserKey
? EncryptedValue.CurrentKey.of(pass.get())
: EncryptedValue.VaultKey.of(pass.get());
EncryptedValue<SshIdentityStrategy> i = keyInput
? (useUserKey
? EncryptedValue.CurrentKey.of(identityStrategy.get())
: EncryptedValue.VaultKey.of(identityStrategy.get()))
: null;
if (u == null && p == null && i == null) {
return null;
} else {

View File

@@ -175,7 +175,10 @@ public class InPlaceKeyStrategy implements SshIdentityStrategy {
}
private FilePath getTargetFilePath() {
var temp = AppSystemInfo.ofCurrent().getTemp().resolve("xpipe-" + Math.abs(Objects.hash(this, AppSystemInfo.ofCurrent().getUser())) + ".key");
var temp = AppSystemInfo.ofCurrent()
.getTemp()
.resolve("xpipe-"
+ Math.abs(Objects.hash(this, AppSystemInfo.ofCurrent().getUser())) + ".key");
return FilePath.of(temp);
}
}