From fdbfcb6ddc6d092830aa5c5086fe2e5e608bce1e Mon Sep 17 00:00:00 2001 From: crschnick Date: Wed, 10 Jul 2024 04:20:55 +0000 Subject: [PATCH] File browser improvements --- .../app/browser/BrowserStatusBarComp.java | 2 +- .../app/browser/BrowserTransferComp.java | 22 +++++----- .../app/browser/BrowserTransferModel.java | 44 ++++++++++++++----- .../xpipe/app/browser/BrowserWelcomeComp.java | 6 ++- .../session/BrowserAbstractSessionModel.java | 1 + .../browser/session/BrowserSessionModel.java | 16 ++++--- .../session/BrowserSessionTabsComp.java | 6 +-- .../io/xpipe/app/resources/style/browser.css | 6 ++- 8 files changed, 64 insertions(+), 39 deletions(-) diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserStatusBarComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserStatusBarComp.java index f784fe6f3..b350ea074 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserStatusBarComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserStatusBarComp.java @@ -32,9 +32,9 @@ public class BrowserStatusBarComp extends SimpleComp { @Override protected Region createSimple() { var bar = new HorizontalComp(List.of( + createProgressEstimateStatus(), createProgressNameStatus(), createProgressStatus(), - createProgressEstimateStatus(), Comp.hspacer(), createClipboardStatus(), createSelectionStatus() diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserTransferComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserTransferComp.java index 0ea541c1e..2d5f26135 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserTransferComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserTransferComp.java @@ -8,7 +8,6 @@ import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.augment.DragOverPseudoClassAugment; import io.xpipe.app.fxcomps.impl.*; import io.xpipe.app.fxcomps.util.DerivedObservableList; -import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.util.ThreadHelper; import javafx.beans.binding.Bindings; import javafx.beans.property.SimpleStringProperty; @@ -38,22 +37,20 @@ public class BrowserTransferComp extends SimpleComp { @Override protected Region createSimple() { - var syncItems = PlatformThread.sync(model.getItems()); - var background = new LabelComp(AppI18n.observable("transferDescription")) .apply(struc -> struc.get().setGraphic(new FontIcon("mdi2d-download-outline"))) .apply(struc -> struc.get().setWrapText(true)) - .visible(Bindings.isEmpty(syncItems)); + .visible(model.getEmpty()); var backgroundStack = new StackComp(List.of(background)).grow(true, true).styleClass("download-background"); - var binding = new DerivedObservableList<>(syncItems, true) + var binding = new DerivedObservableList<>(model.getItems(), true) .mapped(item -> item.getBrowserEntry()) .getList(); var list = new BrowserSelectionListComp( binding, entry -> { - var sourceItem = syncItems.stream() + var sourceItem = model.getCurrentItems().stream() .filter(item -> item.getBrowserEntry() == entry) .findAny(); if (sourceItem.isEmpty()) { @@ -61,7 +58,7 @@ public class BrowserTransferComp extends SimpleComp { } return Bindings.createStringBinding(() -> { var p = sourceItem.get().getProgress().getValue(); - var progressSuffix = sourceItem.get().downloadFinished().get() ? "" : " " + (p.getTransferred() * 100 / p.getTotal()) + "%"; + var progressSuffix = p == null || sourceItem.get().downloadFinished().get() ? "" : " " + (p.getTransferred() * 100 / p.getTotal()) + "%"; return entry.getFileName() + progressSuffix; }, sourceItem.get().getProgress()); }) @@ -70,14 +67,14 @@ public class BrowserTransferComp extends SimpleComp { .apply(struc -> struc.get().setGraphic(new FontIcon("mdi2h-hand-left"))) .apply(struc -> AppFont.medium(struc.get())) .apply(struc -> struc.get().setWrapText(true)) - .hide(Bindings.isEmpty(syncItems)); + .hide(model.getEmpty()); var clearButton = new IconButtonComp("mdi2c-close", () -> { ThreadHelper.runAsync(() -> { model.clear(true); }); }) - .hide(Bindings.isEmpty(syncItems)) + .hide(model.getEmpty()) .tooltipKey("clearTransferDescription"); var downloadButton = new IconButtonComp("mdi2f-folder-move-outline", () -> { @@ -85,7 +82,7 @@ public class BrowserTransferComp extends SimpleComp { model.transferToDownloads(); }); }) - .hide(Bindings.isEmpty(syncItems)) + .hide(model.getEmpty()) .tooltipKey("downloadStageDescription"); var bottom = @@ -127,13 +124,14 @@ public class BrowserTransferComp extends SimpleComp { } }); struc.get().setOnDragDetected(event -> { - var selected = syncItems.stream() + var items = model.getCurrentItems(); + var selected = items.stream() .map(item -> item.getBrowserEntry()) .toList(); Dragboard db = struc.get().startDragAndDrop(TransferMode.COPY); var cc = new ClipboardContent(); - var files = syncItems.stream() + var files = items.stream() .filter(item -> item.downloadFinished().get()) .map(item -> { try { diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserTransferModel.java b/app/src/main/java/io/xpipe/app/browser/BrowserTransferModel.java index b15e38672..817aa1050 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserTransferModel.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserTransferModel.java @@ -23,6 +23,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; +import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -33,6 +34,7 @@ public class BrowserTransferModel { BrowserSessionModel browserSessionModel; ObservableList items = FXCollections.observableArrayList(); + ObservableBooleanValue empty = Bindings.createBooleanBinding(() -> items.isEmpty(), items); public BrowserTransferModel(BrowserSessionModel browserSessionModel) { this.browserSessionModel = browserSessionModel; @@ -51,27 +53,41 @@ public class BrowserTransferModel { thread.start(); } - private void cleanDirectory() { + public List getCurrentItems() { + synchronized (items) { + return new ArrayList<>(items); + } + } + + private void cleanItem(Item item) { if (!Files.isDirectory(TEMP)) { return; } - try (var ls = Files.list(TEMP)) { - var list = ls.toList(); - for (Path path : list) { - FileUtils.forceDelete(path.toFile()); - } + if (!Files.exists(item.getLocalFile())) { + return; + } + + try { + FileUtils.forceDelete(item.getLocalFile().toFile()); } catch (IOException e) { ErrorEvent.fromThrowable(e).handle(); } } public void clear(boolean delete) { + List toClear; synchronized (items) { - items.clear(); + toClear = items.stream().filter(item -> item.downloadFinished().get()).toList(); + if (toClear.isEmpty()) { + return; + } + items.removeAll(toClear); } if (delete) { - cleanDirectory(); + for (Item item : toClear) { + cleanItem(item); + } } } @@ -127,16 +143,20 @@ public class BrowserTransferModel { } public void transferToDownloads() throws Exception { - if (items.isEmpty()) { - return; + List toMove; + synchronized (items) { + toMove = items.stream().filter(item -> item.downloadFinished().get()).toList(); + if (toMove.isEmpty()) { + return; + } + items.removeAll(toMove); } - var files = items.stream().map(item -> item.getLocalFile()).toList(); + var files = toMove.stream().map(item -> item.getLocalFile()).toList(); var downloads = DesktopHelper.getDownloadsDirectory(); for (Path file : files) { Files.move(file, downloads.resolve(file.getFileName()), StandardCopyOption.REPLACE_EXISTING); } - clear(true); DesktopHelper.browseFileInDirectory(downloads.resolve(files.getFirst().getFileName())); } diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserWelcomeComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserWelcomeComp.java index 8350041df..75806e7cd 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserWelcomeComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserWelcomeComp.java @@ -3,6 +3,7 @@ package io.xpipe.app.browser; import io.xpipe.app.browser.session.BrowserSessionModel; import io.xpipe.app.comp.base.ButtonComp; import io.xpipe.app.comp.base.ListBoxViewComp; +import io.xpipe.app.comp.base.LoadingOverlayComp; import io.xpipe.app.comp.base.TileButtonComp; import io.xpipe.app.core.AppFont; import io.xpipe.app.core.AppI18n; @@ -55,7 +56,9 @@ public class BrowserWelcomeComp extends SimpleComp { var img = new PrettySvgComp(new SimpleStringProperty("Hips.svg"), 50, 75) .padding(new Insets(5, 0, 0, 0)) .createRegion(); - var hbox = new HBox(img, vbox); + + var loading = LoadingOverlayComp.noProgress(Comp.empty(),model.getBusy()).createRegion(); + var hbox = new HBox(img, vbox, new Spacer(), loading); hbox.setAlignment(Pos.CENTER_LEFT); hbox.setSpacing(15); @@ -139,7 +142,6 @@ public class BrowserWelcomeComp extends SimpleComp { .hide(empty) .accessibleTextKey("restoreAllSessions"); layout.getChildren().add(tile.createRegion()); - return layout; } diff --git a/app/src/main/java/io/xpipe/app/browser/session/BrowserAbstractSessionModel.java b/app/src/main/java/io/xpipe/app/browser/session/BrowserAbstractSessionModel.java index 289d4cf46..980f13871 100644 --- a/app/src/main/java/io/xpipe/app/browser/session/BrowserAbstractSessionModel.java +++ b/app/src/main/java/io/xpipe/app/browser/session/BrowserAbstractSessionModel.java @@ -17,6 +17,7 @@ public class BrowserAbstractSessionModel> { protected final ObservableList sessionEntries = FXCollections.observableArrayList(); protected final Property selectedEntry = new SimpleObjectProperty<>(); + protected final BooleanProperty busy = new SimpleBooleanProperty(); public void closeAsync(BrowserSessionTab e) { ThreadHelper.runAsync(() -> { diff --git a/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionModel.java b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionModel.java index 59fe6101f..ae7c65fb4 100644 --- a/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionModel.java +++ b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionModel.java @@ -94,13 +94,15 @@ public class BrowserSessionModel extends BrowserAbstractSessionModel * { -fx-padding: 0.6em 0 0.6em 0; }