diff --git a/app/src/main/java/io/xpipe/app/browser/BookmarkList.java b/app/src/main/java/io/xpipe/app/browser/BookmarkList.java index 063867482..ed2c6af64 100644 --- a/app/src/main/java/io/xpipe/app/browser/BookmarkList.java +++ b/app/src/main/java/io/xpipe/app/browser/BookmarkList.java @@ -44,7 +44,7 @@ final class BookmarkList extends SimpleComp { button.setOnAction(event -> { var fileSystem = ((ShellStore) e.getEntry().getStore()); - model.openFileSystem(fileSystem); + model.openFileSystemAsync(fileSystem); event.consume(); }); GrowAugment.create(true, false).augment(new SimpleCompStructure<>(button)); diff --git a/app/src/main/java/io/xpipe/app/browser/FileBrowserModel.java b/app/src/main/java/io/xpipe/app/browser/FileBrowserModel.java index 39ca96a21..ef37942fc 100644 --- a/app/src/main/java/io/xpipe/app/browser/FileBrowserModel.java +++ b/app/src/main/java/io/xpipe/app/browser/FileBrowserModel.java @@ -71,14 +71,14 @@ public class FileBrowserModel { if (found.isPresent()) { selected.setValue(found.get()); } else { - openFileSystem(store); + openFileSystemAsync(store); } } - public void openFileSystem(ShellStore store) { + public void openFileSystemAsync(ShellStore store) { // Prevent multiple tabs in non browser modes if (!mode.equals(Mode.BROWSER)) { - ThreadHelper.runAsync(() -> { + ThreadHelper.runFailableAsync(() -> { var open = openFileSystems.size() > 0 ? openFileSystems.get(0) : null; if (open != null) { open.closeSync(); @@ -88,23 +88,16 @@ public class FileBrowserModel { var model = new OpenFileSystemModel(this); openFileSystems.add(model); selected.setValue(model); - model.switchAsync(store); + model.switchSync(store); }); return; } - // Duplication protection (Not needed for now) -// var found = openFileSystems.stream() -// .filter(fileSystemModel -> fileSystemModel.getStore().getValue().equals(store)) -// .findFirst(); -// if (found.isPresent()) { -// selected.setValue(found.get()); -// return; -// } - - var model = new OpenFileSystemModel(this); - openFileSystems.add(model); - selected.setValue(model); - model.switchAsync(store); + ThreadHelper.runFailableAsync(() -> { + var model = new OpenFileSystemModel(this); + openFileSystems.add(model); + selected.setValue(model); + model.switchSync(store); + }); } } diff --git a/app/src/main/java/io/xpipe/app/browser/FileBrowserStatusBarComp.java b/app/src/main/java/io/xpipe/app/browser/FileBrowserStatusBarComp.java index 10d6b4b3f..549c84e09 100644 --- a/app/src/main/java/io/xpipe/app/browser/FileBrowserStatusBarComp.java +++ b/app/src/main/java/io/xpipe/app/browser/FileBrowserStatusBarComp.java @@ -8,9 +8,11 @@ import io.xpipe.app.fxcomps.util.PlatformThread; import javafx.beans.binding.Bindings; import javafx.scene.control.ToolBar; import javafx.scene.layout.Region; +import lombok.EqualsAndHashCode; import lombok.Value; @Value +@EqualsAndHashCode(callSuper = true) public class FileBrowserStatusBarComp extends SimpleComp { OpenFileSystemModel model; @@ -20,7 +22,7 @@ public class FileBrowserStatusBarComp extends SimpleComp { var cc = PlatformThread.sync(FileBrowserClipboard.currentCopyClipboard); var ccCount = Bindings.createStringBinding(() -> { if (cc.getValue() != null && cc.getValue().getEntries().size() > 0) { - return String.valueOf(cc.getValue().getEntries().size()) + " file" + (cc.getValue().getEntries().size() > 1 ? "s" : "") + " in clipboard"; + return cc.getValue().getEntries().size() + " file" + (cc.getValue().getEntries().size() > 1 ? "s" : "") + " in clipboard"; } else { return null; } diff --git a/app/src/main/java/io/xpipe/app/browser/FileListComp.java b/app/src/main/java/io/xpipe/app/browser/FileListComp.java index 20305311e..5a81cc632 100644 --- a/app/src/main/java/io/xpipe/app/browser/FileListComp.java +++ b/app/src/main/java/io/xpipe/app/browser/FileListComp.java @@ -178,6 +178,13 @@ final class FileListComp extends AnchorPane { } }); + prepareTableEntries(table); + prepareTableChanges(table, mtimeCol, modeCol); + + return table; + } + + private void prepareTableEntries(TableView table) { var emptyEntry = new FileListCompEntry(table, null, fileList); table.setOnDragOver(event -> { emptyEntry.onDragOver(event); @@ -242,16 +249,17 @@ final class FileListComp extends AnchorPane { return row; }); - + } + private void prepareTableChanges(TableView table, TableColumn mtimeCol, TableColumn modeCol) { var lastDir = new SimpleObjectProperty(); - SimpleChangeListener.apply(fileList.getShown(), (newValue) -> { + Runnable updateHandler = () -> { PlatformThread.runLaterIfNeeded(() -> { var newItems = new ArrayList(); var parentEntry = fileList.getFileSystemModel().getCurrentParentDirectory(); if (parentEntry != null) { newItems.add(parentEntry); } - newItems.addAll(newValue); + newItems.addAll(fileList.getShown().getValue()); var hasModifiedDate = newItems.size() == 0 || newItems.stream().anyMatch(entry -> entry.getDate() != null); @@ -278,7 +286,9 @@ final class FileListComp extends AnchorPane { } } - table.getItems().setAll(newItems); + if (!table.getItems().equals(newItems)) { + table.getItems().setAll(newItems); + } var currentDirectory = fileList.getFileSystemModel().getCurrentDirectory(); if (!Objects.equals(lastDir.get(), currentDirectory)) { @@ -295,9 +305,16 @@ final class FileListComp extends AnchorPane { } lastDir.setValue(currentDirectory); }); + }; + updateHandler.run(); + fileList.getShown().addListener((observable, oldValue, newValue) -> { + updateHandler.run(); + }); + fileList.getFileSystemModel().getCurrentPath().addListener((observable, oldValue, newValue) -> { + if (oldValue == null) { + updateHandler.run(); + } }); - - return table; } private void borderScroll(TableView tableView, DragEvent event) { diff --git a/app/src/main/java/io/xpipe/app/browser/OpenFileSystemComp.java b/app/src/main/java/io/xpipe/app/browser/OpenFileSystemComp.java index 0ebbf02f7..028279b9a 100644 --- a/app/src/main/java/io/xpipe/app/browser/OpenFileSystemComp.java +++ b/app/src/main/java/io/xpipe/app/browser/OpenFileSystemComp.java @@ -84,7 +84,10 @@ public class OpenFileSystemComp extends SimpleComp { FileListComp directoryView = new FileListComp(model.getFileList()); - var root = new VBox(topBar, directoryView, new FileBrowserStatusBarComp(model).createRegion()); + var root = new VBox(topBar, directoryView); + if (model.getBrowserModel().getMode() == FileBrowserModel.Mode.BROWSER) { + root.getChildren().add(new FileBrowserStatusBarComp(model).createRegion()); + } VBox.setVgrow(directoryView, Priority.ALWAYS); root.setPadding(Insets.EMPTY); model.getFileList().predicateProperty().set(PREDICATE_NOT_HIDDEN); diff --git a/app/src/main/java/io/xpipe/app/browser/OpenFileSystemModel.java b/app/src/main/java/io/xpipe/app/browser/OpenFileSystemModel.java index c8faae958..fa81db1a5 100644 --- a/app/src/main/java/io/xpipe/app/browser/OpenFileSystemModel.java +++ b/app/src/main/java/io/xpipe/app/browser/OpenFileSystemModel.java @@ -75,28 +75,28 @@ final class OpenFileSystemModel { } public Optional cd(String path) { - if (Objects.equals(path, currentPath.get())) { - return Optional.empty(); - } - - String newPath = null; - try { - newPath = FileSystemHelper.resolveDirectoryPath(this, path); - } catch (Exception ex) { - ErrorEvent.fromThrowable(ex).handle(); - return Optional.of(currentPath.get()); - } - - if (!Objects.equals(path, newPath)) { - return Optional.of(newPath); - } - - ThreadHelper.runFailableAsync(() -> { - try (var ignored = new BusyProperty(busy)) { - cdSync(path); - } - }); + if (Objects.equals(path, currentPath.get())) { return Optional.empty(); + } + + String newPath = null; + try { + newPath = FileSystemHelper.resolveDirectoryPath(this, path); + } catch (Exception ex) { + ErrorEvent.fromThrowable(ex).handle(); + return Optional.of(currentPath.get()); + } + + if (!Objects.equals(path, newPath)) { + return Optional.of(newPath); + } + + ThreadHelper.runFailableAsync(() -> { + try (var ignored = new BusyProperty(busy)) { + cdSync(path); + } + }); + return Optional.empty(); } private void cdSync(String path) throws Exception { @@ -123,7 +123,8 @@ final class OpenFileSystemModel { fileList.setAll(stream); } else { var stream = getFileSystem().listRoots().stream() - .map(s -> new FileSystem.FileEntry(getFileSystem(), s, Instant.now(), true, false, false, 0, null)); + .map(s -> new FileSystem.FileEntry( + getFileSystem(), s, Instant.now(), true, false, false, 0, null)); noDirectory.set(true); fileList.setAll(stream); } @@ -248,22 +249,16 @@ final class OpenFileSystemModel { store = null; } - private void switchSync(FileSystemStore fileSystem) throws Exception { - closeSync(); - this.store.setValue(fileSystem); - var fs = fileSystem.createFileSystem(); - fs.open(); - this.fileSystem = fs; + public void switchSync(FileSystemStore fileSystem) throws Exception { + BusyProperty.execute(busy, () -> { + closeSync(); + this.store.setValue(fileSystem); + var fs = fileSystem.createFileSystem(); + fs.open(); + this.fileSystem = fs; - var current = FileSystemHelper.getStartDirectory(this); - cdSync(current); - } - - public void switchAsync(FileSystemStore fileSystem) { - ThreadHelper.runFailableAsync(() -> { - BusyProperty.execute(busy, () -> { - switchSync(fileSystem); - }); + var current = FileSystemHelper.getStartDirectory(this); + cdSync(current); }); } @@ -278,7 +273,10 @@ final class OpenFileSystemModel { var connection = ((ConnectionFileSystem) fileSystem).getShellControl(); var command = s.control() .initWith(connection.getShellDialect().getCdCommand(directory)) - .prepareTerminalOpen(directory + " - " + XPipeDaemon.getInstance().getStoreName(store.getValue()).orElse("?")); + .prepareTerminalOpen(directory + " - " + + XPipeDaemon.getInstance() + .getStoreName(store.getValue()) + .orElse("?")); TerminalHelper.open(directory, command); } }); diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/DataStoreChoiceComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/DataStoreChoiceComp.java index 6e869813c..631f7b5c8 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/DataStoreChoiceComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/DataStoreChoiceComp.java @@ -66,7 +66,7 @@ public class DataStoreChoiceComp extends SimpleComp { .filter(e -> e.equals(s)) .findAny() .flatMap(store -> { - if (ShellStore.isLocal(store.asNeeded()) && mode == Mode.PROXY) { + if (mode == Mode.PROXY && ShellStore.isLocal(store.asNeeded())) { return Optional.of(AppI18n.get("none")); }