From 02b9ba6062474c7cb0cbcd220e9d0740bb645fc1 Mon Sep 17 00:00:00 2001 From: crschnick Date: Mon, 10 Jun 2024 18:51:37 +0000 Subject: [PATCH] More rework --- .../app/comp/store/DenseStoreEntryComp.java | 2 +- .../comp/store/StandardStoreEntryComp.java | 2 +- .../xpipe/app/comp/store/StoreEntryComp.java | 60 ++++++++----------- .../app/comp/store/StoreEntryWrapper.java | 22 ++++--- .../java/io/xpipe/app/prefs/AppPrefs.java | 2 +- ...rverCategory.java => HttpApiCategory.java} | 4 +- .../io/xpipe/app/storage/DataStorage.java | 1 + .../app/terminal/ExternalTerminalType.java | 32 +++++++++- dist/changelogs/10.0.md | 4 +- lang/app/strings/translations_en.properties | 1 + 10 files changed, 77 insertions(+), 53 deletions(-) rename app/src/main/java/io/xpipe/app/prefs/{HttpServerCategory.java => HttpApiCategory.java} (91%) diff --git a/app/src/main/java/io/xpipe/app/comp/store/DenseStoreEntryComp.java b/app/src/main/java/io/xpipe/app/comp/store/DenseStoreEntryComp.java index b5953cc85..29a52a0ac 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/DenseStoreEntryComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/DenseStoreEntryComp.java @@ -103,7 +103,7 @@ public class DenseStoreEntryComp extends StoreEntryComp { grid.getColumnConstraints().addAll(infoCC, custom); var cr = content != null ? content.createRegion() : new Region(); - var bb = createButtonBar().createRegion(); + var bb = createButtonBar(); var controls = new HBox(cr, bb); controls.setFillHeight(true); controls.setAlignment(Pos.CENTER_RIGHT); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StandardStoreEntryComp.java b/app/src/main/java/io/xpipe/app/comp/store/StandardStoreEntryComp.java index a95a95dbf..595e7bc56 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StandardStoreEntryComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StandardStoreEntryComp.java @@ -51,7 +51,7 @@ public class StandardStoreEntryComp extends StoreEntryComp { var custom = new ColumnConstraints(0, customSize, customSize); custom.setHalignment(HPos.RIGHT); var cr = content != null ? content.createRegion() : new Region(); - var bb = createButtonBar().createRegion(); + var bb = createButtonBar(); var controls = new HBox(cr, bb); controls.setFillHeight(true); HBox.setHgrow(cr, Priority.ALWAYS); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java index 981d9cca8..40bd3e715 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java @@ -1,5 +1,6 @@ package io.xpipe.app.comp.store; +import atlantafx.base.layout.InputGroup; import atlantafx.base.theme.Styles; import io.xpipe.app.comp.base.LoadingOverlayComp; import io.xpipe.app.core.*; @@ -9,8 +10,12 @@ import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.SimpleCompStructure; import io.xpipe.app.fxcomps.augment.ContextMenuAugment; import io.xpipe.app.fxcomps.augment.GrowAugment; -import io.xpipe.app.fxcomps.impl.*; +import io.xpipe.app.fxcomps.impl.IconButtonComp; +import io.xpipe.app.fxcomps.impl.LabelComp; +import io.xpipe.app.fxcomps.impl.PrettyImageHelper; +import io.xpipe.app.fxcomps.impl.TooltipAugment; import io.xpipe.app.fxcomps.util.BindingsHelper; +import io.xpipe.app.fxcomps.util.DerivedObservableList; import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.storage.DataStorage; @@ -199,40 +204,27 @@ public abstract class StoreEntryComp extends SimpleComp { return stack; } - protected Comp createButtonBar() { - var list = new ArrayList>(); - for (var p : wrapper.getActionProviders()) { - var def = p.getDefaultDataStoreCallSite(); - if (def != null && def.equals(wrapper.getDefaultActionProvider().getValue())) { - continue; - } + protected Region createButtonBar() { + var list = new DerivedObservableList<>(wrapper.getActionProviders(), false); + var buttons = list.mapped(actionProvider -> { + var button = buildButton(actionProvider); + return button != null ? button.createRegion() : null; + }).filtered(region -> region != null).getList(); - var button = buildButton(p); - if (button != null) { - list.add(button); - } - } - - var settingsButton = createSettingsButton(); - list.add(settingsButton); - if (list.size() > 1) { - list.getFirst().styleClass(Styles.LEFT_PILL); - for (int i = 1; i < list.size() - 1; i++) { - list.get(i).styleClass(Styles.CENTER_PILL); - } - list.getLast().styleClass(Styles.RIGHT_PILL); - } - list.forEach(comp -> { - comp.apply(struc -> { - struc.get().getStyleClass().remove(Styles.FLAT); - }); - }); - return new HorizontalComp(list) - .apply(struc -> { - struc.get().setAlignment(Pos.CENTER_RIGHT); - struc.get().setPadding(new Insets(5)); - }) - .styleClass("button-bar"); + var ig = new InputGroup(); + Runnable update = () -> { + var l = new ArrayList(buttons); + var settingsButton = createSettingsButton().createRegion(); + l.add(settingsButton); + l.forEach(o -> o.getStyleClass().remove(Styles.FLAT)); + ig.getChildren().setAll(l); + }; + buttons.subscribe(update); + update.run(); + ig.setAlignment(Pos.CENTER_RIGHT); + ig.setPadding(new Insets(5)); + ig.getStyleClass().add("button-bar"); + return ig; } private Comp buildButton(ActionProvider p) { diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryWrapper.java b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryWrapper.java index 8ffcc9f77..705295443 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryWrapper.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryWrapper.java @@ -10,6 +10,7 @@ import io.xpipe.app.storage.DataStoreColor; import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.util.ThreadHelper; import javafx.beans.property.*; +import javafx.collections.FXCollections; import lombok.Getter; import java.time.Duration; @@ -25,8 +26,8 @@ public class StoreEntryWrapper { private final BooleanProperty disabled = new SimpleBooleanProperty(); private final BooleanProperty busy = new SimpleBooleanProperty(); private final Property validity = new SimpleObjectProperty<>(); - private final List actionProviders; - private final Property> defaultActionProvider; + private final ListProperty actionProviders = new SimpleListProperty<>(FXCollections.observableArrayList()); + private final Property defaultActionProvider = new SimpleObjectProperty<>(); private final BooleanProperty deletable = new SimpleBooleanProperty(); private final BooleanProperty expanded = new SimpleBooleanProperty(); private final Property persistentState = new SimpleObjectProperty<>(); @@ -40,7 +41,6 @@ public class StoreEntryWrapper { this.entry = entry; this.name = new SimpleStringProperty(entry.getName()); this.lastAccess = new SimpleObjectProperty<>(entry.getLastAccess().minus(Duration.ofMillis(500))); - this.actionProviders = new ArrayList<>(); ActionProvider.ALL.stream() .filter(dataStoreActionProvider -> { return !entry.isDisabled() @@ -55,7 +55,6 @@ public class StoreEntryWrapper { .forEach(dataStoreActionProvider -> { actionProviders.add(dataStoreActionProvider); }); - this.defaultActionProvider = new SimpleObjectProperty<>(); this.notes = new SimpleObjectProperty<>(new StoreNotes(entry.getNotes(), entry.getNotes())); setupListeners(); } @@ -162,22 +161,21 @@ public class StoreEntryWrapper { .isAssignableFrom(entry.getStore().getClass()) && e.getDefaultDataStoreCallSite().isApplicable(entry.ref())) .findFirst() - .map(ActionProvider::getDefaultDataStoreCallSite) .orElse(null); this.defaultActionProvider.setValue(defaultProvider); - this.actionProviders.clear(); try { - ActionProvider.ALL.stream() + var newProviders = ActionProvider.ALL.stream() .filter(dataStoreActionProvider -> { - return showActionProvider(dataStoreActionProvider); + return !dataStoreActionProvider.equals(defaultProvider) && showActionProvider(dataStoreActionProvider); }) .sorted(Comparator.comparing( actionProvider -> actionProvider.getLeafDataStoreCallSite() != null && actionProvider.getLeafDataStoreCallSite().isSystemAction())) - .forEach(dataStoreActionProvider -> { - actionProviders.add(dataStoreActionProvider); - }); + .toList(); + if (!actionProviders.equals(newProviders)) { + actionProviders.setAll(newProviders); + } } catch (Exception ex) { ErrorEvent.fromThrowable(ex).handle(); } @@ -224,7 +222,7 @@ public class StoreEntryWrapper { var found = getDefaultActionProvider().getValue(); entry.notifyUpdate(true, false); if (found != null) { - found.createAction(entry.ref()).execute(); + found.getDefaultDataStoreCallSite().createAction(entry.ref()).execute(); } else { entry.setExpanded(!entry.isExpanded()); } diff --git a/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java b/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java index d3139cb02..a2e7e3582 100644 --- a/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java +++ b/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java @@ -171,7 +171,7 @@ public class AppPrefs { new SshCategory(), new LocalShellCategory(), new SecurityCategory(), - new HttpServerCategory(), + new HttpApiCategory(), new TroubleshootCategory(), new DeveloperCategory()) .filter(appPrefsCategory -> appPrefsCategory.show()) diff --git a/app/src/main/java/io/xpipe/app/prefs/HttpServerCategory.java b/app/src/main/java/io/xpipe/app/prefs/HttpApiCategory.java similarity index 91% rename from app/src/main/java/io/xpipe/app/prefs/HttpServerCategory.java rename to app/src/main/java/io/xpipe/app/prefs/HttpApiCategory.java index 5d22808e2..94bcf2ba3 100644 --- a/app/src/main/java/io/xpipe/app/prefs/HttpServerCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/HttpApiCategory.java @@ -4,11 +4,11 @@ import io.xpipe.app.beacon.AppBeaconServer; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.util.OptionsBuilder; -public class HttpServerCategory extends AppPrefsCategory { +public class HttpApiCategory extends AppPrefsCategory { @Override protected String getId() { - return "httpServer"; + return "httpApi"; } @Override diff --git a/app/src/main/java/io/xpipe/app/storage/DataStorage.java b/app/src/main/java/io/xpipe/app/storage/DataStorage.java index 320a6083d..e63d66b43 100644 --- a/app/src/main/java/io/xpipe/app/storage/DataStorage.java +++ b/app/src/main/java/io/xpipe/app/storage/DataStorage.java @@ -440,6 +440,7 @@ public abstract class DataStorage { } } }); + refreshEntries(); saveAsync(); toAdd.forEach(dataStoreEntryRef -> dataStoreEntryRef.get().getProvider().onChildrenRefresh(dataStoreEntryRef.getEntry())); toUpdate.forEach(dataStoreEntryRef -> dataStoreEntryRef.getKey().getProvider().onChildrenRefresh(dataStoreEntryRef.getKey())); diff --git a/app/src/main/java/io/xpipe/app/terminal/ExternalTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/ExternalTerminalType.java index f1a4a86d3..e281f21a2 100644 --- a/app/src/main/java/io/xpipe/app/terminal/ExternalTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/ExternalTerminalType.java @@ -238,6 +238,35 @@ public interface ExternalTerminalType extends PrefsChoiceValue { .addFile(configuration.getScriptFile()); } }; + ExternalTerminalType FOOT = new SimplePathType("app.foot", "foot", true) { + @Override + public String getWebsite() { + return "https://codeberg.org/dnkl/foot"; + } + + @Override + public boolean supportsTabs() { + return false; + } + + @Override + public boolean isRecommended() { + return false; + } + + @Override + public boolean supportsColoredTitle() { + return true; + } + + @Override + protected CommandBuilder toCommand(LaunchConfiguration configuration) { + return CommandBuilder.of() + .add("--title") + .addQuoted(configuration.getColoredTitle()) + .addFile(configuration.getScriptFile()); + } + }; ExternalTerminalType ELEMENTARY = new SimplePathType("app.elementaryTerminal", "io.elementary.terminal", true) { @Override @@ -262,7 +291,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue { @Override protected CommandBuilder toCommand(LaunchConfiguration configuration) { - return CommandBuilder.of().add("--new-tab").add("-e").addFile(configuration.getColoredTitle()); + return CommandBuilder.of().add("--new-tab").add("-e").addFile(configuration.getScriptFile()); } }; ExternalTerminalType TILIX = new SimplePathType("app.tilix", "tilix", true) { @@ -641,6 +670,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue { TILDA, XTERM, DEEPIN_TERMINAL, + FOOT, Q_TERMINAL); List MACOS_TERMINALS = List.of( KittyTerminalType.KITTY_MACOS, diff --git a/dist/changelogs/10.0.md b/dist/changelogs/10.0.md index d013f1619..d49ebf9cf 100644 --- a/dist/changelogs/10.0.md +++ b/dist/changelogs/10.0.md @@ -34,7 +34,7 @@ If you have existing scripts, they will have to be manually adjusted by setting The docker integration has been updated to support docker contexts. The UI has also been streamlined to make common actions more easily accessible. -There's also now support for Windows containers running on HyperV. +There's also now support for Windows docker containers running on HyperV. Note that old docker container connections will be removed as they are incompatible with the new version. @@ -51,3 +51,5 @@ You can now order connections relative to other sibling connections. This orderi - The Linux builds now list socat as a dependency such that the kitty terminal integration will work without issues - Searching for connections has been improved to show children as well - The welcome screen will now also contain the option to straight up jump to the synchronization settings +- Add support for foot terminal +- Fix elementary terminal not launching correctly diff --git a/lang/app/strings/translations_en.properties b/lang/app/strings/translations_en.properties index cfb47fde3..a3636c17d 100644 --- a/lang/app/strings/translations_en.properties +++ b/lang/app/strings/translations_en.properties @@ -474,3 +474,4 @@ storeIntroImportDescription=Already using XPipe on another system? Synchronize y importConnections=Sync connections importConnectionsTitle=Import Connections showAllChildren=Show all children +httpApi=HTTP API