From 9cb0b7f494c064152f11012ab4f01c90f5470993 Mon Sep 17 00:00:00 2001 From: crschnick Date: Thu, 18 May 2023 09:48:31 +0000 Subject: [PATCH] File browser improvements --- .../io/xpipe/app/browser/BookmarkList.java | 135 +++++++++++++----- .../io/xpipe/app/browser/FileBrowserComp.java | 88 +++++------- .../xpipe/app/browser/FileBrowserModel.java | 55 ++++--- .../xpipe/app/browser/FileSystemHelper.java | 2 +- .../app/browser/OpenFileSystemModel.java | 37 ++--- .../comp/storage/store/StoreEntryTree.java | 36 +++++ .../main/java/io/xpipe/app/core/AppTheme.java | 35 +++++ .../io/xpipe/app/fxcomps/impl/SvgView.java | 2 +- .../io/xpipe/app/launcher/LauncherInput.java | 5 +- .../io/xpipe/app/resources/style/browser.css | 17 ++- .../browser/OpenDirectoryInNewTabAction.java | 2 +- 11 files changed, 281 insertions(+), 133 deletions(-) create mode 100644 app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryTree.java 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 ed2c6af6..015a327a 100644 --- a/app/src/main/java/io/xpipe/app/browser/BookmarkList.java +++ b/app/src/main/java/io/xpipe/app/browser/BookmarkList.java @@ -1,19 +1,23 @@ package io.xpipe.app.browser; -import io.xpipe.app.comp.base.ListBoxViewComp; -import io.xpipe.app.comp.storage.store.StoreEntryFlatMiniSectionComp; -import io.xpipe.app.fxcomps.Comp; +import io.xpipe.app.comp.storage.store.StoreEntryTree; +import io.xpipe.app.comp.storage.store.StoreEntryWrapper; +import io.xpipe.app.comp.storage.store.StoreViewState; import io.xpipe.app.fxcomps.SimpleComp; -import io.xpipe.app.fxcomps.SimpleCompStructure; -import io.xpipe.app.fxcomps.augment.DragPseudoClassAugment; -import io.xpipe.app.fxcomps.augment.GrowAugment; -import io.xpipe.app.fxcomps.util.BindingsHelper; +import io.xpipe.app.fxcomps.impl.PrettyImageComp; import io.xpipe.core.store.DataStore; import io.xpipe.core.store.ShellStore; import javafx.application.Platform; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; import javafx.geometry.Point2D; -import javafx.scene.control.Button; +import javafx.scene.Node; +import javafx.scene.control.TreeCell; +import javafx.scene.control.TreeItem; +import javafx.scene.control.TreeView; import javafx.scene.input.DragEvent; +import javafx.scene.input.MouseButton; +import javafx.scene.input.MouseEvent; import javafx.scene.layout.Region; import java.util.Timer; @@ -33,34 +37,101 @@ final class BookmarkList extends SimpleComp { @Override protected Region createSimple() { - var observableList = BindingsHelper.filteredContentBinding(StoreEntryFlatMiniSectionComp.ALL, e -> e.getEntry().getState().isUsable()); - var list = new ListBoxViewComp<>(observableList, observableList, e -> { - return Comp.of(() -> { - var button = new Button(null, e.createRegion()); + var root = StoreEntryTree.createTree(); + var view = new TreeView(root); + view.setShowRoot(false); + view.getStyleClass().add("bookmark-list"); + view.setCellFactory(param -> { + return new StoreCell(); + }); - if (!(e.getEntry().getStore() instanceof ShellStore)) { - button.setDisable(true); + model.getSelected().addListener((observable, oldValue, newValue) -> { + if (newValue == null) { + view.getSelectionModel().clearSelection(); + return; + } + + view.getSelectionModel() + .select(getTreeViewItem( + root, + StoreViewState.get().getAllEntries().stream() + .filter(storeEntryWrapper -> storeEntryWrapper + .getState() + .getValue() + .isUsable() + && storeEntryWrapper + .getEntry() + .getStore() + .equals(newValue.getStore())) + .findAny() + .orElse(null))); + }); + + return view; + } + + private static TreeItem getTreeViewItem( + TreeItem item, StoreEntryWrapper value) { + if (item.getValue() != null && item.getValue().equals(value)) { + return item; + } + + for (TreeItem child : item.getChildren()) { + TreeItem s = getTreeViewItem(child, value); + if (s != null) { + return s; + } + } + return null; + } + + private final class StoreCell extends TreeCell { + + private final StringProperty img = new SimpleStringProperty(); + private final Node imageView = new PrettyImageComp(img, 20, 20).createRegion(); + + private StoreCell() { + setGraphic(imageView); + addEventHandler(DragEvent.DRAG_OVER, mouseEvent -> { + if (getItem() == null) { + return; } - button.setOnAction(event -> { - var fileSystem = ((ShellStore) e.getEntry().getStore()); - model.openFileSystemAsync(fileSystem); - event.consume(); - }); - GrowAugment.create(true, false).augment(new SimpleCompStructure<>(button)); - DragPseudoClassAugment.create().augment(new SimpleCompStructure<>(button)); - - button.addEventHandler( - DragEvent.DRAG_OVER, - mouseEvent -> handleHoverTimer(e.getEntry().getStore(), mouseEvent)); - button.addEventHandler( - DragEvent.DRAG_EXITED, - mouseEvent -> activeTask = null); - - return button; + handleHoverTimer(getItem().getEntry().getStore(), mouseEvent); + mouseEvent.consume(); }); - }).styleClass("bookmark-list").createRegion(); - return list; + addEventHandler(DragEvent.DRAG_EXITED, mouseEvent -> { + activeTask = null; + mouseEvent.consume(); + }); + addEventHandler(MouseEvent.MOUSE_CLICKED, event -> { + if (getItem() == null || event.getButton() != MouseButton.PRIMARY) { + return; + } + + var fileSystem = ((ShellStore) getItem().getEntry().getStore()); + model.openFileSystemAsync(fileSystem, null); + event.consume(); + }); + } + + @Override + public void updateItem(StoreEntryWrapper item, boolean empty) { + super.updateItem(item, empty); + if (empty || item == null) { + setText(null); + // Don't set image as that would trigger image comp update + // and cells are emptied on each change, leading to unnecessary changes + // img.set(null); + setGraphic(null); + } else { + setText(item.getName()); + img.set(item.getEntry() + .getProvider() + .getDisplayIconFileName(item.getEntry().getStore())); + setGraphic(imageView); + } + } } private void handleHoverTimer(DataStore store, DragEvent event) { diff --git a/app/src/main/java/io/xpipe/app/browser/FileBrowserComp.java b/app/src/main/java/io/xpipe/app/browser/FileBrowserComp.java index 2fce55cd..09522128 100644 --- a/app/src/main/java/io/xpipe/app/browser/FileBrowserComp.java +++ b/app/src/main/java/io/xpipe/app/browser/FileBrowserComp.java @@ -11,13 +11,13 @@ import io.xpipe.app.fxcomps.SimpleCompStructure; import io.xpipe.app.fxcomps.augment.GrowAugment; import io.xpipe.app.fxcomps.impl.PrettyImageComp; import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.fxcomps.util.SimpleChangeListener; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.util.BusyProperty; import io.xpipe.app.util.ThreadHelper; import javafx.application.Platform; import javafx.beans.binding.Bindings; import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleStringProperty; import javafx.collections.ListChangeListener; import javafx.event.EventHandler; import javafx.geometry.Insets; @@ -46,27 +46,32 @@ public class FileBrowserComp extends SimpleComp { protected Region createSimple() { FileType.loadDefinitions(); DirectoryType.loadDefinitions(); - ThreadHelper.runAsync( () -> { + ThreadHelper.runAsync(() -> { FileIconManager.loadIfNecessary(); }); var bookmarksList = new BookmarkList(model).createRegion(); VBox.setVgrow(bookmarksList, Priority.ALWAYS); - var localDownloadStage = new LocalFileTransferComp(model.getLocalTransfersStage()).hide(Bindings.createBooleanBinding(() -> { - if (model.getOpenFileSystems().size() == 0) { - return true; - } + var localDownloadStage = new LocalFileTransferComp(model.getLocalTransfersStage()) + .hide(PlatformThread.sync(Bindings.createBooleanBinding( + () -> { + if (model.getOpenFileSystems().size() == 0) { + return true; + } - return !model.getMode().equals(FileBrowserModel.Mode.BROWSER); - }, PlatformThread.sync(model.getOpenFileSystems()))).createRegion(); - SimpleChangeListener.apply(model.getSelected(), val -> { - localDownloadStage.visibleProperty().unbind(); - if (val == null) { - return; - } + if (!model.getMode().equals(FileBrowserModel.Mode.BROWSER)) { + return true; + } - localDownloadStage.visibleProperty().bind(PlatformThread.sync(val.getLocal().not())); - }); + if (model.getSelected().getValue() != null) { + return model.getSelected().getValue().isLocal(); + } + + return false; + }, + model.getOpenFileSystems(), + model.getSelected()))) + .createRegion(); var vertical = new VBox(bookmarksList, localDownloadStage); vertical.setFillWidth(true); @@ -75,9 +80,10 @@ public class FileBrowserComp extends SimpleComp { .widthProperty() .addListener( // set sidebar width in pixels depending on split pane width - (obs, old, val) -> splitPane.setDividerPosition(0, 230 / splitPane.getWidth())); + (obs, old, val) -> splitPane.setDividerPosition(0, 280 / splitPane.getWidth())); var r = addBottomBar(splitPane); + r.getStyleClass().add("browser"); // AppFont.small(r); return r; } @@ -92,14 +98,14 @@ public class FileBrowserComp extends SimpleComp { var selected = new HBox(); selected.setAlignment(Pos.CENTER_LEFT); selected.setSpacing(10); -// model.getSelected().addListener((ListChangeListener) c -> { -// selected.getChildren().setAll(c.getList().stream().map(s -> { -// var field = new TextField(s.getPath()); -// field.setEditable(false); -// field.setPrefWidth(400); -// return field; -// }).toList()); -// }); + // model.getSelected().addListener((ListChangeListener) c -> { + // selected.getChildren().setAll(c.getList().stream().map(s -> { + // var field = new TextField(s.getPath()); + // field.setEditable(false); + // field.setPrefWidth(400); + // return field; + // }).toList()); + // }); var spacer = new Spacer(Orientation.HORIZONTAL); var button = new Button("Select"); button.setOnAction(event -> model.finishChooser()); @@ -128,7 +134,8 @@ public class FileBrowserComp extends SimpleComp { map.put(v, t); tabs.getTabs().add(t); }); - tabs.getSelectionModel().select(model.getOpenFileSystems().indexOf(model.getSelected().getValue())); + tabs.getSelectionModel() + .select(model.getOpenFileSystems().indexOf(model.getSelected().getValue())); // Used for ignoring changes by the tabpane when new tabs are added. We want to perform the selections manually! var modifying = new SimpleBooleanProperty(); @@ -195,8 +202,6 @@ public class FileBrowserComp extends SimpleComp { } } }); - - stack.getStyleClass().add("browser"); return stack; } @@ -228,29 +233,14 @@ public class FileBrowserComp extends SimpleComp { .bind(Bindings.createDoubleBinding( () -> model.getBusy().get() ? -1d : 0, PlatformThread.sync(model.getBusy()))); - var name = Bindings.createStringBinding( - () -> { - return model.getStore().getValue() != null - ? DataStorage.get() - .getStoreEntry(model.getStore().getValue()) - .getName() - : null; - }, - PlatformThread.sync(model.getStore())); - var image = Bindings.createStringBinding( - () -> { - return model.getStore().getValue() != null - ? DataStorage.get() - .getStoreEntry(model.getStore().getValue()) - .getProvider() - .getDisplayIconFileName(model.getStore().getValue()) - : null; - }, - model.getStore()); - var logo = new PrettyImageComp(image, 20, 20).createRegion(); + var name = DataStorage.get().getStoreEntry(model.getStore()).getName(); + var image = DataStorage.get() + .getStoreEntry(model.getStore()) + .getProvider() + .getDisplayIconFileName(model.getStore()); + var logo = new PrettyImageComp(new SimpleStringProperty(image), 20, 20).createRegion(); - var label = new Label(); - label.textProperty().bind(name); + var label = new Label(name); label.addEventHandler(DragEvent.DRAG_ENTERED, new EventHandler() { @Override public void handle(DragEvent mouseEvent) { 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 b8cb678e..748c0019 100644 --- a/app/src/main/java/io/xpipe/app/browser/FileBrowserModel.java +++ b/app/src/main/java/io/xpipe/app/browser/FileBrowserModel.java @@ -71,46 +71,43 @@ public class FileBrowserModel { public void openExistingFileSystemIfPresent(ShellStore store) { var found = openFileSystems.stream() - .filter(model -> Objects.equals(model.getStore().getValue(), store)) + .filter(model -> Objects.equals(model.getStore(), store)) .findFirst(); if (found.isPresent()) { selected.setValue(found.get()); } else { - openFileSystemAsync(store); + openFileSystemAsync(store, null); } } - public void openFileSystemSync(ShellStore store, String path) throws Exception { - var model = new OpenFileSystemModel(this); - openFileSystems.add(model); - selected.setValue(model); - model.switchSync(store); - model.cd(path); - } - - public void openFileSystemAsync(ShellStore store) { - // Prevent multiple tabs in non browser modes - if (!mode.equals(Mode.BROWSER)) { - ThreadHelper.runFailableAsync(() -> { - var open = openFileSystems.size() > 0 ? openFileSystems.get(0) : null; - if (open != null) { - open.closeSync(); - openFileSystems.remove(open); - } - - var model = new OpenFileSystemModel(this); - openFileSystems.add(model); - selected.setValue(model); - model.switchSync(store); - }); - return; - } + public void openFileSystemAsync(ShellStore store, String path) { + // // Prevent multiple tabs in non browser modes + // if (!mode.equals(Mode.BROWSER)) { + // ThreadHelper.runFailableAsync(() -> { + // var open = openFileSystems.size() > 0 ? openFileSystems.get(0) : null; + // if (open != null) { + // open.closeSync(); + // openFileSystems.remove(open); + // } + // + // var model = new OpenFileSystemModel(this, store); + // openFileSystems.add(model); + // selected.setValue(model); + // model.switchSync(store); + // }); + // return; + // } ThreadHelper.runFailableAsync(() -> { - var model = new OpenFileSystemModel(this); + var model = new OpenFileSystemModel(this, store); + model.initFileSystem(); openFileSystems.add(model); selected.setValue(model); - model.switchSync(store); + if (path != null) { + model.cd(path); + } else { + model.initDirectory(); + } }); } } diff --git a/app/src/main/java/io/xpipe/app/browser/FileSystemHelper.java b/app/src/main/java/io/xpipe/app/browser/FileSystemHelper.java index bdf66992..3ab0bb2e 100644 --- a/app/src/main/java/io/xpipe/app/browser/FileSystemHelper.java +++ b/app/src/main/java/io/xpipe/app/browser/FileSystemHelper.java @@ -21,7 +21,7 @@ public class FileSystemHelper { } ConnectionFileSystem fileSystem = (ConnectionFileSystem) model.getFileSystem(); - var current = !(model.getStore().getValue() instanceof LocalStore) + var current = !model.isLocal() ? fileSystem .getShellControl() .executeSimpleStringCommand( 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 71ff74e2..c3e9b21f 100644 --- a/app/src/main/java/io/xpipe/app/browser/OpenFileSystemModel.java +++ b/app/src/main/java/io/xpipe/app/browser/OpenFileSystemModel.java @@ -34,7 +34,7 @@ import java.util.stream.Stream; @Getter public final class OpenFileSystemModel { - private Property store = new SimpleObjectProperty<>(); + private final FileSystemStore store; private FileSystem fileSystem; private final Property filter = new SimpleStringProperty(); private final FileListModel fileList; @@ -46,10 +46,11 @@ public final class OpenFileSystemModel { private final Property savedState = new SimpleObjectProperty<>(); private final OpenFileSystemCache cache = new OpenFileSystemCache(this); private final Property overlay = new SimpleObjectProperty<>(); - private final BooleanProperty local = new SimpleBooleanProperty(); + private boolean local; - public OpenFileSystemModel(FileBrowserModel browserModel) { + public OpenFileSystemModel(FileBrowserModel browserModel, FileSystemStore store) { this.browserModel = browserModel; + this.store = store; fileList = new FileListModel(this); addListeners(); } @@ -61,7 +62,7 @@ public final class OpenFileSystemModel { } BusyProperty.execute(busy, () -> { - if (store.getValue() instanceof ShellStore s) { + if (store instanceof ShellStore s) { c.accept(fileSystem.getShell().orElseThrow()); if (refresh) { refreshSync(); @@ -73,11 +74,11 @@ public final class OpenFileSystemModel { private void addListeners() { savedState.addListener((observable, oldValue, newValue) -> { - if (store.getValue() == null) { + if (store == null) { return; } - var storageEntry = DataStorage.get().getStoreEntryIfPresent(store.getValue()); + var storageEntry = DataStorage.get().getStoreEntryIfPresent(store); storageEntry.ifPresent(entry -> AppCache.update("browser-state-" + entry.getUuid(), newValue)); }); @@ -128,7 +129,7 @@ public final class OpenFileSystemModel { if (!FileNames.isAbsolute(path) && fileSystem.getShell().isPresent()) { var directory = currentPath.get(); var name = path + " - " - + XPipeDaemon.getInstance().getStoreName(store.getValue()).orElse("?"); + + XPipeDaemon.getInstance().getStoreName(store).orElse("?"); ThreadHelper.runFailableAsync(() -> { if (ShellDialects.ALL.stream().anyMatch(dialect -> path.startsWith(dialect.getOpenCommand()))) { var cmd = fileSystem @@ -177,7 +178,7 @@ public final class OpenFileSystemModel { private void cdSyncWithoutCheck(String path) throws Exception { if (fileSystem == null) { - var fs = store.getValue().createFileSystem(); + var fs = store.createFileSystem(); fs.open(); this.fileSystem = fs; } @@ -323,21 +324,21 @@ public final class OpenFileSystemModel { ErrorEvent.fromThrowable(e).handle(); } fileSystem = null; - store = null; } - public void switchSync(FileSystemStore fileSystem) throws Exception { + public void initFileSystem() throws Exception { BusyProperty.execute(busy, () -> { - closeSync(); - this.store.setValue(fileSystem); - var fs = fileSystem.createFileSystem(); + var fs = store.createFileSystem(); fs.open(); this.fileSystem = fs; - this.local.set( - fs.getShell().map(shellControl -> shellControl.isLocal()).orElse(false)); + this.local = fs.getShell().map(shellControl -> shellControl.isLocal()).orElse(false); + }); + } + public void initDirectory() throws Exception { + BusyProperty.execute(busy, () -> { var storageEntry = DataStorage.get() - .getStoreEntryIfPresent(fileSystem) + .getStoreEntryIfPresent(store) .map(entry -> entry.getUuid()) .orElse(UUID.randomUUID()); this.savedState.setValue( @@ -362,13 +363,13 @@ public final class OpenFileSystemModel { } BusyProperty.execute(busy, () -> { - if (store.getValue() instanceof ShellStore s) { + if (store instanceof ShellStore s) { var connection = ((ConnectionFileSystem) fileSystem).getShellControl(); var command = s.control() .initWith(connection.getShellDialect().getCdCommand(directory)) .prepareTerminalOpen(directory + " - " + XPipeDaemon.getInstance() - .getStoreName(store.getValue()) + .getStoreName(store) .orElse("?")); TerminalHelper.open(directory, command); } diff --git a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryTree.java b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryTree.java new file mode 100644 index 00000000..2c264879 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryTree.java @@ -0,0 +1,36 @@ +package io.xpipe.app.comp.storage.store; + +import javafx.collections.ListChangeListener; +import javafx.scene.control.TreeItem; + +public class StoreEntryTree { + + public static TreeItem createTree() { + var topLevel = StoreSection.createTopLevel(); + var root = new TreeItem(); + root.setExpanded(true); + + // Listen for any entry list change, not only top level changes + StoreViewState.get().getAllEntries().addListener((ListChangeListener) c -> { + root.getChildren().clear(); + for (StoreSection v : topLevel.getChildren()) { + add(root, v); + } + }); + + for (StoreSection v : topLevel.getChildren()) { + add(root, v); + } + + return root; + } + + private static void add(TreeItem parent, StoreSection section) { + var item = new TreeItem<>(section.getWrapper()); + item.setExpanded(section.getWrapper().getExpanded().getValue()); + parent.getChildren().add(item); + for (StoreSection child : section.getChildren()) { + add(item, child); + } + } +} diff --git a/app/src/main/java/io/xpipe/app/core/AppTheme.java b/app/src/main/java/io/xpipe/app/core/AppTheme.java index 17c60776..961121aa 100644 --- a/app/src/main/java/io/xpipe/app/core/AppTheme.java +++ b/app/src/main/java/io/xpipe/app/core/AppTheme.java @@ -8,12 +8,30 @@ import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.TrackEvent; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.core.process.OsType; +import javafx.animation.Interpolator; +import javafx.animation.KeyFrame; +import javafx.animation.KeyValue; +import javafx.animation.Timeline; import javafx.application.Application; +import javafx.css.PseudoClass; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.Pane; +import javafx.scene.paint.Color; +import javafx.stage.Window; +import javafx.util.Duration; import lombok.AllArgsConstructor; import lombok.Getter; public class AppTheme { + public record AccentColor(Color primaryColor, PseudoClass pseudoClass) { + + public static AccentColor xpipeBlue() { + return new AccentColor(Color.web("#11B4B4"), PseudoClass.getPseudoClass("accent-primer-purple")); + } + } + public static void init() { if (AppPrefs.get() == null) { return; @@ -60,6 +78,23 @@ public class AppTheme { private static void changeTheme(Theme newTheme) { PlatformThread.runLaterIfNeeded(() -> { + for (Window window : Window.getWindows()) { + var scene = window.getScene(); + Image snapshot = scene.snapshot(null); + Pane root = (Pane) scene.getRoot(); + + ImageView imageView = new ImageView(snapshot); + root.getChildren().add(imageView); + + // Animate! + var transition = new Timeline( + new KeyFrame(Duration.ZERO, new KeyValue(imageView.opacityProperty(), 1, Interpolator.EASE_OUT)), + new KeyFrame( + Duration.millis(1250), new KeyValue(imageView.opacityProperty(), 0, Interpolator.EASE_OUT))); + transition.setOnFinished(e -> root.getChildren().remove(imageView)); + transition.play(); + } + Application.setUserAgentStylesheet(newTheme.getTheme().getUserAgentStylesheet()); TrackEvent.debug("Set theme " + newTheme.getId() + " for scene"); }); diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/SvgView.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/SvgView.java index 07fb5480..f8989fa6 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/SvgView.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/SvgView.java @@ -52,7 +52,7 @@ public class SvgView { var widthProperty = new SimpleIntegerProperty(); var heightProperty = new SimpleIntegerProperty(); SimpleChangeListener.apply(content, val -> { - if (val == null) { + if (val == null || val.isBlank()) { return; } diff --git a/app/src/main/java/io/xpipe/app/launcher/LauncherInput.java b/app/src/main/java/io/xpipe/app/launcher/LauncherInput.java index 258b376f..395c2675 100644 --- a/app/src/main/java/io/xpipe/app/launcher/LauncherInput.java +++ b/app/src/main/java/io/xpipe/app/launcher/LauncherInput.java @@ -1,9 +1,11 @@ package io.xpipe.app.launcher; +import io.xpipe.app.browser.FileBrowserModel; import io.xpipe.app.core.mode.OperationMode; import io.xpipe.app.ext.ActionProvider; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.TrackEvent; +import io.xpipe.core.store.ShellStore; import lombok.Getter; import lombok.Value; @@ -114,7 +116,8 @@ public abstract class LauncherInput { return; } - // GuiDsCreatorMultiStep.showForStore(DataSourceProvider.Category.STREAM, FileStore.local(file), null); + var dir = Files.isDirectory(file) ? file : file.getParent(); + FileBrowserModel.DEFAULT.openFileSystemAsync(ShellStore.createLocal(), dir.toString()); } @Override diff --git a/app/src/main/resources/io/xpipe/app/resources/style/browser.css b/app/src/main/resources/io/xpipe/app/resources/style/browser.css index b382eab8..5c22fa96 100644 --- a/app/src/main/resources/io/xpipe/app/resources/style/browser.css +++ b/app/src/main/resources/io/xpipe/app/resources/style/browser.css @@ -49,7 +49,22 @@ } .browser .bookmark-list { - -fx-border-width: 0 0 1 1; + -fx-border-width: 0; +} + +.browser .bookmark-list *.scroll-bar:horizontal, +.browser .bookmark-list *.scroll-bar:horizontal *.track, +.browser .bookmark-list *.scroll-bar:horizontal *.track-background, +.browser .bookmark-list *.scroll-bar:horizontal *.thumb, +.browser .bookmark-list *.scroll-bar:horizontal *.increment-button, +.browser .bookmark-list *.scroll-bar:horizontal *.decrement-button, +.browser .bookmark-list *.scroll-bar:horizontal *.increment-arrow, +.browser .bookmark-list *.scroll-bar:horizontal *.decrement-arrow { + -fx-background-color: null; + -fx-background-radius: 0; + -fx-background-insets: 0; + -fx-padding: 0; + -fx-shape: null; } .browser .tool-bar { diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryInNewTabAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryInNewTabAction.java index 3f18b306..bdc3422e 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryInNewTabAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryInNewTabAction.java @@ -16,7 +16,7 @@ public class OpenDirectoryInNewTabAction implements LeafAction { @Override public void execute(OpenFileSystemModel model, List entries) throws Exception { - model.getBrowserModel().openFileSystemSync(model.getStore().getValue().asNeeded(), entries.get(0).getRawFileEntry().getPath()); + model.getBrowserModel().openFileSystemAsync(model.getStore().asNeeded(), entries.get(0).getRawFileEntry().getPath()); } @Override