diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreCategoryWrapper.java b/app/src/main/java/io/xpipe/app/comp/store/StoreCategoryWrapper.java index 61464a1ff..b18c603ec 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreCategoryWrapper.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreCategoryWrapper.java @@ -1,9 +1,9 @@ package io.xpipe.app.comp.store; import io.xpipe.app.fxcomps.util.PlatformThread; +import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreCategory; -import io.xpipe.app.storage.DataStoreEntry; import javafx.beans.property.Property; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; @@ -64,9 +64,9 @@ public class StoreCategoryWrapper { .orElse(null); } - public boolean contains(DataStoreEntry entry) { - return entry.getCategoryUuid().equals(category.getUuid()) - || children.stream().anyMatch(storeCategoryWrapper -> storeCategoryWrapper.contains(entry)); + public boolean contains(StoreEntryWrapper entry) { + return entry.getEntry().getCategoryUuid().equals(category.getUuid()) + || containedEntries.contains(entry); } public void select() { @@ -88,6 +88,10 @@ public class StoreCategoryWrapper { update(); })); + AppPrefs.get().showChildCategoriesInParentCategory().addListener((observable, oldValue, newValue) -> { + update(); + }); + sortMode.addListener((observable, oldValue, newValue) -> { category.setSortMode(newValue); }); @@ -118,7 +122,10 @@ public class StoreCategoryWrapper { share.setValue(category.isShare()); containedEntries.setAll(StoreViewState.get().getAllEntries().stream() - .filter(entry -> contains(entry.getEntry())) + .filter(entry -> { + return entry.getEntry().getCategoryUuid().equals(category.getUuid()) + || (AppPrefs.get().showChildCategoriesInParentCategory().get() && children.stream().anyMatch(storeCategoryWrapper -> storeCategoryWrapper.contains(entry))); + }) .toList()); children.setAll(StoreViewState.get().getCategories().stream() .filter(storeCategoryWrapper -> getCategory() diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListComp.java index 47f07e454..2973a396a 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListComp.java @@ -36,7 +36,7 @@ public class StoreEntryListComp extends SimpleComp { () -> { var all = StoreViewState.get().getAllConnectionsCategory(); var connections = StoreViewState.get().getAllEntries().stream() - .filter(wrapper -> all.contains(wrapper.getEntry())) + .filter(wrapper -> all.contains(wrapper)) .toList(); return initialCount == connections.size() && StoreViewState.get() diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreSection.java b/app/src/main/java/io/xpipe/app/comp/store/StoreSection.java index 0872ef158..61cd76226 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreSection.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreSection.java @@ -100,7 +100,7 @@ public class StoreSection { var matchesSelector = section.anyMatches(entryFilter); var sameCategory = category == null || category.getValue() == null - || category.getValue().contains(section.getWrapper().getEntry()); + || category.getValue().contains(section.getWrapper()); return showFilter && matchesSelector && sameCategory; }, category, @@ -139,7 +139,7 @@ public class StoreSection { var matchesSelector = section.anyMatches(entryFilter); var sameCategory = category == null || category.getValue() == null - || category.getValue().contains(section.getWrapper().getEntry()); + || category.getValue().contains(section.getWrapper()); // If this entry is already shown as root due to a different category than parent, don't show it // again here var notRoot = 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 0976ff7ed..b51e2c0da 100644 --- a/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java +++ b/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java @@ -39,23 +39,15 @@ public class AppPrefs { final BooleanProperty performanceMode = map(new SimpleBooleanProperty(false), "performanceMode", Boolean.class); final BooleanProperty useBundledTools = map(new SimpleBooleanProperty(false), "useBundledTools", Boolean.class); - // Languages - // ========= public final ObjectProperty theme = map(new SimpleObjectProperty<>(), "theme", AppTheme.Theme.class); final BooleanProperty useSystemFont = map(new SimpleBooleanProperty(true), "useSystemFont", Boolean.class); final Property uiScale = map(new SimpleObjectProperty<>(null), "uiScale", Integer.class); final BooleanProperty saveWindowLocation = map(new SimpleBooleanProperty(true), "saveWindowLocation", Boolean.class); - // External terminal - // ================= final ObjectProperty terminalType = map(new SimpleObjectProperty<>(), "terminalType", ExternalTerminalType.class); - // Window opacity - // ============== final DoubleProperty windowOpacity = map(new SimpleDoubleProperty(1.0), "windowOpacity", Double.class); - // Custom terminal - // =============== final StringProperty customTerminalCommand = map(new SimpleStringProperty(""), "customTerminalCommand", String.class); final BooleanProperty preferTerminalTabs = @@ -74,34 +66,19 @@ public class AppPrefs { map(new SimpleBooleanProperty(false), "dontCachePasswords", Boolean.class); public final BooleanProperty denyTempScriptCreation = map(new SimpleBooleanProperty(false), "denyTempScriptCreation", Boolean.class); - // Password manager - // ================ final StringProperty passwordManagerCommand = map(new SimpleStringProperty(""), "passwordManagerCommand", String.class); - // Start behaviour - // =============== final ObjectProperty startupBehaviour = map(new SimpleObjectProperty<>(StartupBehaviour.GUI), "startupBehaviour", StartupBehaviour.class); - - // Lock - // ==== - // Git storage - // =========== public final BooleanProperty enableGitStorage = map(new SimpleBooleanProperty(false), "enableGitStorage", Boolean.class); final StringProperty storageGitRemote = map(new SimpleStringProperty(""), "storageGitRemote", String.class); - // Close behaviour - // =============== final ObjectProperty closeBehaviour = map(new SimpleObjectProperty<>(CloseBehaviour.QUIT), "closeBehaviour", CloseBehaviour.class); - // External editor - // =============== final ObjectProperty externalEditor = map(new SimpleObjectProperty<>(), "externalEditor", ExternalEditorType.class); final StringProperty customEditorCommand = map(new SimpleStringProperty(""), "customEditorCommand", String.class); final BooleanProperty preferEditorTabs = map(new SimpleBooleanProperty(true), "preferEditorTabs", Boolean.class); - // Automatically update - // ==================== final BooleanProperty automaticallyCheckForUpdates = map(new SimpleBooleanProperty(true), "automaticallyCheckForUpdates", Boolean.class); final BooleanProperty encryptAllVaultData = @@ -110,8 +87,8 @@ public class AppPrefs { map(new SimpleBooleanProperty(false), "enforceWindowModality", Boolean.class); final BooleanProperty condenseConnectionDisplay = map(new SimpleBooleanProperty(false), "condenseConnectionDisplay", Boolean.class); - // Storage - // ======= + final BooleanProperty showChildCategoriesInParentCategory = + map(new SimpleBooleanProperty(true), "showChildrenConnectionsInParentCategory", Boolean.class); final ObjectProperty storageDirectory = map(new SimpleObjectProperty<>(DEFAULT_STORAGE_DIR), "storageDirectory", Path.class); private final AppPrefsStorageHandler vaultStorageHandler = @@ -293,6 +270,10 @@ public class AppPrefs { return condenseConnectionDisplay; } + public ObservableBooleanValue showChildCategoriesInParentCategory() { + return showChildCategoriesInParentCategory; + } + public ReadOnlyProperty closeBehaviour() { return closeBehaviour; } diff --git a/app/src/main/java/io/xpipe/app/prefs/AppearanceCategory.java b/app/src/main/java/io/xpipe/app/prefs/AppearanceCategory.java index 64ac0da7a..5f3277018 100644 --- a/app/src/main/java/io/xpipe/app/prefs/AppearanceCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/AppearanceCategory.java @@ -31,7 +31,9 @@ public class AppearanceCategory extends AppPrefsCategory { .nameAndDescription("useSystemFont") .addToggle(prefs.useSystemFont) .nameAndDescription("condenseConnectionDisplay") - .addToggle(prefs.condenseConnectionDisplay)) + .addToggle(prefs.condenseConnectionDisplay) + .nameAndDescription("showChildCategoriesInParentCategory") + .addToggle(prefs.showChildCategoriesInParentCategory)) .addTitle("windowOptions") .sub(new OptionsBuilder() .nameAndDescription("windowOpacity") diff --git a/app/src/main/resources/io/xpipe/app/resources/lang/preferences_en.properties b/app/src/main/resources/io/xpipe/app/resources/lang/preferences_en.properties index 2c2ce9806..eaa99a1c6 100644 --- a/app/src/main/resources/io/xpipe/app/resources/lang/preferences_en.properties +++ b/app/src/main/resources/io/xpipe/app/resources/lang/preferences_en.properties @@ -55,6 +55,8 @@ windowOptions=Window Options saveWindowLocation=Save window location saveWindowLocationDescription=Controls whether the window coordinates should be saved and restored on restarts. startupShutdown=Startup / Shutdown +showChildCategoriesInParentCategory=Show child categories in parent category +showChildCategoriesInParentCategoryDescription=Whether or not to include all connections located in sub categories when having a certain parent category is selected.\n\nIf this is disabled, the categories behave more like classical folders which only show their direct contents without including sub folders. condenseConnectionDisplay=Condense connection display condenseConnectionDisplayDescription=Make every top level connection take a less vertical space to allow for a more condensed connection list. enforceWindowModality=Enforce window modality