mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-09-19 22:01:12 +00:00
More browser improvements
This commit is contained in:
parent
01a3177843
commit
e0b34ff480
89
app/src/main/java/io/xpipe/app/browser/FileFilterComp.java
Normal file
89
app/src/main/java/io/xpipe/app/browser/FileFilterComp.java
Normal file
|
@ -0,0 +1,89 @@
|
|||
package io.xpipe.app.browser;
|
||||
|
||||
import atlantafx.base.theme.Styles;
|
||||
import io.xpipe.app.fxcomps.SimpleComp;
|
||||
import io.xpipe.app.fxcomps.SimpleCompStructure;
|
||||
import io.xpipe.app.fxcomps.augment.GrowAugment;
|
||||
import io.xpipe.app.fxcomps.impl.TextFieldComp;
|
||||
import io.xpipe.app.fxcomps.util.Shortcuts;
|
||||
import io.xpipe.app.fxcomps.util.SimpleChangeListener;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyCodeCombination;
|
||||
import javafx.scene.input.KeyCombination;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Region;
|
||||
import org.kordamp.ikonli.javafx.FontIcon;
|
||||
|
||||
public class FileFilterComp extends SimpleComp {
|
||||
|
||||
private final Property<String> filterString;
|
||||
|
||||
public FileFilterComp(Property<String> filterString) {
|
||||
this.filterString = filterString;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Region createSimple() {
|
||||
var expanded = new SimpleBooleanProperty();
|
||||
var text = new TextFieldComp(filterString, false).createRegion();
|
||||
text.focusedProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (!newValue && filterString.getValue() == null) {
|
||||
expanded.set(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (newValue) {
|
||||
expanded.set(true);
|
||||
}
|
||||
});
|
||||
filterString.addListener((observable, oldValue, newValue) -> {
|
||||
if (newValue == null && !text.isFocused()) {
|
||||
expanded.set(false);
|
||||
}
|
||||
});
|
||||
text.setMinWidth(0);
|
||||
Styles.toggleStyleClass(text, Styles.LEFT_PILL);
|
||||
|
||||
SimpleChangeListener.apply(filterString, val -> {
|
||||
if (val == null) {
|
||||
text.getStyleClass().remove(Styles.SUCCESS);
|
||||
} else {
|
||||
text.getStyleClass().add(Styles.SUCCESS);
|
||||
}
|
||||
});
|
||||
|
||||
var fi = new FontIcon("mdi2m-magnify");
|
||||
var button = new Button();
|
||||
GrowAugment.create(false, true).augment(new SimpleCompStructure<>(button));
|
||||
Shortcuts.addShortcut(button, new KeyCodeCombination(KeyCode.F, KeyCombination.SHORTCUT_DOWN));
|
||||
button.setGraphic(fi);
|
||||
button.setOnAction(event -> {
|
||||
if (expanded.get() && filterString.getValue() == null) {
|
||||
expanded.set(false);
|
||||
return;
|
||||
}
|
||||
|
||||
text.requestFocus();
|
||||
event.consume();
|
||||
});
|
||||
|
||||
SimpleChangeListener.apply(expanded, val -> {
|
||||
if (val) {
|
||||
text.setPrefWidth(250);
|
||||
button.getStyleClass().add(Styles.RIGHT_PILL);
|
||||
button.getStyleClass().remove(Styles.FLAT);
|
||||
} else {
|
||||
text.setPrefWidth(0);
|
||||
button.getStyleClass().remove(Styles.RIGHT_PILL);
|
||||
button.getStyleClass().add(Styles.FLAT);
|
||||
}
|
||||
});
|
||||
|
||||
var box = new HBox(text, button);
|
||||
box.setFillHeight(true);
|
||||
return box;
|
||||
}
|
||||
}
|
|
@ -22,10 +22,7 @@ import javafx.scene.Node;
|
|||
import javafx.scene.control.*;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.input.*;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.layout.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.time.Instant;
|
||||
|
@ -83,6 +80,7 @@ final class FileListComp extends AnchorPane {
|
|||
// ~
|
||||
|
||||
var table = new TableView<FileSystem.FileEntry>();
|
||||
table.setPlaceholder(new Region());
|
||||
table.getStyleClass().add(Styles.STRIPED);
|
||||
table.getColumns().setAll(filenameCol, sizeCol, mtimeCol);
|
||||
table.getSortOrder().add(filenameCol);
|
||||
|
|
|
@ -14,6 +14,7 @@ import lombok.Getter;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@Getter
|
||||
|
@ -34,6 +35,10 @@ final class FileListModel {
|
|||
|
||||
public FileListModel(OpenFileSystemModel model) {
|
||||
this.model = model;
|
||||
|
||||
model.getFilter().addListener((observable, oldValue, newValue) -> {
|
||||
refreshShown();
|
||||
});
|
||||
}
|
||||
|
||||
public void setAll(List<FileSystem.FileEntry> newFiles) {
|
||||
|
@ -47,11 +52,17 @@ final class FileListModel {
|
|||
}
|
||||
|
||||
private void refreshShown() {
|
||||
List<FileSystem.FileEntry> filtered = model.getFilter().getValue() != null ? all.getValue().stream().filter(entry -> {
|
||||
var name = FileNames.getFileName(entry.getPath()).toLowerCase(Locale.ROOT);
|
||||
var filterString = model.getFilter().getValue().toLowerCase(Locale.ROOT);
|
||||
return name.contains(filterString);
|
||||
}).toList() : all.getValue();
|
||||
|
||||
Comparator<FileSystem.FileEntry> tableComparator = comparatorProperty.getValue();
|
||||
var comparator = tableComparator != null
|
||||
? FILE_TYPE_COMPARATOR.thenComparing(tableComparator)
|
||||
: FILE_TYPE_COMPARATOR;
|
||||
var listCopy = new ArrayList<>(all.getValue());
|
||||
var listCopy = new ArrayList<>(filtered);
|
||||
listCopy.sort(comparator);
|
||||
shown.setValue(listCopy);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import io.xpipe.core.store.ShellStore;
|
|||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class FileSystemHelper {
|
||||
|
@ -108,7 +108,7 @@ public class FileSystemHelper {
|
|||
|
||||
private static void dropFileAcrossFileSystems(FileSystem.FileEntry target, FileSystem.FileEntry source)
|
||||
throws Exception {
|
||||
var flatFiles = new HashMap<FileSystem.FileEntry, String>();
|
||||
var flatFiles = new LinkedHashMap<FileSystem.FileEntry, String>();
|
||||
|
||||
// Prevent dropping directory into itself
|
||||
if (source.getFileSystem().equals(target.getFileSystem())
|
||||
|
|
|
@ -57,12 +57,15 @@ public class OpenFileSystemComp extends SimpleComp {
|
|||
creatingProperty.set(true);
|
||||
});
|
||||
|
||||
var filter = new FileFilterComp(model.getFilter()).createRegion();
|
||||
|
||||
var topBar = new ToolBar();
|
||||
topBar.getItems().setAll(
|
||||
backBtn,
|
||||
forthBtn,
|
||||
new Spacer(10),
|
||||
pathBar,
|
||||
filter,
|
||||
refreshBtn,
|
||||
terminalBtn,
|
||||
addBtn
|
||||
|
|
|
@ -25,6 +25,7 @@ final class OpenFileSystemModel {
|
|||
|
||||
private Property<FileSystemStore> store = new SimpleObjectProperty<>();
|
||||
private FileSystem fileSystem;
|
||||
private final Property<String> filter = new SimpleStringProperty();
|
||||
private final FileListModel fileList;
|
||||
private final ReadOnlyObjectWrapper<String> currentPath = new ReadOnlyObjectWrapper<>();
|
||||
private final FileBrowserNavigationHistory history = new FileBrowserNavigationHistory();
|
||||
|
@ -63,6 +64,7 @@ final class OpenFileSystemModel {
|
|||
return false;
|
||||
}
|
||||
|
||||
filter.setValue(null);
|
||||
currentPath.set(path);
|
||||
history.cd(path);
|
||||
return true;
|
||||
|
|
|
@ -39,7 +39,7 @@ public class AppInstaller {
|
|||
} else {
|
||||
targetFile = FileNames.join(
|
||||
s.getTemporaryDirectory(), localFile.getFileName().toString());
|
||||
try (CommandProcessControl c = s.command(s.getShellDialect().getStreamFileWriteCommand(targetFile))
|
||||
try (CommandProcessControl c = s.getShellDialect().getStreamFileWriteCommand(s, targetFile)
|
||||
.start()) {
|
||||
c.discardOut();
|
||||
c.discardErr();
|
||||
|
|
|
@ -3,17 +3,22 @@ package io.xpipe.core.impl;
|
|||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
import io.xpipe.core.process.ProcessControlProvider;
|
||||
import io.xpipe.core.process.ShellProcessControl;
|
||||
import io.xpipe.core.store.*;
|
||||
import io.xpipe.core.store.FileSystem;
|
||||
import io.xpipe.core.store.FileSystemStore;
|
||||
import io.xpipe.core.store.MachineStore;
|
||||
import io.xpipe.core.util.JacksonizedValue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
@JsonTypeName("local")
|
||||
public class LocalStore extends JacksonizedValue implements FileSystemStore, MachineStore {
|
||||
|
@ -25,7 +30,6 @@ public class LocalStore extends JacksonizedValue implements FileSystemStore, Mac
|
|||
|
||||
@Override
|
||||
public FileSystem createFileSystem() {
|
||||
if (true) return new ConnectionFileSystem(ShellStore.local().create());
|
||||
return new FileSystem() {
|
||||
@Override
|
||||
public Optional<ShellProcessControl> getShell() {
|
||||
|
@ -34,7 +38,7 @@ public class LocalStore extends JacksonizedValue implements FileSystemStore, Mac
|
|||
|
||||
@Override
|
||||
public FileSystem open() throws Exception {
|
||||
return this;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -44,17 +48,17 @@ public class LocalStore extends JacksonizedValue implements FileSystemStore, Mac
|
|||
|
||||
@Override
|
||||
public void delete(String file) throws Exception {
|
||||
|
||||
Files.delete(Path.of(file));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copy(String file, String newFile) throws Exception {
|
||||
|
||||
Files.copy(Path.of(file), Path.of(newFile), StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(String file, String newFile) throws Exception {
|
||||
|
||||
Files.move(Path.of(file), Path.of(newFile), StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -69,6 +73,11 @@ public class LocalStore extends JacksonizedValue implements FileSystemStore, Mac
|
|||
|
||||
@Override
|
||||
public void touch(String file) throws Exception {
|
||||
if (exists(file)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Files.createFile(Path.of(file));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -78,12 +87,27 @@ public class LocalStore extends JacksonizedValue implements FileSystemStore, Mac
|
|||
|
||||
@Override
|
||||
public Stream<FileEntry> listFiles(String file) throws Exception {
|
||||
return null;
|
||||
return Files.list(Path.of(file)).map(path -> {
|
||||
try {
|
||||
var date = Files.getLastModifiedTime(path);
|
||||
var size = Files.isDirectory(path) ? 0 : Files.size(path);
|
||||
return new FileEntry(
|
||||
this,
|
||||
path.toString(),
|
||||
date.toInstant(),
|
||||
Files.isDirectory(path),
|
||||
Files.isHidden(path),
|
||||
Files.isExecutable(path),
|
||||
size);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> listRoots() throws Exception {
|
||||
return null;
|
||||
return StreamSupport.stream(FileSystems.getDefault().getRootDirectories().spliterator(), false).map(path -> path.toString()).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -99,9 +123,7 @@ public class LocalStore extends JacksonizedValue implements FileSystemStore, Mac
|
|||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
|
||||
}
|
||||
public void close() throws IOException {}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ public interface ShellDialect {
|
|||
|
||||
String getFileMoveCommand(String oldFile, String newFile);
|
||||
|
||||
String getStreamFileWriteCommand(String file);
|
||||
CommandProcessControl getStreamFileWriteCommand(ShellProcessControl processControl, String file);
|
||||
|
||||
String getTextFileWriteCommand(String content, String file);
|
||||
|
||||
|
|
|
@ -54,8 +54,8 @@ public class ConnectionFileSystem implements FileSystem {
|
|||
|
||||
@Override
|
||||
public OutputStream openOutput(String file) throws Exception {
|
||||
return shellProcessControl.command(proc -> proc.getShellDialect()
|
||||
.getStreamFileWriteCommand(proc.getOsType().normalizeFileName(file)))
|
||||
return shellProcessControl.getShellDialect()
|
||||
.getStreamFileWriteCommand(shellProcessControl, shellProcessControl.getOsType().normalizeFileName(file))
|
||||
.startExternalStdin();
|
||||
}
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ public interface FileSystem extends Closeable, AutoCloseable {
|
|||
}
|
||||
|
||||
try {
|
||||
return listFilesRecursively(fileEntry.getPath());
|
||||
return Stream.concat(Stream.of(fileEntry), listFilesRecursively(fileEntry.getPath()));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue