File browser transfer adjustments

This commit is contained in:
crschnick 2023-07-17 01:03:12 +00:00
parent 6909019231
commit 324a48f157
9 changed files with 128 additions and 39 deletions

View file

@ -68,8 +68,9 @@ public class BrowserComp extends SimpleComp {
return true;
}
// Also show on local
if (model.getSelected().getValue() != null) {
return model.getSelected().getValue().isLocal();
// return model.getSelected().getValue().isLocal();
}
return false;

View file

@ -35,7 +35,10 @@ public class BrowserFileListCompEntry {
public void onMouseClick(MouseEvent t) {
if (item == null) {
model.getSelection().clear();
// Only clear for normal clicks
if (t.isStillSincePress()) {
model.getSelection().clear();
}
t.consume();
return;
}
@ -85,7 +88,8 @@ public class BrowserFileListCompEntry {
return true;
}
if (BrowserClipboard.currentDragClipboard == null) {
BrowserClipboard.Instance cb = BrowserClipboard.currentDragClipboard;
if (cb == null) {
return false;
}
@ -94,7 +98,7 @@ public class BrowserFileListCompEntry {
}
// Prevent drag and drops of files into the current directory
if (BrowserClipboard.currentDragClipboard
if (cb.getBaseDirectory() != null && cb
.getBaseDirectory()
.getPath()
.equals(model.getFileSystemModel().getCurrentDirectory().getPath())
@ -103,7 +107,7 @@ public class BrowserFileListCompEntry {
}
// Prevent dropping items onto themselves
if (item != null && BrowserClipboard.currentDragClipboard.getEntries().contains(item.getRawFileEntry())) {
if (item != null && cb.getEntries().contains(item.getRawFileEntry())) {
return false;
}

View file

@ -66,7 +66,7 @@ public class BrowserModel {
private final ObservableList<OpenFileSystemModel> openFileSystems = FXCollections.observableArrayList();
private final Property<OpenFileSystemModel> selected = new SimpleObjectProperty<>();
private final BrowserTransferModel localTransfersStage = new BrowserTransferModel();
private final BrowserTransferModel localTransfersStage = new BrowserTransferModel(this);
private final ObservableList<BrowserEntry> selection = FXCollections.observableArrayList();
public void restoreState(BrowserSavedState state) {

View file

@ -6,22 +6,31 @@ import io.xpipe.app.core.AppStyle;
import io.xpipe.app.core.AppWindowHelper;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.fxcomps.impl.SvgCacheComp;
import io.xpipe.app.fxcomps.util.PlatformThread;
import io.xpipe.core.impl.FileNames;
import io.xpipe.core.store.FileSystem;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.control.Label;
import javafx.scene.control.OverrunStyle;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Value;
import java.util.function.Function;
@Value
@EqualsAndHashCode(callSuper = true)
@AllArgsConstructor
public class BrowserSelectionListComp extends SimpleComp {
public static Image snapshot(ObservableList<FileSystem.FileEntry> list) {
@ -36,17 +45,25 @@ public class BrowserSelectionListComp extends SimpleComp {
}
ObservableList<FileSystem.FileEntry> list;
Function<FileSystem.FileEntry, ObservableValue<String>> nameTransformation;
public BrowserSelectionListComp(ObservableList<FileSystem.FileEntry> list) {
this(list, entry -> new SimpleStringProperty(FileNames.getFileName(entry.getPath())));
}
@Override
protected Region createSimple() {
var c = new ListBoxViewComp<>(list, list, entry -> {
return Comp.of(() -> {
var icon = new ImageView(FileIconManager.getSvgCache()
.getCached(FileIconManager.getFileIcon(entry, false))
.orElse(null));
icon.setFitWidth(20);
icon.setFitHeight(20);
var l = new Label(FileNames.getFileName(entry.getPath()), icon);
var wv = new SvgCacheComp(
new SimpleDoubleProperty(20),
new SimpleDoubleProperty(20),
new SimpleStringProperty(FileIconManager.getFileIcon(entry, false)),
FileIconManager.getSvgCache())
.createRegion();
var l = new Label(null, wv);
l.setTextOverrun(OverrunStyle.CENTER_ELLIPSIS);
l.textProperty().bind(PlatformThread.sync(nameTransformation.apply(entry)));
return l;
});
})

View file

@ -5,15 +5,15 @@ import io.xpipe.app.core.AppI18n;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.fxcomps.augment.DragPseudoClassAugment;
import io.xpipe.app.fxcomps.impl.IconButtonComp;
import io.xpipe.app.fxcomps.impl.LabelComp;
import io.xpipe.app.fxcomps.impl.StackComp;
import io.xpipe.app.fxcomps.impl.VerticalComp;
import io.xpipe.app.fxcomps.impl.*;
import io.xpipe.app.fxcomps.util.BindingsHelper;
import io.xpipe.app.fxcomps.util.PlatformThread;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.core.impl.FileNames;
import javafx.beans.binding.Bindings;
import javafx.collections.FXCollections;
import javafx.geometry.Insets;
import javafx.scene.image.Image;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
@ -41,27 +41,45 @@ public class BrowserTransferComp extends SimpleComp {
new StackComp(List.of(background)).grow(true, true).styleClass("download-background");
var binding = BindingsHelper.mappedContentBinding(stage.getItems(), item -> item.getFileEntry());
var list = new BrowserSelectionListComp(binding)
var list = new BrowserSelectionListComp(binding, entry -> Bindings.createStringBinding(() -> {
var sourceItem = stage.getItems().stream().filter(item -> item.getFileEntry() == entry).findAny();
if (sourceItem.isEmpty()) {
return "?";
}
var name = sourceItem.get().getFinishedDownload().get() ? "Local" : DataStorage.get().getStoreDisplayName(entry.getFileSystem().getStore()).orElse("?");
return FileNames.getFileName(entry.getPath()) + " (" + name + ")";
}, stage.getAllDownloaded()))
.apply(struc -> struc.get().setMinHeight(150))
.grow(false, true);
var dragNotice = new LabelComp(AppI18n.observable("dragFiles"))
var dragNotice = new LabelComp(stage.getAllDownloaded().flatMap(aBoolean -> aBoolean ? AppI18n.observable("dragLocalFiles") : AppI18n.observable("dragFiles")))
.apply(struc -> struc.get().setGraphic(new FontIcon("mdi2e-export")))
.hide(BindingsHelper.persist(Bindings.isEmpty(stage.getItems())))
.hide(PlatformThread.sync(
BindingsHelper.persist(Bindings.isEmpty(stage.getItems()))))
.grow(true, false)
.apply(struc -> struc.get().setPadding(new Insets(8)));
var clearButton = new IconButtonComp("mdi2d-delete", () -> {
stage.getItems().clear();
var downloadButton = new IconButtonComp("mdi2d-download", () -> {
stage.download();
})
.hide(BindingsHelper.persist(Bindings.isEmpty(stage.getItems())))
.disable(PlatformThread.sync(stage.getAllDownloaded()))
.apply(new FancyTooltipAugment<>("downloadStageDescription"));
var clearButton = new IconButtonComp("mdi2c-close", () -> {
stage.clear();
})
.hide(BindingsHelper.persist(Bindings.isEmpty(stage.getItems())));
var clearPane = Comp.derive(clearButton, button -> {
var p = new AnchorPane(button);
AnchorPane.setRightAnchor(button, 10.0);
AnchorPane.setTopAnchor(button, 10.0);
return p;
});
var clearPane = Comp.derive(
new HorizontalComp(List.of(downloadButton, clearButton))
.apply(struc -> struc.get().setSpacing(10)),
button -> {
var p = new AnchorPane(button);
AnchorPane.setRightAnchor(button, 20.0);
AnchorPane.setTopAnchor(button, 20.0);
p.setPickOnBounds(false);
return p;
});
var listBox = new VerticalComp(List.of(list, dragNotice));
var listBox = new VerticalComp(List.of(list, dragNotice)).padding(new Insets(10, 10, 5, 10));
var stack = new LoadingOverlayComp(
new StackComp(List.of(backgroundStack, listBox, clearPane))
.apply(DragPseudoClassAugment.create())
@ -87,6 +105,21 @@ public class BrowserTransferComp extends SimpleComp {
return;
}
// Drag within browser
if (!stage.getAllDownloaded().get()) {
var selected = stage.getItems().stream().map(item -> item.getFileEntry()).toList();
Dragboard db = struc.get().startDragAndDrop(TransferMode.COPY);
db.setContent(BrowserClipboard.startDrag(null, selected));
Image image = BrowserSelectionListComp.snapshot(FXCollections.observableList(selected));
db.setDragView(image, -20, 15);
event.setDragDetect(true);
event.consume();
return;
}
// Drag outside browser
var files = stage.getItems().stream()
.map(item -> {
try {

View file

@ -11,7 +11,9 @@ import javafx.collections.ObservableList;
import lombok.Value;
import org.apache.commons.io.FileUtils;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@ -37,8 +39,19 @@ public class BrowserTransferModel {
BooleanProperty finishedDownload = new SimpleBooleanProperty();
}
BrowserModel browserModel;
ObservableList<Item> items = FXCollections.observableArrayList();
BooleanProperty downloading = new SimpleBooleanProperty();
BooleanProperty allDownloaded = new SimpleBooleanProperty();
public void clear() {
try {
FileUtils.deleteDirectory(TEMP.toFile());
} catch (IOException e) {
ErrorEvent.fromThrowable(e).handle();
}
items.clear();
}
public void drop(List<FileSystem.FileEntry> entries) {
entries.forEach(entry -> {
@ -50,18 +63,34 @@ public class BrowserTransferModel {
Path file = TEMP.resolve(name);
var item = new Item(name, entry, file);
items.add(item);
executor.submit(() -> {
allDownloaded.set(false);
});
}
public void download() {
executor.submit(() -> {
try {
FileUtils.forceMkdir(TEMP.toFile());
} catch (IOException e) {
ErrorEvent.fromThrowable(e).handle();
return;
}
for (Item item : new ArrayList<>(items)) {
try {
FileUtils.forceMkdir(TEMP.toFile());
try (var b = new BusyProperty(downloading)) {
FileSystemHelper.dropFilesInto(FileSystemHelper.getLocal(TEMP), List.of(entry), false);
FileSystemHelper.dropFilesInto(
FileSystemHelper.getLocal(TEMP),
List.of(item.getFileEntry()),
true);
}
item.finishedDownload.set(true);
} catch (Throwable t) {
ErrorEvent.fromThrowable(t).handle();
items.remove(item);
}
});
}
allDownloaded.set(true);
});
}
}

View file

@ -32,13 +32,13 @@ public class FileStoreChoiceComp extends SimpleComp {
@Override
protected Region createSimple() {
var fileProperty = new SimpleStringProperty(
var filePathProperty = new SimpleStringProperty(
selected.getValue() != null ? selected.getValue().getPath() : null);
fileProperty.addListener((observable, oldValue, newValue) -> {
filePathProperty.addListener((observable, oldValue, newValue) -> {
setSelected(selected.getValue() != null ? selected.getValue().getFileSystem() : null, newValue);
});
selected.addListener((observable, oldValue, newValue) -> {
fileProperty.setValue(newValue != null ? newValue.getPath() : null);
filePathProperty.setValue(newValue != null ? newValue.getPath() : null);
});
var fileSystemChoiceComp =
@ -47,7 +47,7 @@ public class FileStoreChoiceComp extends SimpleComp {
fileSystemChoiceComp.hide(new SimpleBooleanProperty(true));
}
var fileNameComp = new TextFieldComp(fileProperty)
var fileNameComp = new TextFieldComp(filePathProperty)
.apply(struc -> HBox.setHgrow(struc.get(), Priority.ALWAYS))
.styleClass(onlyLocal ? Styles.LEFT_PILL : Styles.CENTER_PILL)
.grow(false, true);

View file

@ -3,6 +3,7 @@ package io.xpipe.app.fxcomps.impl;
import io.xpipe.app.core.AppImages;
import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.fxcomps.util.PlatformThread;
import io.xpipe.app.fxcomps.util.SimpleChangeListener;
import javafx.animation.AnimationTimer;
import javafx.application.Platform;
import javafx.beans.property.SimpleObjectProperty;
@ -50,7 +51,7 @@ public class SvgCacheComp extends SimpleComp {
var back = SvgView.create(webViewContent).createWebview();
back.prefWidthProperty().bind(width);
back.prefHeightProperty().bind(height);
svgFile.addListener((observable, oldValue, newValue) -> {
SimpleChangeListener.apply(svgFile, newValue -> {
if (newValue == null) {
back.setVisible(false);
front.setVisible(false);
@ -122,6 +123,8 @@ public class SvgCacheComp extends SimpleComp {
// active.set(timer);
});
});
svgFile.addListener((observable, oldValue, newValue) -> {
});
var stack = new StackPane(back, front);
stack.prefWidthProperty().bind(width);

View file

@ -11,6 +11,7 @@ lockCreationAlertTitle=Create Lock
lockCreationAlertHeader=Set your new lock password
finish=Finish
error=Error
downloadStageDescription=Downloads files to your local machine, so you can drag and drop them into your native desktop environment.
ok=Ok
search=Search
newFile=New file
@ -30,7 +31,8 @@ deleteAlertHeader=Do you want to delete the ($COUNT$) selected elements?
selectedElements=Selected elements:
mustNotBeEmpty=$NAME$ must not be empty
download=Drop to download
dragFiles=Drag files from here
dragFiles=Drag files within browser
dragLocalFiles=Drag local files from here
null=$VALUE$ must be not null
roots=Roots
recent=Recent