From 8b486c8d84751ff39069b9fb0ffd2b46e42c7d4b Mon Sep 17 00:00:00 2001 From: crschnick Date: Wed, 19 Nov 2025 15:49:57 +0000 Subject: [PATCH] Various sftp improvements --- .../file/BrowserFileListCompEntry.java | 37 ++++++++++--------- .../app/browser/file/BrowserOverviewComp.java | 33 +++++++++-------- .../xpipe/app/ext/ConnectionFileSystem.java | 6 ++- .../io/xpipe/app/hub/comp/StoreViewState.java | 33 +++++++++++------ 4 files changed, 63 insertions(+), 46 deletions(-) diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListCompEntry.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListCompEntry.java index 1e467854b..d1d104556 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListCompEntry.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListCompEntry.java @@ -302,25 +302,28 @@ public class BrowserFileListCompEntry { .setValue(item == null || item.getRawFileEntry().getKind() != FileKind.DIRECTORY); model.getDraggedOverDirectory().setValue(item); - if (item != null) { - var timestamp = Instant.now(); - lastHoverUpdate = timestamp; - // Reduce printed window updates - GlobalTimer.delay( - () -> { - if (!timestamp.equals(lastHoverUpdate)) { - return; - } - if (item != model.getDraggedOverDirectory().getValue()) { - return; - } - - model.getFileSystemModel() - .cdAsync(item.getRawFileEntry().getPath()); - }, - Duration.ofMillis(500)); + if (item == null || item.getRawFileEntry().getKind() != FileKind.DIRECTORY) { + return; } + + var timestamp = Instant.now(); + lastHoverUpdate = timestamp; + // Reduce printed window updates + GlobalTimer.delay( + () -> { + if (!timestamp.equals(lastHoverUpdate)) { + return; + } + + if (item != model.getDraggedOverDirectory().getValue()) { + return; + } + + model.getFileSystemModel() + .cdAsync(item.getRawFileEntry().getPath()); + }, + Duration.ofMillis(500)); } public void onDragOver(DragEvent event) { diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserOverviewComp.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserOverviewComp.java index 558a87b84..230928987 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserOverviewComp.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserOverviewComp.java @@ -10,6 +10,7 @@ import io.xpipe.app.issue.ErrorEventFactory; import io.xpipe.app.platform.DerivedObservableList; import io.xpipe.app.util.ThreadHelper; +import io.xpipe.core.FilePath; import javafx.application.Platform; import javafx.beans.binding.Bindings; import javafx.collections.FXCollections; @@ -46,22 +47,22 @@ public class BrowserOverviewComp extends SimpleComp { var commonPlatform = FXCollections.synchronizedObservableList(FXCollections.observableArrayList()); ThreadHelper.runFailableAsync(() -> { - var common = model.getFileSystem().listCommonDirectories().stream() - .map(s -> FileEntry.ofDirectory(model.getFileSystem(), s)) - .filter(entry -> { - var fs = model.getFileSystem(); - - try { - return fs.directoryExists(entry.getPath()); - } catch (Exception e) { - ErrorEventFactory.fromThrowable(e).handle(); - return false; - } - }) - .toList(); - Platform.runLater(() -> { - commonPlatform.setAll(common); - }); + try { + var all = new ArrayList(); + for (FilePath cd : model.getFileSystem().listCommonDirectories()) { + var entry = FileEntry.ofDirectory(model.getFileSystem(), cd); + var fs = model.getFileSystem(); + if (fs.directoryExists(entry.getPath())) { + all.add(entry); + } + } + Platform.runLater(() -> { + commonPlatform.setAll(all); + }); + } catch (Exception e) { + // The file system can die + ErrorEventFactory.fromThrowable(e).expected().omit().handle(); + } }); var commonOverview = new BrowserFileOverviewComp(model, commonPlatform, false); var commonPane = new SimpleTitledPaneComp(AppI18n.observable("common"), commonOverview, false) diff --git a/app/src/main/java/io/xpipe/app/ext/ConnectionFileSystem.java b/app/src/main/java/io/xpipe/app/ext/ConnectionFileSystem.java index 2cf3786b8..8d8ca7639 100644 --- a/app/src/main/java/io/xpipe/app/ext/ConnectionFileSystem.java +++ b/app/src/main/java/io/xpipe/app/ext/ConnectionFileSystem.java @@ -12,6 +12,8 @@ import io.xpipe.core.OsType; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Getter; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Files; @@ -232,7 +234,7 @@ public class ConnectionFileSystem implements FileSystem { @Override public InputStream openInput(FilePath file) throws Exception { if (shellControl.isLocal()) { - return Files.newInputStream(file.asLocalPath()); + return new BufferedInputStream(Files.newInputStream(file.asLocalPath())); } return shellControl @@ -244,7 +246,7 @@ public class ConnectionFileSystem implements FileSystem { @Override public OutputStream openOutput(FilePath file, long totalBytes) throws Exception { if (shellControl.isLocal()) { - return Files.newOutputStream(file.asLocalPath()); + return new BufferedOutputStream(Files.newOutputStream(file.asLocalPath())); } var cmd = 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 de84bc5e9..b2d29b0f8 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 @@ -12,6 +12,7 @@ import io.xpipe.app.storage.DataStoreCategory; import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.storage.StorageListener; +import io.xpipe.app.util.ThreadHelper; import javafx.application.Platform; import javafx.beans.Observable; import javafx.beans.binding.Bindings; @@ -228,21 +229,31 @@ public class StoreViewState { } private void initFilterListener() { - var all = getAllConnectionsCategory(); filter.addListener((observable, oldValue, newValue) -> { - categories.getList().forEach(e -> e.update()); - var matchingCats = categories.getList().stream() - .filter(storeCategoryWrapper -> - storeCategoryWrapper.getRoot().equals(all)) - .filter(storeCategoryWrapper -> storeCategoryWrapper.getDirectContainedEntries().getList().stream() - .anyMatch(wrapper -> wrapper.matchesFilter(newValue))) - .toList(); - if (matchingCats.size() == 1) { - activeCategory.setValue(matchingCats.getFirst()); - } + ThreadHelper.runAsync(() -> { + onFilterUpdate(newValue); + }); }); } + private void onFilterUpdate(String newValue) { + var all = getAllConnectionsCategory(); + categories.getList().forEach(e -> { + Platform.runLater(() -> { + e.update(); + }); + }); + var matchingCats = categories.getList().stream() + .filter(storeCategoryWrapper -> + storeCategoryWrapper.getRoot().equals(all)) + .filter(storeCategoryWrapper -> storeCategoryWrapper.getDirectContainedEntries().getList().stream() + .anyMatch(wrapper -> wrapper.matchesFilter(newValue))) + .toList(); + if (matchingCats.size() == 1) { + activeCategory.setValue(matchingCats.getFirst()); + } + } + private void initBatchListeners() { batchModeSelection.getList().addListener((ListChangeListener) c -> { if (c.getList().isEmpty()) {