diff --git a/app/src/main/java/io/xpipe/app/comp/base/ListBoxViewComp.java b/app/src/main/java/io/xpipe/app/comp/base/ListBoxViewComp.java index 2812d56c7..7060f5e07 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/ListBoxViewComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/ListBoxViewComp.java @@ -134,9 +134,7 @@ public class ListBoxViewComp extends RegionBuilder { // If one node within has focus and moves out of focus fast, // the scrollbar will try to focus another one and move it into view // This can result in flicker when scrolling fast enough - if (scroll.isFocusWithin()) { - scroll.requestFocus(); - } + scroll.requestFocus(); dirty.set(true); }); scroll.heightProperty().addListener((observable, oldValue, newValue) -> { diff --git a/app/src/main/java/io/xpipe/app/hub/comp/StoreSectionBaseComp.java b/app/src/main/java/io/xpipe/app/hub/comp/StoreSectionBaseComp.java index 8adc1685a..5f21125d5 100644 --- a/app/src/main/java/io/xpipe/app/hub/comp/StoreSectionBaseComp.java +++ b/app/src/main/java/io/xpipe/app/hub/comp/StoreSectionBaseComp.java @@ -92,7 +92,12 @@ public abstract class StoreSectionBaseComp extends RegionBuilder { AtomicReference built = new AtomicReference<>(); Consumer update = (visible) -> { if (visible) { - if (root.getScene() == null || !root.isVisible()) { + // Ignore any changes before this was added to the scene + if (root.getScene() == null && built.get() == null) { + return; + } + + if (!root.isVisible()) { return; } diff --git a/app/src/main/java/io/xpipe/app/hub/comp/StoreViewState.java b/app/src/main/java/io/xpipe/app/hub/comp/StoreViewState.java index 4285e4c7a..60be64ad8 100644 --- a/app/src/main/java/io/xpipe/app/hub/comp/StoreViewState.java +++ b/app/src/main/java/io/xpipe/app/hub/comp/StoreViewState.java @@ -82,8 +82,9 @@ public class StoreViewState { @Getter private final ObservableValue> effectiveSortMode = Bindings.createObjectBinding( () -> { - var g = globalSortMode.getValue() != null ? globalSortMode.getValue() : null; - var t = tieSortMode.getValue() != null ? tieSortMode.getValue() : StoreSectionSortMode.DATE_DESC; + var global = globalSortMode.getValue() != null ? globalSortMode.getValue() : null; + var tie = tieSortMode.getValue() != null ? tieSortMode.getValue() : StoreSectionSortMode.DATE_DESC; + var fallback = Comparator.comparing(sec -> sec.getWrapper().getName().getValue()); var failed = Comparator.comparingInt(value -> { if (value.getWrapper().getValidity().getValue() == DataStoreEntry.Validity.LOAD_FAILED) { return 1; @@ -91,9 +92,9 @@ public class StoreViewState { return 0; }); - return g != null - ? failed.thenComparing(g.comparator().thenComparing(t.comparator())) - : failed.thenComparing(t.comparator()); + return global != null + ? failed.thenComparing(global.comparator().thenComparing(tie.comparator())).thenComparing(fallback) + : failed.thenComparing(tie.comparator()).thenComparing(fallback); }, globalSortMode, tieSortMode); diff --git a/app/src/main/java/io/xpipe/app/process/ShellDialects.java b/app/src/main/java/io/xpipe/app/process/ShellDialects.java index d8d8eb6ca..fdd27c1ae 100644 --- a/app/src/main/java/io/xpipe/app/process/ShellDialects.java +++ b/app/src/main/java/io/xpipe/app/process/ShellDialects.java @@ -61,7 +61,7 @@ public class ShellDialects { return d == POWERSHELL || d == POWERSHELL_CORE; } - public static Optional byNameIfPresent(String name) { + public static Optional byIdIfPresent(String name) { return ALL.stream().filter(shellType -> shellType.getId().equals(name)).findFirst(); } diff --git a/app/src/main/java/io/xpipe/app/process/ShellView.java b/app/src/main/java/io/xpipe/app/process/ShellView.java index 920e91a6f..c5e27db3c 100644 --- a/app/src/main/java/io/xpipe/app/process/ShellView.java +++ b/app/src/main/java/io/xpipe/app/process/ShellView.java @@ -32,6 +32,10 @@ public class ShellView { return shellControl.getShellDialect(); } + public synchronized void setCachedPredicate(String key, boolean value) { + genericCache.put(key, value); + } + public synchronized boolean getCachedPredicate(String key, FailableSupplier supplier) throws Exception { var v = genericCache.get(key); if (v != null) { 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 758e0b8f5..eaacfadf0 100644 --- a/app/src/main/java/io/xpipe/app/storage/DataStorage.java +++ b/app/src/main/java/io/xpipe/app/storage/DataStorage.java @@ -948,6 +948,13 @@ public abstract class DataStorage { for (DataStoreEntry e : toAdd) { e.refreshStore(); } + + // Retain ordering + toAdd.reversed().forEach(e -> { + ThreadHelper.sleep(1); + e.notifyUpdate(false, true); + }); + this.listeners.forEach(l -> l.onStoreAdd(toAdd.toArray(DataStoreEntry[]::new))); saveAsync(); } diff --git a/app/src/main/java/io/xpipe/app/storage/DataStoreCategory.java b/app/src/main/java/io/xpipe/app/storage/DataStoreCategory.java index ba1da9a8c..214cd2580 100644 --- a/app/src/main/java/io/xpipe/app/storage/DataStoreCategory.java +++ b/app/src/main/java/io/xpipe/app/storage/DataStoreCategory.java @@ -175,6 +175,11 @@ public class DataStoreCategory extends StorageElement { return true; } + @Override + public boolean isInStorage() { + return DataStorage.get().getStoreCategories().contains(this); + } + @Override public Path[] getShareableFiles() { return new Path[] {directory.resolve("category.json")}; diff --git a/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java b/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java index 6f612ce69..377790b31 100644 --- a/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java +++ b/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java @@ -525,6 +525,11 @@ public class DataStoreEntry extends StorageElement { } } + @Override + public boolean isInStorage() { + return DataStorage.get().getStoreEntries().contains(this); + } + @Override public Path[] getShareableFiles() { var notes = directory.resolve("notes.md"); diff --git a/app/src/main/java/io/xpipe/app/storage/StorageElement.java b/app/src/main/java/io/xpipe/app/storage/StorageElement.java index a2ed7a06a..d12795a88 100644 --- a/app/src/main/java/io/xpipe/app/storage/StorageElement.java +++ b/app/src/main/java/io/xpipe/app/storage/StorageElement.java @@ -85,10 +85,15 @@ public abstract class StorageElement { synchronized (listeners) { listeners.forEach(l -> l.onUpdate()); } + // Save changes instantly - DataStorage.get().saveAsync(); + if (isInStorage()) { + DataStorage.get().saveAsync(); + } } + public abstract boolean isInStorage(); + public abstract Path[] getShareableFiles(); public void notifyUpdate(boolean used, boolean modified) { @@ -105,7 +110,7 @@ public abstract class StorageElement { } // Save changes instantly - if (modified) { + if (modified && isInStorage()) { DataStorage.get().saveAsync(); } } diff --git a/app/src/main/java/io/xpipe/app/util/AppJacksonModule.java b/app/src/main/java/io/xpipe/app/util/AppJacksonModule.java index 238584317..7748ea455 100644 --- a/app/src/main/java/io/xpipe/app/util/AppJacksonModule.java +++ b/app/src/main/java/io/xpipe/app/util/AppJacksonModule.java @@ -210,10 +210,10 @@ public class AppJacksonModule extends SimpleModule { if (t == null) { return null; } - return ShellDialects.byNameIfPresent(t.asText()).orElse(null); + return ShellDialects.byIdIfPresent(t.asText()).orElse(null); } - return ShellDialects.byNameIfPresent(tree.asText()).orElse(null); + return ShellDialects.byIdIfPresent(tree.asText()).orElse(null); } } diff --git a/lang/strings/translations_en.properties b/lang/strings/translations_en.properties index 962d71ba5..9ef8fdd72 100644 --- a/lang/strings/translations_en.properties +++ b/lang/strings/translations_en.properties @@ -1615,6 +1615,10 @@ gitRepoDontWarn=Don't warn anymore gitRepoDontWarnDescription=If this is expected, make XPipe ignore this error in the future gitRepoTryAgain=Try again gitRepoTryAgainDescription=Attempt the same operation again +gitRepoEnablePlain=Use plain directory sync +gitRepoEnablePlainDescription=Don't initialize a git repository to sync changes to directory +gitRepoCreateBare=Use git sync +gitRepoCreateBareDescription=Initialize a new bare git repository in the sync directory gitRepoDisable=Disable git vault for now gitRepoDisableDescription=Don't commit any changes during this session gitRepoPullRefresh=Pull changes and refresh diff --git a/version b/version index 44983118e..79b565d3d 100644 --- a/version +++ b/version @@ -1 +1 @@ -21.0-9 +21.0-10