diff --git a/app/src/main/java/io/xpipe/app/browser/FileBrowserClipboard.java b/app/src/main/java/io/xpipe/app/browser/FileBrowserClipboard.java index f02fb53a0..9b0f4ec92 100644 --- a/app/src/main/java/io/xpipe/app/browser/FileBrowserClipboard.java +++ b/app/src/main/java/io/xpipe/app/browser/FileBrowserClipboard.java @@ -1,14 +1,14 @@ package io.xpipe.app.browser; import io.xpipe.core.store.FileSystem; -import io.xpipe.core.util.XPipeTempDirectory; import javafx.scene.input.ClipboardContent; import javafx.scene.input.Dragboard; import lombok.SneakyThrows; import lombok.Value; -import java.nio.file.Files; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; public class FileBrowserClipboard { @@ -18,7 +18,6 @@ public static class Instance { List entries; } - public static Map> CLIPBOARD = new HashMap<>(); public static Instance currentCopyClipboard; public static Instance currentDragClipboard; @@ -26,17 +25,15 @@ public static class Instance { public static ClipboardContent startDrag(List selected) { var content = new ClipboardContent(); var idea = UUID.randomUUID(); - var file = XPipeTempDirectory.getLocal().resolve(idea.toString()); - Files.createFile(file); currentDragClipboard = new Instance(idea, selected); - content.putFiles(List.of(file.toFile())); + content.putString(idea.toString()); return content; } @SneakyThrows public static void startCopy(List selected) { - var idea = UUID.randomUUID(); - currentCopyClipboard = new Instance(idea, new ArrayList<>(selected)); + var id = UUID.randomUUID(); + currentCopyClipboard = new Instance(id, new ArrayList<>(selected)); } public static Instance retrieveCopy() { @@ -45,15 +42,19 @@ public static Instance retrieveCopy() { } public static Instance retrieveDrag(Dragboard dragboard) { - if (dragboard.getFiles().size() != 1) { + if (dragboard.getString() == null) { return null; } - var idea = UUID.fromString(dragboard.getFiles().get(0).toPath().getFileName().toString()); - if (idea.equals(currentDragClipboard.uuid)) { - var current = currentDragClipboard; - currentDragClipboard = null; - return current; + try { + var idea = UUID.fromString(dragboard.getString()); + if (idea.equals(currentDragClipboard.uuid)) { + var current = currentDragClipboard; + currentDragClipboard = null; + return current; + } + } catch (Exception ex) { + return null; } return null; diff --git a/app/src/main/java/io/xpipe/app/browser/FileContextMenu.java b/app/src/main/java/io/xpipe/app/browser/FileContextMenu.java index d10258ab0..964142e40 100644 --- a/app/src/main/java/io/xpipe/app/browser/FileContextMenu.java +++ b/app/src/main/java/io/xpipe/app/browser/FileContextMenu.java @@ -4,7 +4,11 @@ import io.xpipe.app.comp.source.GuiDsCreatorMultiStep; import io.xpipe.app.ext.DataSourceProvider; -import io.xpipe.app.util.*; +import io.xpipe.app.util.FileOpener; +import io.xpipe.app.util.ScriptHelper; +import io.xpipe.app.util.TerminalHelper; +import io.xpipe.app.util.ThreadHelper; +import io.xpipe.core.impl.FileNames; import io.xpipe.core.impl.FileStore; import io.xpipe.core.process.OsType; import io.xpipe.core.process.ShellControl; @@ -13,10 +17,11 @@ import javafx.scene.control.ContextMenu; import javafx.scene.control.MenuItem; import javafx.scene.control.SeparatorMenuItem; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyCodeCombination; import org.apache.commons.io.FilenameUtils; +import java.awt.*; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.StringSelection; import java.util.List; final class FileContextMenu extends ContextMenu { @@ -73,8 +78,7 @@ private void createMenu() { var execute = new MenuItem("Run in terminal"); execute.setOnAction(event -> { ThreadHelper.runFailableAsync(() -> { - ShellControl pc = - model.getFileSystem().getShell().orElseThrow(); + ShellControl pc = model.getFileSystem().getShell().orElseThrow(); pc.executeBooleanSimpleCommand(pc.getShellDialect().getMakeExecutableCommand(entry.getPath())); var cmd = pc.command("\"" + entry.getPath() + "\"").prepareTerminalOpen(); TerminalHelper.open(FilenameUtils.getBaseName(entry.getPath()), cmd); @@ -86,8 +90,7 @@ private void createMenu() { var executeInBackground = new MenuItem("Run in background"); executeInBackground.setOnAction(event -> { ThreadHelper.runFailableAsync(() -> { - ShellControl pc = - model.getFileSystem().getShell().orElseThrow(); + ShellControl pc = model.getFileSystem().getShell().orElseThrow(); pc.executeBooleanSimpleCommand(pc.getShellDialect().getMakeExecutableCommand(entry.getPath())); var cmd = ScriptHelper.createDetachCommand(pc, "\"" + entry.getPath() + "\""); pc.executeBooleanSimpleCommand(cmd); @@ -112,30 +115,48 @@ private void createMenu() { GuiDsCreatorMultiStep.showForStore(DataSourceProvider.Category.STREAM, store, null); event.consume(); }); - getItems().add(pipe); + // getItems().add(pipe); var edit = new MenuItem("Edit"); edit.setOnAction(event -> { - FileOpener.openInTextEditor(entry); + ThreadHelper.runAsync(() -> FileOpener.openInTextEditor(entry)); event.consume(); }); getItems().add(edit); } - var cut = new MenuItem("Delete"); - cut.setOnAction(event -> { + getItems().add(new SeparatorMenuItem()); + + var copyName = new MenuItem("Copy name"); + copyName.setOnAction(event -> { + var selection = new StringSelection(FileNames.getFileName(entry.getPath())); + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + clipboard.setContents(selection, selection); + event.consume(); + }); + getItems().add(copyName); + + var copyPath = new MenuItem("Copy full path"); + copyPath.setOnAction(event -> { + var selection = new StringSelection(entry.getPath()); + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + clipboard.setContents(selection, selection); + event.consume(); + }); + getItems().add(copyPath); + + var delete = new MenuItem("Delete"); + delete.setOnAction(event -> { event.consume(); model.deleteAsync(entry.getPath()); }); - cut.setAccelerator(new KeyCodeCombination(KeyCode.DELETE)); var rename = new MenuItem("Rename"); rename.setOnAction(event -> { event.consume(); editing.setValue(entry.getPath()); }); - rename.setAccelerator(new KeyCodeCombination(KeyCode.F2)); - getItems().addAll(new SeparatorMenuItem(), cut, rename); + getItems().addAll(new SeparatorMenuItem(), rename, delete); } } 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 37db1b28d..e8390b0cf 100644 --- a/app/src/main/java/io/xpipe/app/browser/FileSystemHelper.java +++ b/app/src/main/java/io/xpipe/app/browser/FileSystemHelper.java @@ -23,6 +23,11 @@ public static String normalizeDirectoryPath(OpenFileSystemModel model, String pa return null; } + // Handle special case when file system creation has failed + if (model.getFileSystem() == null) { + return path; + } + var shell = model.getFileSystem().getShell(); if (shell.isEmpty()) { return path; 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 0dd5e8f42..b848462b9 100644 --- a/app/src/main/java/io/xpipe/app/browser/OpenFileSystemModel.java +++ b/app/src/main/java/io/xpipe/app/browser/OpenFileSystemModel.java @@ -13,6 +13,7 @@ import io.xpipe.core.store.ShellStore; import javafx.beans.property.*; import lombok.Getter; +import lombok.SneakyThrows; import java.io.IOException; import java.nio.file.Path; @@ -40,13 +41,14 @@ public OpenFileSystemModel(FileBrowserModel browserModel) { fileList = new FileListModel(this); } + @SneakyThrows public void refresh() { BusyProperty.execute(busy, () -> { cdSync(currentPath.get()); }); } - private void refreshInternal() { + private void refreshInternal() throws Exception { cdSync(currentPath.get()); } @@ -68,7 +70,13 @@ public Optional cd(String path) { return Optional.empty(); } - private void cdSync(String path) { + private void cdSync(String path) throws Exception { + if (fileSystem == null) { + var fs = store.getValue().createFileSystem(); + fs.open(); + this.fileSystem = fs; + } + path = FileSystemHelper.normalizeDirectoryPath(this, path); navigateToSync(path); @@ -99,6 +107,10 @@ private boolean navigateToSync(String dir) { public void dropLocalFilesIntoAsync(FileSystem.FileEntry entry, List files) { ThreadHelper.runFailableAsync(() -> { BusyProperty.execute(busy, () -> { + if (fileSystem == null) { + return; + } + FileSystemHelper.dropLocalFilesInto(entry, files); refreshInternal(); }); @@ -109,6 +121,10 @@ public void dropFilesIntoAsync( FileSystem.FileEntry target, List files, boolean explicitCopy) { ThreadHelper.runFailableAsync(() -> { BusyProperty.execute(busy, () -> { + if (fileSystem == null) { + return; + } + FileSystemHelper.dropFilesInto(target, files, explicitCopy); refreshInternal(); }); @@ -122,6 +138,10 @@ public void createDirectoryAsync(String path) { ThreadHelper.runFailableAsync(() -> { BusyProperty.execute(busy, () -> { + if (fileSystem == null) { + return; + } + fileSystem.mkdirs(path); refreshInternal(); }); @@ -135,6 +155,10 @@ public void createFileAsync(String path) { ThreadHelper.runFailableAsync(() -> { BusyProperty.execute(busy, () -> { + if (fileSystem == null) { + return; + } + fileSystem.touch(path); refreshInternal(); }); @@ -144,6 +168,10 @@ public void createFileAsync(String path) { public void deleteAsync(String path) { ThreadHelper.runFailableAsync(() -> { BusyProperty.execute(busy, () -> { + if (fileSystem == null) { + return; + } + fileSystem.delete(path); refreshInternal(); }); @@ -164,12 +192,6 @@ void closeSync() { store = null; } - public void switchFileSystem(FileSystemStore fileSystem) throws Exception { - BusyProperty.execute(busy, () -> { - switchSync(fileSystem); - }); - } - private void switchSync(FileSystemStore fileSystem) throws Exception { closeSync(); this.store.setValue(fileSystem); @@ -198,6 +220,10 @@ public void switchAsync(FileSystemStore fileSystem) { public void openTerminalAsync(String directory) { ThreadHelper.runFailableAsync(() -> { + if (fileSystem == null) { + return; + } + BusyProperty.execute(busy, () -> { if (store.getValue() instanceof ShellStore s) { var connection = ((ConnectionFileSystem) fileSystem).getShellControl(); diff --git a/app/src/main/java/io/xpipe/app/comp/about/AboutTabComp.java b/app/src/main/java/io/xpipe/app/comp/about/AboutTabComp.java index 8b7cb8244..66c6c2fe7 100644 --- a/app/src/main/java/io/xpipe/app/comp/about/AboutTabComp.java +++ b/app/src/main/java/io/xpipe/app/comp/about/AboutTabComp.java @@ -8,7 +8,7 @@ import io.xpipe.app.util.Hyperlinks; import javafx.scene.control.Hyperlink; import javafx.scene.control.Label; -import javafx.scene.layout.BorderPane; +import javafx.scene.control.SplitPane; import javafx.scene.layout.Region; import javafx.scene.layout.VBox; import org.kordamp.ikonli.javafx.FontIcon; @@ -62,10 +62,10 @@ public CompStructure createBase() { .styleClass("information"); return Comp.derive(box, boxS -> { - var bp = new BorderPane(); - bp.setLeft(boxS); + var bp = new SplitPane(); + bp.getItems().add(boxS); var deps = createThirdPartyDeps(); - bp.setRight(createThirdPartyDeps()); + bp.getItems().add(createThirdPartyDeps()); deps.prefWidthProperty().bind(bp.widthProperty().divide(2)); boxS.prefWidthProperty().bind(bp.widthProperty().divide(2)); bp.getStyleClass().add("about-tab"); diff --git a/app/src/main/java/io/xpipe/app/comp/about/ThirdPartyDependencyListComp.java b/app/src/main/java/io/xpipe/app/comp/about/ThirdPartyDependencyListComp.java index 6ec225c83..8ddc8ef69 100644 --- a/app/src/main/java/io/xpipe/app/comp/about/ThirdPartyDependencyListComp.java +++ b/app/src/main/java/io/xpipe/app/comp/about/ThirdPartyDependencyListComp.java @@ -28,7 +28,7 @@ private TitledPane createPane(ThirdPartyDependency t) { var sp = new StackPane(link, licenseName); StackPane.setAlignment(licenseName, Pos.CENTER_RIGHT); StackPane.setAlignment(link, Pos.CENTER_LEFT); - sp.prefWidthProperty().bind(tp.widthProperty().subtract(40)); + sp.prefWidthProperty().bind(tp.widthProperty().subtract(65)); tp.setGraphic(sp); var text = new TextArea(); @@ -36,7 +36,7 @@ private TitledPane createPane(ThirdPartyDependency t) { text.setText(t.licenseText()); text.setWrapText(true); text.setPrefHeight(300); - text.prefWidthProperty().bind(tp.widthProperty()); + text.maxWidthProperty().bind(tp.widthProperty()); AppFont.setSize(text, -4); tp.setContent(text); AppFont.verySmall(tp); diff --git a/app/src/main/java/io/xpipe/app/comp/base/IntegratedTextAreaComp.java b/app/src/main/java/io/xpipe/app/comp/base/IntegratedTextAreaComp.java index 85e35732a..adc1e4eff 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/IntegratedTextAreaComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/IntegratedTextAreaComp.java @@ -47,8 +47,9 @@ protected Region createSimple() { } private Region createOpenButton(Region container) { + var name = identifier + (fileType != null ? "." + fileType : ""); var button = new IconButtonComp("mdal-edit", () -> FileOpener - .openString(identifier, fileType, this, value.getValue(), (s) -> { + .openString(name, this, value.getValue(), (s) -> { Platform.runLater(() -> value.setValue(s)); })) .createRegion(); diff --git a/app/src/main/java/io/xpipe/app/comp/source/store/GuiDsStoreCreator.java b/app/src/main/java/io/xpipe/app/comp/source/store/GuiDsStoreCreator.java index 26791f869..a2f909c27 100644 --- a/app/src/main/java/io/xpipe/app/comp/source/store/GuiDsStoreCreator.java +++ b/app/src/main/java/io/xpipe/app/comp/source/store/GuiDsStoreCreator.java @@ -93,7 +93,7 @@ public static void showEdit(DataStoreEntry e) { e.applyChanges(newE); if (!DataStorage.get().getStoreEntries().contains(e)) { DataStorage.get().addStoreEntry(e); - ScanAlert.showIfNeeded(e.getStore()); + ScanAlert.showIfNeeded(e.getStore(), true); } DataStorage.get().refresh(); }); @@ -104,7 +104,7 @@ public static void showCreation(Predicate filter) { show(null, null, null, filter, e -> { try { DataStorage.get().addStoreEntry(e); - ScanAlert.showIfNeeded(e.getStore()); + ScanAlert.showIfNeeded(e.getStore(), true); } catch (Exception ex) { ErrorEvent.fromThrowable(ex).handle(); } @@ -183,6 +183,9 @@ private Region createStoreProperties(Comp comp, Validator propVal) { public CompStructure createBase() { var layout = new BorderPane(); var providerChoice = new DsStoreProviderChoiceComp(filter, provider); + if (provider.getValue() != null) { + providerChoice.apply(struc -> struc.get().setDisable(true)); + } providerChoice.apply(GrowAugment.create(true, false)); SimpleChangeListener.apply(provider, n -> { diff --git a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreIntroComp.java b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreIntroComp.java index 9461f56cc..cff038e75 100644 --- a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreIntroComp.java +++ b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreIntroComp.java @@ -35,7 +35,7 @@ public Region createSimple() { }); var scanButton = new Button(AppI18n.get("detectConnections"), new FontIcon("mdi2m-magnify")); - scanButton.setOnAction(event -> ScanAlert.showIfNeeded(new LocalStore())); + scanButton.setOnAction(event -> ScanAlert.showIfNeeded(new LocalStore(), false)); var scanPane = new StackPane(scanButton); scanPane.setAlignment(Pos.CENTER); diff --git a/app/src/main/java/io/xpipe/app/core/FileWatchManager.java b/app/src/main/java/io/xpipe/app/core/AppFileWatcher.java similarity index 91% rename from app/src/main/java/io/xpipe/app/core/FileWatchManager.java rename to app/src/main/java/io/xpipe/app/core/AppFileWatcher.java index d3b206446..df4d82289 100644 --- a/app/src/main/java/io/xpipe/app/core/FileWatchManager.java +++ b/app/src/main/java/io/xpipe/app/core/AppFileWatcher.java @@ -15,21 +15,21 @@ import static java.nio.file.StandardWatchEventKinds.*; -public class FileWatchManager { +public class AppFileWatcher { - private static FileWatchManager INSTANCE; + private static AppFileWatcher INSTANCE; private final Set watchedDirectories = new CopyOnWriteArraySet<>(); private WatchService watchService; private Thread watcherThread; private boolean active; - public static FileWatchManager getInstance() { + public static AppFileWatcher getInstance() { return INSTANCE; } public static void init() { - INSTANCE = new FileWatchManager(); + INSTANCE = new AppFileWatcher(); INSTANCE.startWatcher(); } @@ -55,7 +55,7 @@ private void startWatcher() { while (active) { WatchKey key; try { - key = FileWatchManager.this.watchService.poll(10, TimeUnit.MILLISECONDS); + key = AppFileWatcher.this.watchService.poll(10, TimeUnit.MILLISECONDS); if (key == null) { continue; } @@ -113,7 +113,7 @@ private void createRecursiveWatchers(Path dir) { } try { - dir.register(FileWatchManager.this.watchService, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE); + dir.register(AppFileWatcher.this.watchService, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE); Files.list(dir).filter(Files::isDirectory).forEach(this::createRecursiveWatchers); } catch (IOException e) { ErrorEvent.fromThrowable(e).omit().handle(); @@ -158,7 +158,7 @@ private void handleWatchEvent(Path path, WatchEvent event) { // Add new watcher for directory if (ev.kind().equals(ENTRY_CREATE) && Files.isDirectory(file)) { try { - file.register(FileWatchManager.this.watchService, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE); + file.register(AppFileWatcher.this.watchService, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE); } catch (IOException e) { ErrorEvent.fromThrowable(e).omit().handle(); } diff --git a/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java b/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java index 9d0a4d627..19f658801 100644 --- a/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java +++ b/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java @@ -39,7 +39,7 @@ public void initialSetup() throws Exception { AppCharsets.init(); AppCharsetter.init(); DataStorage.init(); - FileWatchManager.init(); + AppFileWatcher.init(); FileBridge.init(); AppSocketServer.init(); AppUpdater.init(); diff --git a/app/src/main/java/io/xpipe/app/ext/ScanProvider.java b/app/src/main/java/io/xpipe/app/ext/ScanProvider.java index 97f0dd8e3..30585e802 100644 --- a/app/src/main/java/io/xpipe/app/ext/ScanProvider.java +++ b/app/src/main/java/io/xpipe/app/ext/ScanProvider.java @@ -45,5 +45,5 @@ public static List getAll() { return ALL; } - public abstract ScanOperation create(DataStore store); + public abstract ScanOperation create(DataStore store, boolean automatic); } diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/OptionsComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/OptionsComp.java index 13b4a3c64..4ee27165c 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/OptionsComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/OptionsComp.java @@ -2,6 +2,7 @@ import atlantafx.base.controls.Popover; import atlantafx.base.controls.Spacer; +import atlantafx.base.theme.Styles; import io.xpipe.app.comp.base.MarkdownComp; import io.xpipe.app.core.AppFont; import io.xpipe.app.fxcomps.Comp; @@ -90,6 +91,8 @@ public CompStructure createBase() { AppFont.small(popover.getContentNode()); var descriptionHover = new Button("... ?"); + descriptionHover.getStyleClass().add(Styles.BUTTON_OUTLINED); + descriptionHover.getStyleClass().add(Styles.ACCENT); descriptionHover.setPadding(new Insets(0, 6, 0, 6)); descriptionHover.getStyleClass().add("long-description"); AppFont.header(descriptionHover); diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/ToggleGroupComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/ToggleGroupComp.java index 116c0d6ae..ddabf6039 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/ToggleGroupComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/ToggleGroupComp.java @@ -1,5 +1,6 @@ package io.xpipe.app.fxcomps.impl; +import atlantafx.base.theme.Styles; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.SimpleCompStructure; @@ -55,14 +56,14 @@ public CompStructure createBase() { } if (box.getChildren().size() > 0) { - box.getChildren().get(0).getStyleClass().add("first"); + box.getChildren().get(0).getStyleClass().add(Styles.LEFT_PILL); for (int i = 1; i < box.getChildren().size() - 1; i++) { - box.getChildren().get(i).getStyleClass().add("center"); + box.getChildren().get(i).getStyleClass().add(Styles.CENTER_PILL); } box.getChildren() .get(box.getChildren().size() - 1) .getStyleClass() - .add("last"); + .add(Styles.RIGHT_PILL); } }); diff --git a/app/src/main/java/io/xpipe/app/issue/UserReportComp.java b/app/src/main/java/io/xpipe/app/issue/UserReportComp.java index 31e0c3001..7a20c8399 100644 --- a/app/src/main/java/io/xpipe/app/issue/UserReportComp.java +++ b/app/src/main/java/io/xpipe/app/issue/UserReportComp.java @@ -103,7 +103,7 @@ private Region createBottomBarNavigation() { .apply(struc -> struc.get().getStyleClass().addAll(BUTTON_OUTLINED, ACCENT)) .createRegion(); var spacer = new Region(); - var buttons = new HBox(dataPolicyButton, spacer, sendButton); + var buttons = new HBox(spacer, sendButton); buttons.setAlignment(Pos.CENTER); buttons.getStyleClass().add("buttons"); HBox.setHgrow(spacer, Priority.ALWAYS); diff --git a/app/src/main/java/io/xpipe/app/util/ApplicationHelper.java b/app/src/main/java/io/xpipe/app/util/ApplicationHelper.java index 18339d004..13c9a39af 100644 --- a/app/src/main/java/io/xpipe/app/util/ApplicationHelper.java +++ b/app/src/main/java/io/xpipe/app/util/ApplicationHelper.java @@ -13,7 +13,7 @@ public class ApplicationHelper { public static void executeLocalApplication(String s) throws Exception { var args = ShellDialects.getPlatformDefault().executeCommandListWithShell(s); TrackEvent.withDebug("proc", "Executing local application") - .elements(args) + .tag("command", s) .handle(); try (var c = LocalStore.getShell().command(s).start()) { c.discardOrThrow(); @@ -21,9 +21,8 @@ public static void executeLocalApplication(String s) throws Exception { } public static void executeLocalApplication(List s) throws Exception { - var args = ShellDialects.getPlatformDefault().executeCommandListWithShell(s); TrackEvent.withDebug("proc", "Executing local application") - .elements(args) + .elements(s) .handle(); try (var c = LocalStore.getShell().command(s).start()) { c.discardOrThrow(); diff --git a/app/src/main/java/io/xpipe/app/util/FileBridge.java b/app/src/main/java/io/xpipe/app/util/FileBridge.java index 698eb1407..3dd02019e 100644 --- a/app/src/main/java/io/xpipe/app/util/FileBridge.java +++ b/app/src/main/java/io/xpipe/app/util/FileBridge.java @@ -1,6 +1,6 @@ package io.xpipe.app.util; -import io.xpipe.app.core.FileWatchManager; +import io.xpipe.app.core.AppFileWatcher; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.TrackEvent; import io.xpipe.app.prefs.AppPrefs; @@ -51,7 +51,7 @@ public static void init() { } catch (IOException ignored) { } - FileWatchManager.getInstance().startWatchersInDirectories(List.of(TEMP), (changed, kind) -> { + AppFileWatcher.getInstance().startWatchersInDirectories(List.of(TEMP), (changed, kind) -> { if (kind == StandardWatchEventKinds.ENTRY_DELETE) { event("Editor entry file " + changed.toString() + " has been removed"); INSTANCE.removeForFile(changed); @@ -121,7 +121,7 @@ private Optional getForFile(Path file) { return Optional.empty(); } - public void openString(String keyName, String fileType, Object key, String input, Consumer output, Consumer consumer) { + public void openString(String keyName, Object key, String input, Consumer output, Consumer consumer) { if (input == null) { input = ""; } @@ -129,7 +129,6 @@ public void openString(String keyName, String fileType, Object key, String input String s = input; openIO( keyName, - fileType, key, () -> new ByteArrayInputStream(s.getBytes(StandardCharsets.UTF_8)), () -> new ByteArrayOutputStream(s.length()) { @@ -144,7 +143,6 @@ public void close() throws IOException { public void openIO( String keyName, - String fileType, Object key, FailableSupplier input, FailableSupplier output, @@ -155,9 +153,7 @@ public void openIO( return; } - var name = keyName + " - " + UUID.randomUUID().toString().substring(0, 6) + "." - + (fileType != null ? fileType : "txt"); - Path file = TEMP.resolve(name); + Path file = TEMP.resolve(UUID.randomUUID().toString().substring(0, 6)).resolve(keyName); try { FileUtils.forceMkdirParent(file.toFile()); try (var out = Files.newOutputStream(file); diff --git a/app/src/main/java/io/xpipe/app/util/FileOpener.java b/app/src/main/java/io/xpipe/app/util/FileOpener.java index cf2553155..9484a995f 100644 --- a/app/src/main/java/io/xpipe/app/util/FileOpener.java +++ b/app/src/main/java/io/xpipe/app/util/FileOpener.java @@ -6,7 +6,6 @@ import io.xpipe.core.impl.LocalStore; import io.xpipe.core.process.OsType; import io.xpipe.core.store.FileSystem; -import org.apache.commons.io.FilenameUtils; import java.nio.file.Path; import java.util.function.Consumer; @@ -23,7 +22,6 @@ public static void openInDefaultApplication(FileSystem.FileEntry entry) { FileBridge.get() .openIO( FileNames.getFileName(file), - FilenameUtils.getExtension(file), file, () -> { return entry.getFileSystem().openInput(file); @@ -42,7 +40,6 @@ public static void openInTextEditor(FileSystem.FileEntry entry) { FileBridge.get() .openIO( FileNames.getFileName(file), - FilenameUtils.getExtension(file), file, () -> { return entry.getFileSystem().openInput(file); @@ -67,7 +64,7 @@ public static void openInTextEditor(String file) { public static void openInDefaultApplication(String file) { try (var pc = LocalStore.getShell().start()) { if (pc.getOsType().equals(OsType.WINDOWS)) { - pc.executeSimpleCommand("\"" + file + "\""); + pc.executeSimpleCommand("start \"\" \"" + file + "\""); } else if (pc.getOsType().equals(OsType.LINUX)) { pc.executeSimpleCommand("xdg-open \"" + file + "\""); } else { @@ -78,7 +75,7 @@ public static void openInDefaultApplication(String file) { } } - public static void openString(String keyName, String fileType, Object key, String input, Consumer output) { - FileBridge.get().openString(keyName, fileType, key, input, output, file -> openInTextEditor(file)); + public static void openString(String keyName,Object key, String input, Consumer output) { + FileBridge.get().openString(keyName, key, input, output, file -> openInTextEditor(file)); } } diff --git a/app/src/main/java/io/xpipe/app/util/OptionsBuilder.java b/app/src/main/java/io/xpipe/app/util/OptionsBuilder.java index 7c7034028..c29b513c0 100644 --- a/app/src/main/java/io/xpipe/app/util/OptionsBuilder.java +++ b/app/src/main/java/io/xpipe/app/util/OptionsBuilder.java @@ -5,6 +5,7 @@ import io.xpipe.app.fxcomps.impl.*; import io.xpipe.core.util.SecretValue; import javafx.beans.property.Property; +import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ObservableValue; import javafx.scene.control.Label; import javafx.scene.layout.Region; @@ -12,6 +13,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.function.Supplier; public class OptionsBuilder { @@ -80,7 +82,18 @@ public OptionsBuilder addInteger(Property prop) { props.add(prop); return this; } - + public OptionsBuilder addToggle(Property prop) { + var comp = new ToggleGroupComp<>( + prop, + new SimpleObjectProperty<>(Map.of( + Boolean.TRUE, + AppI18n.observable("app.yes"), + Boolean.FALSE, + AppI18n.observable("app.no")))); + pushComp(comp); + props.add(prop); + return this; + } public OptionsBuilder addString(Property prop) { return addString(prop, false); } diff --git a/app/src/main/java/io/xpipe/app/util/ScanAlert.java b/app/src/main/java/io/xpipe/app/util/ScanAlert.java index b20a5bc90..d04f6b7ac 100644 --- a/app/src/main/java/io/xpipe/app/util/ScanAlert.java +++ b/app/src/main/java/io/xpipe/app/util/ScanAlert.java @@ -19,10 +19,10 @@ public class ScanAlert { - public static void showIfNeeded(DataStore store) { + public static void showIfNeeded(DataStore store, boolean automatic) { var providers = ScanProvider.getAll(); var applicable = providers.stream() - .map(scanProvider -> scanProvider.create(store)) + .map(scanProvider -> scanProvider.create(store, automatic)) .filter(scanOperation -> scanOperation != null) .toList(); if (applicable.size() == 0) { diff --git a/app/src/main/resources/io/xpipe/app/resources/style/error-handler-comp.css b/app/src/main/resources/io/xpipe/app/resources/style/error-handler-comp.css index cf3afc989..4901747ae 100644 --- a/app/src/main/resources/io/xpipe/app/resources/style/error-handler-comp.css +++ b/app/src/main/resources/io/xpipe/app/resources/style/error-handler-comp.css @@ -25,8 +25,8 @@ } .error-report .buttons { --fx-border-color:-color-accent-fg; --fx-border-width: 0.1em 0 0 0; +-fx-border-color: -color-neutral-emphasis; +-fx-border-width: 1px 0 0 0; -fx-padding: 1.0em 1.5em 1em 1.5em; -fx-background-color: -color-neutral-muted; -fx-effect: dropshadow(three-pass-box, #333, 6, 0, 0, -1); diff --git a/app/src/main/resources/io/xpipe/app/resources/style/style.css b/app/src/main/resources/io/xpipe/app/resources/style/style.css index b7cfeafdd..307c9033e 100644 --- a/app/src/main/resources/io/xpipe/app/resources/style/style.css +++ b/app/src/main/resources/io/xpipe/app/resources/style/style.css @@ -43,6 +43,6 @@ } .loading-comp { --fx-background-color: #FFFFFFAA; +-fx-background-color: #0002; } diff --git a/core/src/main/java/io/xpipe/core/impl/FileNames.java b/core/src/main/java/io/xpipe/core/impl/FileNames.java index 8b833c82f..97aff146c 100644 --- a/core/src/main/java/io/xpipe/core/impl/FileNames.java +++ b/core/src/main/java/io/xpipe/core/impl/FileNames.java @@ -34,6 +34,19 @@ public static String getFileName(String file) { return components.get(components.size() - 1); } + public static String getExtension(String file) { + if (file == null || file.isEmpty()) { + return null; + } + + var name = FileNames.getFileName(file); + var split = file.split("\\."); + if (split.length == 0) { + return null; + } + return split[split.length - 1]; + } + public static String join(String... parts) { var joined = String.join("/", parts); return normalize(joined); diff --git a/core/src/main/java/io/xpipe/core/process/ShellDialects.java b/core/src/main/java/io/xpipe/core/process/ShellDialects.java index 3c7a85afa..62dcf8fed 100644 --- a/core/src/main/java/io/xpipe/core/process/ShellDialects.java +++ b/core/src/main/java/io/xpipe/core/process/ShellDialects.java @@ -37,7 +37,7 @@ public boolean requiresFullDaemon() { @Override public boolean prioritizeLoading() { - return false; + return true; } } diff --git a/version b/version index 389faccca..ad83b1b09 100644 --- a/version +++ b/version @@ -1 +1 @@ -0.5.5 \ No newline at end of file +0.5.6 \ No newline at end of file