diff --git a/app/src/main/java/io/xpipe/app/Main.java b/app/src/main/java/io/xpipe/app/Main.java index 25c6cadc6..39716c264 100644 --- a/app/src/main/java/io/xpipe/app/Main.java +++ b/app/src/main/java/io/xpipe/app/Main.java @@ -12,11 +12,13 @@ public class Main { return; } - // Since this is not marked as a console application, it will not print anything when you run it in a console on Windows + // Since this is not marked as a console application, it will not print anything when you run it in a console on + // Windows if (args.length == 1 && args[0].equals("--help")) { - System.out.println(""" + System.out.println( + """ The daemon executable xpiped does not accept any command-line arguments. - + For a reference on what you can do from the CLI, take a look at the xpipe CLI executable instead. """); return; diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserBookmarkComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserBookmarkComp.java index 736de4643..a5b602c96 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserBookmarkComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserBookmarkComp.java @@ -39,8 +39,7 @@ public final class BrowserBookmarkComp extends SimpleComp { public BrowserBookmarkComp( ObservableValue selected, Predicate applicable, - BiConsumer action - ) { + BiConsumer action) { this.selected = selected; this.applicable = applicable; this.action = action; @@ -66,8 +65,8 @@ public final class BrowserBookmarkComp extends SimpleComp { .pseudoClassStateChanged( SELECTED, newValue != null - && newValue - .equals(s.getWrapper().getEntry())); + && newValue.equals( + s.getWrapper().getEntry())); }); }); }); diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserBreadcrumbBar.java b/app/src/main/java/io/xpipe/app/browser/BrowserBreadcrumbBar.java index 585e2b144..b2a1f2850 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserBreadcrumbBar.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserBreadcrumbBar.java @@ -40,7 +40,7 @@ public class BrowserBreadcrumbBar extends SimpleComp { var breadcrumbs = new Breadcrumbs(); breadcrumbs.setMinWidth(0); - PlatformThread.sync(model.getCurrentPath()).subscribe( val -> { + PlatformThread.sync(model.getCurrentPath()).subscribe(val -> { if (val == null) { breadcrumbs.setSelectedCrumb(null); return; diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserFilterComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserFilterComp.java index 2171e4b1f..65cbbd66a 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserFilterComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserFilterComp.java @@ -4,8 +4,8 @@ import atlantafx.base.theme.Styles; import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; -import io.xpipe.app.fxcomps.impl.TooltipAugment; import io.xpipe.app.fxcomps.impl.TextFieldComp; +import io.xpipe.app.fxcomps.impl.TooltipAugment; import javafx.beans.property.Property; import javafx.beans.property.SimpleBooleanProperty; import javafx.geometry.Pos; 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 ca9de277d..c6a320798 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserStatusBarComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserStatusBarComp.java @@ -128,6 +128,10 @@ public class BrowserStatusBarComp extends SimpleComp { }); // Use status bar as an extension of file list - new ContextMenuAugment<>(mouseEvent -> mouseEvent.getButton() == MouseButton.SECONDARY, null, () -> new BrowserContextMenu(model, null)).augment(new SimpleCompStructure<>(r)); + new ContextMenuAugment<>( + mouseEvent -> mouseEvent.getButton() == MouseButton.SECONDARY, + null, + () -> new BrowserContextMenu(model, null)) + .augment(new SimpleCompStructure<>(r)); } } 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 c275f117b..01b12d6d7 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserTransferComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserTransferComp.java @@ -123,14 +123,15 @@ public class BrowserTransferComp extends SimpleComp { return; } - if (!(model.getBrowserSessionModel().getSelectedEntry().getValue() instanceof OpenFileSystemModel fileSystemModel)) { + if (!(model.getBrowserSessionModel() + .getSelectedEntry() + .getValue() + instanceof OpenFileSystemModel fileSystemModel)) { return; } var files = drag.getEntries(); - model.drop( - fileSystemModel, - files); + model.drop(fileSystemModel, files); event.setDropCompleted(true); event.consume(); } 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 8e1b95267..7187b11a8 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserWelcomeComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserWelcomeComp.java @@ -78,15 +78,14 @@ public class BrowserWelcomeComp extends SimpleComp { }); var empty = Bindings.createBooleanBinding(() -> list.isEmpty(), list); - var headerBinding = BindingsHelper.flatMap(empty,b -> { + var headerBinding = BindingsHelper.flatMap(empty, b -> { if (b) { return AppI18n.observable("browserWelcomeEmpty"); } else { return AppI18n.observable("browserWelcomeSystems"); } }); - var header = new LabelComp(headerBinding) - .createRegion(); + var header = new LabelComp(headerBinding).createRegion(); AppFont.setSize(header, 1); vbox.getChildren().add(header); @@ -94,7 +93,7 @@ public class BrowserWelcomeComp extends SimpleComp { storeList.setSpacing(8); var listBox = new ListBoxViewComp<>(list, list, e -> { - var disable = new SimpleBooleanProperty(); + var disable = new SimpleBooleanProperty(); var entryButton = entryButton(e, disable); var dirButton = dirButton(e, disable); return new HorizontalComp(List.of(entryButton, dirButton)); @@ -130,15 +129,17 @@ public class BrowserWelcomeComp extends SimpleComp { private Comp entryButton(BrowserSavedState.Entry e, BooleanProperty disable) { var entry = DataStorage.get().getStoreEntryIfPresent(e.getUuid()); - var graphic = entry.get() - .getProvider() - .getDisplayIconFileName(entry.get().getStore()); + var graphic = + entry.get().getProvider().getDisplayIconFileName(entry.get().getStore()); var view = PrettyImageHelper.ofFixedSize(graphic, 30, 24); - return new ButtonComp(new SimpleStringProperty(DataStorage.get().getStoreDisplayName(entry.get())), view.createRegion(), () -> { - ThreadHelper.runAsync(() -> { - model.restoreStateAsync(e, disable); - }); - }) + return new ButtonComp( + new SimpleStringProperty(DataStorage.get().getStoreDisplayName(entry.get())), + view.createRegion(), + () -> { + ThreadHelper.runAsync(() -> { + model.restoreStateAsync(e, disable); + }); + }) .minWidth(250) .accessibleText(DataStorage.get().getStoreDisplayName(entry.get())) .disable(disable) @@ -149,10 +150,10 @@ public class BrowserWelcomeComp extends SimpleComp { private Comp dirButton(BrowserSavedState.Entry e, BooleanProperty disable) { var entry = DataStorage.get().getStoreEntryIfPresent(e.getUuid()); return new ButtonComp(new SimpleStringProperty(e.getPath()), null, () -> { - ThreadHelper.runAsync(() -> { - model.restoreStateAsync(e, disable); - }); - }) + ThreadHelper.runAsync(() -> { + model.restoreStateAsync(e, disable); + }); + }) .accessibleText(e.getPath()) .disable(disable) .styleClass("directory-button") diff --git a/app/src/main/java/io/xpipe/app/browser/action/BrowserAction.java b/app/src/main/java/io/xpipe/app/browser/action/BrowserAction.java index bb06196ff..a496962ea 100644 --- a/app/src/main/java/io/xpipe/app/browser/action/BrowserAction.java +++ b/app/src/main/java/io/xpipe/app/browser/action/BrowserAction.java @@ -92,6 +92,5 @@ public interface BrowserAction { }) .toList()); } - } } diff --git a/app/src/main/java/io/xpipe/app/browser/action/LeafAction.java b/app/src/main/java/io/xpipe/app/browser/action/LeafAction.java index a96bb65ff..5813546aa 100644 --- a/app/src/main/java/io/xpipe/app/browser/action/LeafAction.java +++ b/app/src/main/java/io/xpipe/app/browser/action/LeafAction.java @@ -60,8 +60,7 @@ public interface LeafAction extends BrowserAction { return b; } - default MenuItem toMenuItem( - OpenFileSystemModel model, List selected) { + default MenuItem toMenuItem(OpenFileSystemModel model, List selected) { var name = getName(model, selected); var mi = new MenuItem(); mi.textProperty().bind(name); diff --git a/app/src/main/java/io/xpipe/app/browser/action/MultiExecuteAction.java b/app/src/main/java/io/xpipe/app/browser/action/MultiExecuteAction.java index b173fc002..acd027940 100644 --- a/app/src/main/java/io/xpipe/app/browser/action/MultiExecuteAction.java +++ b/app/src/main/java/io/xpipe/app/browser/action/MultiExecuteAction.java @@ -43,7 +43,9 @@ public abstract class MultiExecuteAction implements BranchAction { @Override public ObservableValue getName(OpenFileSystemModel model, List entries) { var t = AppPrefs.get().terminalType().getValue(); - return AppI18n.observable("executeInTerminal", t != null ? t.toTranslatedString().getValue() : "?"); + return AppI18n.observable( + "executeInTerminal", + t != null ? t.toTranslatedString().getValue() : "?"); } @Override diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserEntry.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserEntry.java index 7ac1013c6..49f90ae74 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserEntry.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserEntry.java @@ -1,6 +1,5 @@ package io.xpipe.app.browser.file; -import io.xpipe.app.browser.file.BrowserFileListModel; import io.xpipe.app.browser.icon.BrowserIconDirectoryType; import io.xpipe.app.browser.icon.BrowserIconFileType; import io.xpipe.core.store.FileKind; diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListComp.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListComp.java index afa5c29c8..534adb8d2 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListComp.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListComp.java @@ -267,7 +267,7 @@ public final class BrowserFileListComp extends SimpleComp { return false; }, - null, + null, () -> { if (row.getItem() != null && row.getItem().isSynthetic()) { return null; @@ -505,15 +505,20 @@ public final class BrowserFileListComp extends SimpleComp { var quickAccess = new BrowserQuickAccessButtonComp( () -> getTableRow().getItem(), fileList.getFileSystemModel()) .hide(Bindings.createBooleanBinding( - () -> { - var item = getTableRow().getItem(); - var notDir = item.getRawFileEntry().resolved().getKind() != FileKind.DIRECTORY; - var isParentLink = item - .getRawFileEntry() - .equals(fileList.getFileSystemModel().getCurrentParentDirectory()); - return notDir || isParentLink; - }, - itemProperty()).not().not()) + () -> { + var item = getTableRow().getItem(); + var notDir = item.getRawFileEntry() + .resolved() + .getKind() + != FileKind.DIRECTORY; + var isParentLink = item.getRawFileEntry() + .equals(fileList.getFileSystemModel() + .getCurrentParentDirectory()); + return notDir || isParentLink; + }, + itemProperty()) + .not() + .not()) .createRegion(); editing.addListener((observable, oldValue, newValue) -> { @@ -557,7 +562,7 @@ public final class BrowserFileListComp extends SimpleComp { // 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); - + // Visibility seems to be bugged, so use opacity setOpacity(0.0); } else { diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileOverviewComp.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileOverviewComp.java index 2bb265e73..1f263631b 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileOverviewComp.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileOverviewComp.java @@ -32,8 +32,10 @@ public class BrowserFileOverviewComp extends SimpleComp { Function> factory = entry -> { return Comp.of(() -> { var icon = BrowserIcons.createIcon(entry); - var graphic = new HorizontalComp(List.of(icon, - new BrowserQuickAccessButtonComp(() -> new BrowserEntry(entry, model.getFileList(),false),model))); + var graphic = new HorizontalComp(List.of( + icon, + new BrowserQuickAccessButtonComp( + () -> new BrowserEntry(entry, model.getFileList(), false), model))); var l = new Button(entry.getPath(), graphic.createRegion()); l.setGraphicTextGap(1); l.setOnAction(event -> { diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserQuickAccessContextMenu.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserQuickAccessContextMenu.java index fdf0547b2..382b6cced 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserQuickAccessContextMenu.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserQuickAccessContextMenu.java @@ -29,18 +29,105 @@ import java.util.stream.Collectors; public class BrowserQuickAccessContextMenu extends ContextMenu { + private final Supplier base; + private final OpenFileSystemModel model; + private ContextMenu shownBrowserActionsMenu; + private boolean expandBrowserActionMenuKey; + private boolean keyBasedNavigation; + private boolean closeBrowserActionMenuKey; + public BrowserQuickAccessContextMenu(Supplier base, OpenFileSystemModel model) { + this.base = base; + this.model = model; + + addEventFilter(Menu.ON_SHOWING, e -> { + Node content = getSkin().getNode(); + if (content instanceof Region r) { + r.setMaxWidth(500); + } + }); + addEventFilter(Menu.ON_SHOWN, e -> { + Platform.runLater(() -> { + getItems().getFirst().getStyleableNode().requestFocus(); + }); + }); + InputHelper.onLeft(this, false, e -> { + hide(); + e.consume(); + }); + setAutoHide(true); + getStyleClass().add("condensed"); + } + + public void showMenu(Node anchor) { + getItems().clear(); + ThreadHelper.runFailableAsync(() -> { + var entry = base.get(); + if (entry.getRawFileEntry().resolved().getKind() != FileKind.DIRECTORY) { + return; + } + + var actionsMenu = new AtomicReference(); + var r = new Menu(); + var newItems = updateMenuItems(r, entry, true); + Platform.runLater(() -> { + getItems().addAll(r.getItems()); + show(anchor, Side.RIGHT, 0, 0); + }); + }); + } + + private MenuItem createItem(BrowserEntry browserEntry) { + return new QuickAccessMenu(browserEntry).getMenu(); + } + + private List updateMenuItems(Menu m, BrowserEntry entry, boolean updateInstantly) throws Exception { + var newFiles = model.getFileSystem() + .listFiles(entry.getRawFileEntry().resolved().getPath()); + try (var s = newFiles) { + var list = s.map(fileEntry -> fileEntry.resolved()).toList(); + // Wait until all files are listed, i.e. do not skip the stream elements + list = list.subList(0, Math.min(list.size(), 150)); + + var newItems = new ArrayList(); + if (list.isEmpty()) { + var empty = new Menu(""); + empty.getStyleClass().add("leaf"); + newItems.add(empty); + } else { + var browserEntries = list.stream() + .map(fileEntry -> new BrowserEntry(fileEntry, model.getFileList(), false)) + .toList(); + var menus = browserEntries.stream() + .sorted(model.getFileList().order()) + .collect(Collectors.toMap(e -> e, e -> createItem(e), (v1, v2) -> v2, LinkedHashMap::new)); + var dirs = browserEntries.stream() + .filter(e -> e.getRawFileEntry().getKind() == FileKind.DIRECTORY) + .toList(); + if (dirs.size() == 1) { + updateMenuItems((Menu) menus.get(dirs.getFirst()), dirs.getFirst(), true); + } + newItems.addAll(menus.values()); + } + if (updateInstantly) { + m.getItems().setAll(newItems); + } + return newItems; + } + } + @Getter class QuickAccessMenu { private final BrowserEntry browserEntry; - private ContextMenu browserActionMenu; private final Menu menu; + private ContextMenu browserActionMenu; public QuickAccessMenu(BrowserEntry browserEntry) { this.browserEntry = browserEntry; this.menu = new Menu( // Use original name, not the link target browserEntry.getRawFileEntry().getName(), - PrettyImageHelper.ofFixedSizeSquare(FileIconManager.getFileIcon(browserEntry.getRawFileEntry(), false), 24) + PrettyImageHelper.ofFixedSizeSquare( + FileIconManager.getFileIcon(browserEntry.getRawFileEntry(), false), 24) .createRegion()); createMenu(); addInputListeners(); @@ -49,7 +136,7 @@ public class BrowserQuickAccessContextMenu extends ContextMenu { private void createMenu() { var fileEntry = browserEntry.getRawFileEntry(); if (fileEntry.resolved().getKind() != FileKind.DIRECTORY) { - createFileMenu(); + createFileMenu(); } else { createDirectoryMenu(); } @@ -141,8 +228,9 @@ public class BrowserQuickAccessContextMenu extends ContextMenu { } }); new BooleanAnimationTimer(hover, 100, () -> { - expandDirectoryMenu(empty); - }).start(); + expandDirectoryMenu(empty); + }) + .start(); } private void addInputListeners() { @@ -155,13 +243,15 @@ public class BrowserQuickAccessContextMenu extends ContextMenu { } else { expandBrowserActionMenuKey = false; } - if (event.getCode().equals(KeyCode.LEFT) && browserActionMenu != null && browserActionMenu.isShowing()) { + if (event.getCode().equals(KeyCode.LEFT) + && browserActionMenu != null + && browserActionMenu.isShowing()) { closeBrowserActionMenuKey = true; } else { closeBrowserActionMenuKey = false; } }); - contextMenu.addEventFilter(MouseEvent.ANY,event -> { + contextMenu.addEventFilter(MouseEvent.ANY, event -> { keyBasedNavigation = false; }); } @@ -217,102 +307,4 @@ public class BrowserQuickAccessContextMenu extends ContextMenu { }); } } - - private final Supplier base; - private final OpenFileSystemModel model; - private ContextMenu shownBrowserActionsMenu; - - private boolean expandBrowserActionMenuKey; - private boolean keyBasedNavigation; - private boolean closeBrowserActionMenuKey; - - public BrowserQuickAccessContextMenu(Supplier base, OpenFileSystemModel model) { - this.base = base; - this.model = model; - - addEventFilter(Menu.ON_SHOWING, e -> { - Node content = getSkin().getNode(); - if (content instanceof Region r) { - r.setMaxWidth(500); - } - }); - addEventFilter(Menu.ON_SHOWN, e -> { - Platform.runLater(() -> { - getItems().getFirst().getStyleableNode().requestFocus(); - }); - }); - InputHelper.onLeft(this, false, e -> { - hide(); - e.consume(); - }); - setAutoHide(true); - getStyleClass().add("condensed"); - } - - public void showMenu(Node anchor) { - getItems().clear(); - ThreadHelper.runFailableAsync(() -> { - var entry = base.get(); - if (entry.getRawFileEntry().resolved().getKind() != FileKind.DIRECTORY) { - return; - } - - var actionsMenu = new AtomicReference(); - var r = new Menu(); - var newItems = updateMenuItems(r, entry, true); - Platform.runLater(() -> { - getItems().addAll(r.getItems()); - show(anchor, Side.RIGHT, 0, 0); - }); - }); - } - - private MenuItem createItem(BrowserEntry browserEntry) { - return new QuickAccessMenu(browserEntry).getMenu(); - } - - private List updateMenuItems( - Menu m, - BrowserEntry entry, - boolean updateInstantly) - throws Exception { - var newFiles = model.getFileSystem().listFiles(entry.getRawFileEntry().resolved().getPath()); - try (var s = newFiles) { - var list = s.map(fileEntry -> fileEntry.resolved()).toList(); - // Wait until all files are listed, i.e. do not skip the stream elements - list = list.subList(0, Math.min(list.size(), 150)); - - var newItems = new ArrayList(); - if (list.isEmpty()) { - var empty = new Menu(""); - empty.getStyleClass().add("leaf"); - newItems.add(empty); - } else { - var browserEntries = list.stream() - .map(fileEntry -> new BrowserEntry(fileEntry, model.getFileList(), false)) - .toList(); - var menus = browserEntries.stream() - .sorted(model.getFileList().order()) - .collect(Collectors.toMap( - e -> e, - e -> createItem(e), - (v1, v2) -> v2, - LinkedHashMap::new)); - var dirs = browserEntries.stream() - .filter(e -> e.getRawFileEntry().getKind() == FileKind.DIRECTORY) - .toList(); - if (dirs.size() == 1) { - updateMenuItems( - (Menu) menus.get(dirs.getFirst()), - dirs.getFirst(), - true); - } - newItems.addAll(menus.values()); - } - if (updateInstantly) { - m.getItems().setAll(newItems); - } - return newItems; - } - } } diff --git a/app/src/main/java/io/xpipe/app/browser/file/FileSystemHelper.java b/app/src/main/java/io/xpipe/app/browser/file/FileSystemHelper.java index 5dae14b27..6dab09a9d 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/FileSystemHelper.java +++ b/app/src/main/java/io/xpipe/app/browser/file/FileSystemHelper.java @@ -296,8 +296,11 @@ public class FileSystemHelper { AtomicLong transferred = new AtomicLong(); for (var e : flatFiles.entrySet()) { var sourceFile = e.getKey(); - var targetFile = target.getFileSystem().getShell().orElseThrow().getOsType().makeFileSystemCompatible( - FileNames.join(target.getPath(), e.getValue())); + var targetFile = target.getFileSystem() + .getShell() + .orElseThrow() + .getOsType() + .makeFileSystemCompatible(FileNames.join(target.getPath(), e.getValue())); if (sourceFile.getFileSystem().equals(target.getFileSystem())) { throw new IllegalStateException(); } diff --git a/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemComp.java b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemComp.java index 6f29718c6..70990781f 100644 --- a/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemComp.java +++ b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemComp.java @@ -60,7 +60,9 @@ public class OpenFileSystemComp extends SimpleComp { var menuButton = new MenuButton(null, new FontIcon("mdral-folder_open")); new ContextMenuAugment<>( - event -> event.getButton() == MouseButton.PRIMARY, null, () -> new BrowserContextMenu(model, null)) + event -> event.getButton() == MouseButton.PRIMARY, + null, + () -> new BrowserContextMenu(model, null)) .augment(new SimpleCompStructure<>(menuButton)); menuButton.disableProperty().bind(model.getInOverview()); menuButton.setAccessibleText("Directory options"); diff --git a/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemModel.java b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemModel.java index f8ee6af5f..1c86f940d 100644 --- a/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemModel.java +++ b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemModel.java @@ -1,10 +1,10 @@ package io.xpipe.app.browser.fs; -import io.xpipe.app.browser.file.BrowserFileListModel; import io.xpipe.app.browser.BrowserSavedState; import io.xpipe.app.browser.BrowserTransferProgress; -import io.xpipe.app.browser.file.FileSystemHelper; import io.xpipe.app.browser.action.BrowserAction; +import io.xpipe.app.browser.file.BrowserFileListModel; +import io.xpipe.app.browser.file.FileSystemHelper; import io.xpipe.app.browser.session.BrowserAbstractSessionModel; import io.xpipe.app.browser.session.BrowserSessionModel; import io.xpipe.app.browser.session.BrowserSessionTab; @@ -49,7 +49,10 @@ public final class OpenFileSystemModel extends BrowserSessionTab model, DataStoreEntryRef entry, SelectionMode selectionMode) { + public OpenFileSystemModel( + BrowserAbstractSessionModel model, + DataStoreEntryRef entry, + SelectionMode selectionMode) { super(model, entry); this.inOverview.bind(Bindings.createBooleanBinding( () -> { @@ -68,8 +71,8 @@ public final class OpenFileSystemModel extends BrowserSessionTab ALL = new ArrayList<>(); - public synchronized static BrowserIconDirectoryType byId(String id) { + public static synchronized BrowserIconDirectoryType byId(String id) { return ALL.stream() .filter(fileType -> fileType.getId().equals(id)) .findAny() .orElseThrow(); } - public synchronized static void loadDefinitions() { + public static synchronized void loadDefinitions() { ALL.add(new BrowserIconDirectoryType() { @Override diff --git a/app/src/main/java/io/xpipe/app/browser/icon/BrowserIconFileType.java b/app/src/main/java/io/xpipe/app/browser/icon/BrowserIconFileType.java index 58be92326..3d23c0337 100644 --- a/app/src/main/java/io/xpipe/app/browser/icon/BrowserIconFileType.java +++ b/app/src/main/java/io/xpipe/app/browser/icon/BrowserIconFileType.java @@ -16,14 +16,14 @@ public abstract class BrowserIconFileType { private static final List ALL = new ArrayList<>(); - public synchronized static BrowserIconFileType byId(String id) { + public static synchronized BrowserIconFileType byId(String id) { return ALL.stream() .filter(fileType -> fileType.getId().equals(id)) .findAny() .orElseThrow(); } - public synchronized static void loadDefinitions() { + public static synchronized void loadDefinitions() { AppResources.with(AppResources.XPIPE_MODULE, "file_list.txt", path -> { try (var reader = new BufferedReader(new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8))) { @@ -57,11 +57,11 @@ public abstract class BrowserIconFileType { return ALL; } - public abstract String getId(); + public abstract String getId(); - public abstract boolean matches(FileSystem.FileEntry entry); + public abstract boolean matches(FileSystem.FileEntry entry); - public abstract String getIcon(); + public abstract String getIcon(); @Getter public static class Simple extends BrowserIconFileType { diff --git a/app/src/main/java/io/xpipe/app/browser/session/BrowserChooserComp.java b/app/src/main/java/io/xpipe/app/browser/session/BrowserChooserComp.java index 0fc206e63..4654cd89a 100644 --- a/app/src/main/java/io/xpipe/app/browser/session/BrowserChooserComp.java +++ b/app/src/main/java/io/xpipe/app/browser/session/BrowserChooserComp.java @@ -50,7 +50,8 @@ public class BrowserChooserComp extends SimpleComp { var comp = new BrowserChooserComp(model) .apply(struc -> struc.get().setPrefSize(1200, 700)) .apply(struc -> AppFont.normal(struc.get())); - var window = AppWindowHelper.sideWindow(AppI18n.get(save ? "saveFileTitle" : "openFileTitle"), stage -> comp, false, null); + var window = AppWindowHelper.sideWindow( + AppI18n.get(save ? "saveFileTitle" : "openFileTitle"), stage -> comp, false, null); model.setOnFinish(fileStores -> { file.accept(fileStores.size() > 0 ? fileStores.getFirst() : null); window.close(); @@ -81,7 +82,12 @@ public class BrowserChooserComp extends SimpleComp { }); }; - var bookmarksList = new BrowserBookmarkComp(BindingsHelper.map(model.getSelectedEntry(), v -> v.getEntry().get()), applicable, action).vgrow(); + var bookmarksList = new BrowserBookmarkComp( + BindingsHelper.map( + model.getSelectedEntry(), v -> v.getEntry().get()), + applicable, + action) + .vgrow(); var stack = Comp.of(() -> { var s = new StackPane(); model.getSelectedEntry().subscribe(selected -> { diff --git a/app/src/main/java/io/xpipe/app/browser/session/BrowserChooserModel.java b/app/src/main/java/io/xpipe/app/browser/session/BrowserChooserModel.java index 2c24178ef..c93b65009 100644 --- a/app/src/main/java/io/xpipe/app/browser/session/BrowserChooserModel.java +++ b/app/src/main/java/io/xpipe/app/browser/session/BrowserChooserModel.java @@ -103,5 +103,4 @@ public class BrowserChooserModel extends BrowserAbstractSessionModel v.getEntry().get()), applicable, action).vgrow(); + var bookmarksList = new BrowserBookmarkComp( + BindingsHelper.map( + model.getSelectedEntry(), v -> v.getEntry().get()), + applicable, + action) + .vgrow(); var localDownloadStage = new BrowserTransferComp(model.getLocalTransfersStage()) .hide(PlatformThread.sync(Bindings.createBooleanBinding( () -> { 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 7a34ea16b..931cb10d9 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 @@ -28,7 +28,6 @@ public class BrowserSessionModel extends BrowserAbstractSessionModel { return true; } - public void init() throws Exception { + public void init() throws Exception {} - } - - public void close() { - - } + public void close() {} } diff --git a/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionTabsComp.java b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionTabsComp.java index 6fe120f4c..ecce9a155 100644 --- a/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionTabsComp.java +++ b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionTabsComp.java @@ -72,7 +72,8 @@ public class BrowserSessionTabsComp extends SimpleComp { tabs.getTabs().add(t); }); tabs.getSelectionModel() - .select(model.getSessionEntries().indexOf(model.getSelectedEntry().getValue())); + .select(model.getSessionEntries() + .indexOf(model.getSelectedEntry().getValue())); // Used for ignoring changes by the tabpane when new tabs are added. We want to perform the selections manually! var modifying = new SimpleBooleanProperty(); diff --git a/app/src/main/java/io/xpipe/app/comp/AppLayoutComp.java b/app/src/main/java/io/xpipe/app/comp/AppLayoutComp.java index 2e38f5bf6..ca1991628 100644 --- a/app/src/main/java/io/xpipe/app/comp/AppLayoutComp.java +++ b/app/src/main/java/io/xpipe/app/comp/AppLayoutComp.java @@ -24,9 +24,14 @@ public class AppLayoutComp extends Comp> { @Override public CompStructure createBase() { - Map, ObservableValue> map = model.getEntries().stream().collect(Collectors.toMap(entry -> entry.comp(), entry -> Bindings.createBooleanBinding(() -> { - return model.getSelected().getValue().equals(entry); - }, model.getSelected()))); + Map, ObservableValue> map = model.getEntries().stream() + .collect(Collectors.toMap( + entry -> entry.comp(), + entry -> Bindings.createBooleanBinding( + () -> { + return model.getSelected().getValue().equals(entry); + }, + model.getSelected()))); var multi = new MultiContentComp(map); var pane = new BorderPane(); diff --git a/app/src/main/java/io/xpipe/app/comp/base/FontIconComp.java b/app/src/main/java/io/xpipe/app/comp/base/FontIconComp.java index 99742218b..462e05ca7 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/FontIconComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/FontIconComp.java @@ -2,7 +2,6 @@ package io.xpipe.app.comp.base; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; -import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.fxcomps.util.PlatformThread; import javafx.beans.property.SimpleStringProperty; import javafx.beans.value.ObservableValue; @@ -12,19 +11,7 @@ import lombok.Value; import org.kordamp.ikonli.javafx.FontIcon; @AllArgsConstructor -public class FontIconComp extends Comp { - - @Value - public static class Structure implements CompStructure { - - FontIcon icon; - StackPane pane; - - @Override - public StackPane get() { - return pane; - } - } +public class FontIconComp extends Comp { private final ObservableValue icon; @@ -45,4 +32,16 @@ public class FontIconComp extends Comp { var pane = new StackPane(fi); return new FontIconComp.Structure(fi, pane); } + + @Value + public static class Structure implements CompStructure { + + FontIcon icon; + StackPane pane; + + @Override + public StackPane get() { + return pane; + } + } } diff --git a/app/src/main/java/io/xpipe/app/comp/base/OsLogoComp.java b/app/src/main/java/io/xpipe/app/comp/base/OsLogoComp.java index ae0cebbd1..b54fd38cb 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/OsLogoComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/OsLogoComp.java @@ -53,9 +53,8 @@ public class OsLogoComp extends SimpleComp { wrapper.getPersistentState(), state); var hide = BindingsHelper.map(img, s -> s != null); - return new StackComp(List.of( - new SystemStateComp(state).hide(hide), - new PrettyImageComp(img, 24, 24).visible(hide))) + return new StackComp( + List.of(new SystemStateComp(state).hide(hide), new PrettyImageComp(img, 24, 24).visible(hide))) .createRegion(); } diff --git a/app/src/main/java/io/xpipe/app/comp/base/SideMenuBarComp.java b/app/src/main/java/io/xpipe/app/comp/base/SideMenuBarComp.java index 0187a58e9..91c7b7d11 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/SideMenuBarComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/SideMenuBarComp.java @@ -7,8 +7,8 @@ import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.SimpleCompStructure; import io.xpipe.app.fxcomps.augment.Augment; -import io.xpipe.app.fxcomps.impl.TooltipAugment; import io.xpipe.app.fxcomps.impl.IconButtonComp; +import io.xpipe.app.fxcomps.impl.TooltipAugment; import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.UserReportComp; diff --git a/app/src/main/java/io/xpipe/app/comp/base/ToggleSwitchComp.java b/app/src/main/java/io/xpipe/app/comp/base/ToggleSwitchComp.java index 69bfb3794..110897b1f 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/ToggleSwitchComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/ToggleSwitchComp.java @@ -22,7 +22,7 @@ public class ToggleSwitchComp extends SimpleComp { @Override protected Region createSimple() { var s = new ToggleSwitch(); - s.addEventFilter(KeyEvent.KEY_PRESSED,event -> { + s.addEventFilter(KeyEvent.KEY_PRESSED, event -> { if (event.getCode() == KeyCode.SPACE || event.getCode() == KeyCode.ENTER) { s.setSelected(!s.isSelected()); event.consume(); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java index c102b2ef3..dd2680d0e 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java @@ -95,7 +95,11 @@ public abstract class StoreEntryComp extends SimpleComp { wrapper.executeDefaultAction(); }); }); - new ContextMenuAugment<>(mouseEvent -> mouseEvent.getButton() == MouseButton.SECONDARY, null, () -> this.createContextMenu()).augment(button); + new ContextMenuAugment<>( + mouseEvent -> mouseEvent.getButton() == MouseButton.SECONDARY, + null, + () -> this.createContextMenu()) + .augment(button); var loading = LoadingOverlayComp.noProgress( Comp.of(() -> button), @@ -244,7 +248,9 @@ public abstract class StoreEntryComp extends SimpleComp { settingsButton.styleClass("settings"); settingsButton.accessibleText("More"); settingsButton.apply(new ContextMenuAugment<>( - event -> event.getButton() == MouseButton.PRIMARY, null, () -> StoreEntryComp.this.createContextMenu())); + event -> event.getButton() == MouseButton.PRIMARY, + null, + () -> StoreEntryComp.this.createContextMenu())); settingsButton.apply(new TooltipAugment<>("more")); return settingsButton; } diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListStatusComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListStatusComp.java index d2412f1bd..f667c6079 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListStatusComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListStatusComp.java @@ -5,9 +5,9 @@ import io.xpipe.app.core.AppFont; import io.xpipe.app.core.AppI18n; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.SimpleComp; -import io.xpipe.app.fxcomps.impl.TooltipAugment; import io.xpipe.app.fxcomps.impl.FilterComp; import io.xpipe.app.fxcomps.impl.IconButtonComp; +import io.xpipe.app.fxcomps.impl.TooltipAugment; import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.fxcomps.util.ListBindingsHelper; import io.xpipe.app.util.ThreadHelper; @@ -51,8 +51,12 @@ public class StoreEntryListStatusComp extends SimpleComp { private Region createGroupListHeader() { var label = new Label(); - var name = BindingsHelper.flatMap(StoreViewState.get().getActiveCategory(), - categoryWrapper -> AppI18n.observable(categoryWrapper.getRoot().equals(StoreViewState.get().getAllConnectionsCategory()) ? "connections" : "scripts")); + var name = BindingsHelper.flatMap( + StoreViewState.get().getActiveCategory(), + categoryWrapper -> AppI18n.observable( + categoryWrapper.getRoot().equals(StoreViewState.get().getAllConnectionsCategory()) + ? "connections" + : "scripts")); label.textProperty().bind(name); label.getStyleClass().add("name"); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreIntroComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreIntroComp.java index 2a942412e..bc7689cd7 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreIntroComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreIntroComp.java @@ -46,9 +46,7 @@ public class StoreIntroComp extends SimpleComp { hbox.setSpacing(35); hbox.setAlignment(Pos.CENTER); - var v = new VBox( - hbox, scanPane - ); + var v = new VBox(hbox, scanPane); v.setMinWidth(Region.USE_PREF_SIZE); v.setMaxWidth(Region.USE_PREF_SIZE); v.setMinHeight(Region.USE_PREF_SIZE); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreQuickAccessButtonComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreQuickAccessButtonComp.java index 77a81cbfc..44e35a972 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreQuickAccessButtonComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreQuickAccessButtonComp.java @@ -42,7 +42,9 @@ public class StoreQuickAccessButtonComp extends Comp> { var graphic = w.getEntry().getProvider().getDisplayIconFileName(w.getEntry().getStore()); if (c.isEmpty()) { - var item = ContextMenuHelper.item(PrettyImageHelper.ofFixedSizeSquare(graphic, 16), w.getName().getValue()); + var item = ContextMenuHelper.item( + PrettyImageHelper.ofFixedSizeSquare(graphic, 16), + w.getName().getValue()); item.setOnAction(event -> { action.accept(w); contextMenu.hide(); @@ -83,7 +85,7 @@ public class StoreQuickAccessButtonComp extends Comp> { } struc.get().setOnAction(event -> { - ContextMenuHelper.toggleShow(cm,struc.get(), Side.RIGHT); + ContextMenuHelper.toggleShow(cm, struc.get(), Side.RIGHT); event.consume(); }); }); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreSection.java b/app/src/main/java/io/xpipe/app/comp/store/StoreSection.java index c2939b9ac..68d050b44 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreSection.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreSection.java @@ -94,7 +94,9 @@ public class StoreSection { }, category); var cached = ListBindingsHelper.cachedMappedContentBinding( - topLevel, topLevel, storeEntryWrapper -> create(storeEntryWrapper, 1, all, entryFilter, filterString, category)); + topLevel, + topLevel, + storeEntryWrapper -> create(storeEntryWrapper, 1, all, entryFilter, filterString, category)); var ordered = sorted(cached, category); var shown = ListBindingsHelper.filteredContentBinding( ordered, @@ -133,7 +135,9 @@ public class StoreSection { return DataStorage.get().getStoreChildren(e.getEntry()).contains(other.getEntry()); }); var cached = ListBindingsHelper.cachedMappedContentBinding( - allChildren, allChildren, entry1 -> create(entry1, depth + 1, all, entryFilter, filterString, category)); + allChildren, + allChildren, + entry1 -> create(entry1, depth + 1, all, entryFilter, filterString, category)); var ordered = sorted(cached, category); var filtered = ListBindingsHelper.filteredContentBinding( ordered, diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreViewState.java b/app/src/main/java/io/xpipe/app/comp/store/StoreViewState.java index f08b2e4ad..84f9816a2 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreViewState.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreViewState.java @@ -270,7 +270,9 @@ public class StoreViewState { return parent; } - return o1.nameProperty().getValue().compareToIgnoreCase(o2.nameProperty().getValue()); + return o1.nameProperty() + .getValue() + .compareToIgnoreCase(o2.nameProperty().getValue()); } }; return ListBindingsHelper.filteredContentBinding( diff --git a/app/src/main/java/io/xpipe/app/core/AppExtensionManager.java b/app/src/main/java/io/xpipe/app/core/AppExtensionManager.java index 8b58139a2..d198685bc 100644 --- a/app/src/main/java/io/xpipe/app/core/AppExtensionManager.java +++ b/app/src/main/java/io/xpipe/app/core/AppExtensionManager.java @@ -49,7 +49,7 @@ public class AppExtensionManager { if (load) { try { ProcessControlProvider.init(INSTANCE.extendedLayer); - ModuleLayerLoader.loadAll(INSTANCE.extendedLayer, t -> { + ModuleLayerLoader.loadAll(INSTANCE.extendedLayer, t -> { ErrorEvent.fromThrowable(t).handle(); }); } catch (Throwable t) { diff --git a/app/src/main/java/io/xpipe/app/core/AppI18n.java b/app/src/main/java/io/xpipe/app/core/AppI18n.java index 3bac061ed..cfef3e554 100644 --- a/app/src/main/java/io/xpipe/app/core/AppI18n.java +++ b/app/src/main/java/io/xpipe/app/core/AppI18n.java @@ -34,18 +34,10 @@ import java.util.regex.Pattern; public class AppI18n { - @Value - static class LoadedTranslations { - - Map translations; - Map markdownDocumentations; - PrettyTime prettyTime; - } - private static final Pattern VAR_PATTERN = Pattern.compile("\\$\\w+?\\$"); private static AppI18n INSTANCE; - private LoadedTranslations english; private final Property currentLanguage = new SimpleObjectProperty<>(); + private LoadedTranslations english; public static void init() throws Exception { if (INSTANCE == null) { @@ -54,39 +46,21 @@ public class AppI18n { INSTANCE.load(); } - private void load() throws Exception { - if (english == null) { - english = load(Locale.ENGLISH); - } - - if (AppPrefs.get() != null) { - AppPrefs.get().language().subscribe(n -> { - try { - currentLanguage.setValue(n != null ? load(n.getLocale()) : null); - } catch (Exception e) { - ErrorEvent.fromThrowable(e).handle(); - } - }); - } - } - public static AppI18n get() { return INSTANCE; } - private LoadedTranslations getLoaded() { - return currentLanguage.getValue() != null ? currentLanguage.getValue() : english; - } - public static ObservableValue observable(String s, Object... vars) { if (s == null) { return null; } var key = INSTANCE.getKey(s); - return Bindings.createStringBinding(() -> { - return get(key, vars); - }, INSTANCE.currentLanguage); + return Bindings.createStringBinding( + () -> { + return get(key, vars); + }, + INSTANCE.currentLanguage); } public static String get(String s, Object... vars) { @@ -131,6 +105,26 @@ public class AppI18n { return ""; } + private void load() throws Exception { + if (english == null) { + english = load(Locale.ENGLISH); + } + + if (AppPrefs.get() != null) { + AppPrefs.get().language().subscribe(n -> { + try { + currentLanguage.setValue(n != null ? load(n.getLocale()) : null); + } catch (Exception e) { + ErrorEvent.fromThrowable(e).handle(); + } + }); + } + } + + private LoadedTranslations getLoaded() { + return currentLanguage.getValue() != null ? currentLanguage.getValue() : english; + } + public String getKey(String s) { var key = s; if (!s.contains(".")) { @@ -147,7 +141,8 @@ public class AppI18n { return s; } - if (currentLanguage.getValue() != null && currentLanguage.getValue().getTranslations().containsKey(key)) { + if (currentLanguage.getValue() != null + && currentLanguage.getValue().getTranslations().containsKey(key)) { var localisedString = currentLanguage.getValue().getTranslations().get(key); return getValue(localisedString, vars); } @@ -168,8 +163,10 @@ public class AppI18n { } public String getMarkdownDocumentation(String name) { - if (currentLanguage.getValue() != null && currentLanguage.getValue().getMarkdownDocumentations().containsKey(name)) { - var localisedString = currentLanguage.getValue().getMarkdownDocumentations().get(name); + if (currentLanguage.getValue() != null + && currentLanguage.getValue().getMarkdownDocumentations().containsKey(name)) { + var localisedString = + currentLanguage.getValue().getMarkdownDocumentations().get(name); return localisedString; } @@ -192,81 +189,83 @@ public class AppI18n { var translations = new HashMap(); for (var module : AppExtensionManager.getInstance().getContentModules()) { - var basePath = getModuleLangPath(FilenameUtils.getExtension(module.getName())).resolve("strings"); - if (!Files.exists(basePath)) { - continue; - } + var basePath = getModuleLangPath(FilenameUtils.getExtension(module.getName())) + .resolve("strings"); + if (!Files.exists(basePath)) { + continue; + } - AtomicInteger fileCounter = new AtomicInteger(); - AtomicInteger lineCounter = new AtomicInteger(); - var simpleName = FilenameUtils.getExtension(module.getName()); - String defaultPrefix = simpleName.equals("app") ? "app." : simpleName + "."; - Files.walkFileTree(basePath, new SimpleFileVisitor<>() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { - if (!matchesLocale(file, l)) { - return FileVisitResult.CONTINUE; - } - - if (!file.getFileName().toString().endsWith(".properties")) { - return FileVisitResult.CONTINUE; - } - - fileCounter.incrementAndGet(); - try (var in = Files.newInputStream(file)) { - var props = new Properties(); - props.load(new InputStreamReader(in, StandardCharsets.UTF_8)); - props.forEach((key, value) -> { - var hasPrefix = key.toString().contains("."); - var usedPrefix = hasPrefix ? "" : defaultPrefix; - translations.put(usedPrefix + key, value.toString()); - lineCounter.incrementAndGet(); - }); - } catch (IOException ex) { - ErrorEvent.fromThrowable(ex).omitted(true).build().handle(); - } + AtomicInteger fileCounter = new AtomicInteger(); + AtomicInteger lineCounter = new AtomicInteger(); + var simpleName = FilenameUtils.getExtension(module.getName()); + String defaultPrefix = simpleName.equals("app") ? "app." : simpleName + "."; + Files.walkFileTree(basePath, new SimpleFileVisitor<>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + if (!matchesLocale(file, l)) { return FileVisitResult.CONTINUE; } - }); - TrackEvent.withDebug("Loading translations for module " + simpleName) - .tag("fileCount", fileCounter.get()) - .tag("lineCount", lineCounter.get()) - .handle(); + if (!file.getFileName().toString().endsWith(".properties")) { + return FileVisitResult.CONTINUE; + } + + fileCounter.incrementAndGet(); + try (var in = Files.newInputStream(file)) { + var props = new Properties(); + props.load(new InputStreamReader(in, StandardCharsets.UTF_8)); + props.forEach((key, value) -> { + var hasPrefix = key.toString().contains("."); + var usedPrefix = hasPrefix ? "" : defaultPrefix; + translations.put(usedPrefix + key, value.toString()); + lineCounter.incrementAndGet(); + }); + } catch (IOException ex) { + ErrorEvent.fromThrowable(ex).omitted(true).build().handle(); + } + return FileVisitResult.CONTINUE; + } + }); + + TrackEvent.withDebug("Loading translations for module " + simpleName) + .tag("fileCount", fileCounter.get()) + .tag("lineCount", lineCounter.get()) + .handle(); } var markdownDocumentations = new HashMap(); for (var module : AppExtensionManager.getInstance().getContentModules()) { - var basePath = getModuleLangPath(FilenameUtils.getExtension(module.getName())).resolve("texts"); - if (!Files.exists(basePath)) { - continue; - } + var basePath = getModuleLangPath(FilenameUtils.getExtension(module.getName())) + .resolve("texts"); + if (!Files.exists(basePath)) { + continue; + } - var moduleName = FilenameUtils.getExtension(module.getName()); - Files.walkFileTree(basePath, new SimpleFileVisitor<>() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { - if (!matchesLocale(file, l)) { - return FileVisitResult.CONTINUE; - } - - if (!file.getFileName().toString().endsWith(".md")) { - return FileVisitResult.CONTINUE; - } - - var name = file.getFileName() - .toString() - .substring(0, file.getFileName().toString().lastIndexOf("_")); - try (var in = Files.newInputStream(file)) { - var usedPrefix = moduleName + ":"; - markdownDocumentations.put( - usedPrefix + name, new String(in.readAllBytes(), StandardCharsets.UTF_8)); - } catch (IOException ex) { - ErrorEvent.fromThrowable(ex).omitted(true).build().handle(); - } + var moduleName = FilenameUtils.getExtension(module.getName()); + Files.walkFileTree(basePath, new SimpleFileVisitor<>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + if (!matchesLocale(file, l)) { return FileVisitResult.CONTINUE; } - }); + + if (!file.getFileName().toString().endsWith(".md")) { + return FileVisitResult.CONTINUE; + } + + var name = file.getFileName() + .toString() + .substring(0, file.getFileName().toString().lastIndexOf("_")); + try (var in = Files.newInputStream(file)) { + var usedPrefix = moduleName + ":"; + markdownDocumentations.put( + usedPrefix + name, new String(in.readAllBytes(), StandardCharsets.UTF_8)); + } catch (IOException ex) { + ErrorEvent.fromThrowable(ex).omitted(true).build().handle(); + } + return FileVisitResult.CONTINUE; + } + }); } var prettyTime = new PrettyTime( @@ -274,7 +273,15 @@ public class AppI18n { ? AppPrefs.get().language().getValue().getLocale() : SupportedLocale.getEnglish().getLocale()); - return new LoadedTranslations(translations,markdownDocumentations, prettyTime); + return new LoadedTranslations(translations, markdownDocumentations, prettyTime); + } + + @Value + static class LoadedTranslations { + + Map translations; + Map markdownDocumentations; + PrettyTime prettyTime; } @SuppressWarnings("removal") diff --git a/app/src/main/java/io/xpipe/app/core/AppLayoutModel.java b/app/src/main/java/io/xpipe/app/core/AppLayoutModel.java index dbe70cb2b..ccfad3989 100644 --- a/app/src/main/java/io/xpipe/app/core/AppLayoutModel.java +++ b/app/src/main/java/io/xpipe/app/core/AppLayoutModel.java @@ -71,7 +71,10 @@ public class AppLayoutModel { private List createEntryList() { var l = new ArrayList<>(List.of( - new Entry(AppI18n.observable("browser"), "mdi2f-file-cabinet", new BrowserSessionComp(BrowserSessionModel.DEFAULT)), + new Entry( + AppI18n.observable("browser"), + "mdi2f-file-cabinet", + new BrowserSessionComp(BrowserSessionModel.DEFAULT)), new Entry(AppI18n.observable("connections"), "mdi2c-connection", new StoreLayoutComp()), new Entry(AppI18n.observable("settings"), "mdsmz-miscellaneous_services", new AppPrefsComp()), new Entry( 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 fcf698860..548efe347 100644 --- a/app/src/main/java/io/xpipe/app/core/AppTheme.java +++ b/app/src/main/java/io/xpipe/app/core/AppTheme.java @@ -48,7 +48,8 @@ public class AppTheme { Runnable r = () -> { AppPrefs.get().theme.subscribe(t -> { - Theme.ALL.forEach(theme -> stage.getScene().getRoot().getStyleClass().remove(theme.getCssId())); + Theme.ALL.forEach( + theme -> stage.getScene().getRoot().getStyleClass().remove(theme.getCssId())); if (t == null) { return; } @@ -88,7 +89,7 @@ public class AppTheme { var c = new WindowControl(stage); c.setWindowAttribute(20, AppPrefs.get().theme.getValue().isDark()); stage.setWidth(stage.getWidth() + 1); - Platform.runLater( () -> { + Platform.runLater(() -> { stage.setWidth(stage.getWidth() - 1); }); } catch (Throwable e) { @@ -105,11 +106,11 @@ public class AppTheme { AppPrefs.get().theme.addListener((observable, oldValue, newValue) -> { Platform.runLater(() -> { - var transition = new PauseTransition(Duration.millis(300)); - transition.setOnFinished(e -> { - windowTheme.handle(null); - }); - transition.play(); + var transition = new PauseTransition(Duration.millis(300)); + transition.setOnFinished(e -> { + windowTheme.handle(null); + }); + transition.play(); }); }); } diff --git a/app/src/main/java/io/xpipe/app/core/AppWindowHelper.java b/app/src/main/java/io/xpipe/app/core/AppWindowHelper.java index 55f48185d..d2f1895ac 100644 --- a/app/src/main/java/io/xpipe/app/core/AppWindowHelper.java +++ b/app/src/main/java/io/xpipe/app/core/AppWindowHelper.java @@ -53,11 +53,12 @@ public class AppWindowHelper { // This allows for assigning logos even if AppImages has not been initialized yet var dir = OsType.getLocal() == OsType.MACOS ? "img/logo/padded" : "img/logo/full"; AppResources.with(AppResources.XPIPE_MODULE, dir, path -> { - var size = switch (OsType.getLocal()) { - case OsType.Linux linux -> 128; - case OsType.MacOs macOs -> 128; - case OsType.Windows windows -> 32; - }; + var size = + switch (OsType.getLocal()) { + case OsType.Linux linux -> 128; + case OsType.MacOs macOs -> 128; + case OsType.Windows windows -> 32; + }; stage.getIcons().add(AppImages.loadImage(path.resolve("logo_" + size + "x" + size + ".png"))); }); } diff --git a/app/src/main/java/io/xpipe/app/core/check/AppFontLoadingCheck.java b/app/src/main/java/io/xpipe/app/core/check/AppFontLoadingCheck.java index f2bce53fa..d3812b757 100644 --- a/app/src/main/java/io/xpipe/app/core/check/AppFontLoadingCheck.java +++ b/app/src/main/java/io/xpipe/app/core/check/AppFontLoadingCheck.java @@ -13,7 +13,8 @@ public class AppFontLoadingCheck { // This can fail if the found system fonts can somehow not be loaded Font.getDefault(); } catch (Throwable e) { - var event = ErrorEvent.fromThrowable("Unable to load fonts. Do you have valid font packages installed?", e).build(); + var event = ErrorEvent.fromThrowable("Unable to load fonts. Do you have valid font packages installed?", e) + .build(); // We can't use the normal error handling facility // as the platform reports as working but opening windows still does not work new LogErrorHandler().handle(event); diff --git a/app/src/main/java/io/xpipe/app/exchange/LaunchExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/LaunchExchangeImpl.java index 3ecbce070..a7dfb5a7c 100644 --- a/app/src/main/java/io/xpipe/app/exchange/LaunchExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/exchange/LaunchExchangeImpl.java @@ -15,9 +15,9 @@ public class LaunchExchangeImpl extends LaunchExchange public Response handleRequest(BeaconHandler handler, Request msg) throws Exception { var store = getStoreEntryById(msg.getId(), false); if (store.getStore() instanceof LaunchableStore s) { -// var command = s.prepareLaunchCommand() -// .prepareTerminalOpen(TerminalInitScriptConfig.ofName(store.getName()), sc -> null); -// return Response.builder().command(split(command)).build(); + // var command = s.prepareLaunchCommand() + // .prepareTerminalOpen(TerminalInitScriptConfig.ofName(store.getName()), sc -> null); + // return Response.builder().command(split(command)).build(); } throw new IllegalArgumentException(store.getName() + " is not launchable"); diff --git a/app/src/main/java/io/xpipe/app/exchange/MessageExchangeImpls.java b/app/src/main/java/io/xpipe/app/exchange/MessageExchangeImpls.java index 3b113bfe0..94a18b15b 100644 --- a/app/src/main/java/io/xpipe/app/exchange/MessageExchangeImpls.java +++ b/app/src/main/java/io/xpipe/app/exchange/MessageExchangeImpls.java @@ -12,6 +12,28 @@ import java.util.stream.Collectors; public class MessageExchangeImpls { + private static List> ALL; + + @SuppressWarnings("unchecked") + public static Optional> byId( + String name) { + var r = ALL.stream().filter(d -> d.getId().equals(name)).findAny(); + return Optional.ofNullable((MessageExchangeImpl) r.orElse(null)); + } + + @SuppressWarnings("unchecked") + public static + Optional> byRequest(RQ req) { + var r = ALL.stream() + .filter(d -> d.getRequestClass().equals(req.getClass())) + .findAny(); + return Optional.ofNullable((MessageExchangeImpl) r.orElse(null)); + } + + public static List> getAll() { + return ALL; + } + public static class Loader implements ModuleLayerLoader { @Override @@ -36,27 +58,4 @@ public class MessageExchangeImpls { }); } } - - private static List> ALL; - - - @SuppressWarnings("unchecked") - public static Optional> byId( - String name) { - var r = ALL.stream().filter(d -> d.getId().equals(name)).findAny(); - return Optional.ofNullable((MessageExchangeImpl) r.orElse(null)); - } - - @SuppressWarnings("unchecked") - public static - Optional> byRequest(RQ req) { - var r = ALL.stream() - .filter(d -> d.getRequestClass().equals(req.getClass())) - .findAny(); - return Optional.ofNullable((MessageExchangeImpl) r.orElse(null)); - } - - public static List> getAll() { - return ALL; - } } diff --git a/app/src/main/java/io/xpipe/app/ext/ActionProvider.java b/app/src/main/java/io/xpipe/app/ext/ActionProvider.java index 8fafc49ef..e08ccf72f 100644 --- a/app/src/main/java/io/xpipe/app/ext/ActionProvider.java +++ b/app/src/main/java/io/xpipe/app/ext/ActionProvider.java @@ -143,6 +143,5 @@ public interface ActionProvider { }) .toList()); } - } } diff --git a/app/src/main/java/io/xpipe/app/ext/DataStoreProviders.java b/app/src/main/java/io/xpipe/app/ext/DataStoreProviders.java index de5a12349..7b62155f1 100644 --- a/app/src/main/java/io/xpipe/app/ext/DataStoreProviders.java +++ b/app/src/main/java/io/xpipe/app/ext/DataStoreProviders.java @@ -14,37 +14,6 @@ import java.util.stream.Collectors; public class DataStoreProviders { - public static class Loader implements ModuleLayerLoader { - - @Override - public void init(ModuleLayer layer) { - TrackEvent.info("Loading extension providers ..."); - ALL = ServiceLoader.load(layer, DataStoreProvider.class).stream().map(ServiceLoader.Provider::get).collect(Collectors.toList()); - ALL.removeIf(p -> { - try { - if (!p.init()) { - return true; - } - - p.validate(); - return false; - } catch (Throwable e) { - ErrorEvent.fromThrowable(e).handle(); - return true; - } - }); - - for (DataStoreProvider p : getAll()) { - TrackEvent.trace("Loaded data store provider " + p.getId()); - JacksonMapper.configure(objectMapper -> { - for (Class storeClass : p.getStoreClasses()) { - objectMapper.registerSubtypes(new NamedType(storeClass)); - } - }); - } - } - } - private static List ALL; public static void postInit(ModuleLayer layer) { @@ -100,4 +69,37 @@ public class DataStoreProviders { public static List getAll() { return ALL; } + + public static class Loader implements ModuleLayerLoader { + + @Override + public void init(ModuleLayer layer) { + TrackEvent.info("Loading extension providers ..."); + ALL = ServiceLoader.load(layer, DataStoreProvider.class).stream() + .map(ServiceLoader.Provider::get) + .collect(Collectors.toList()); + ALL.removeIf(p -> { + try { + if (!p.init()) { + return true; + } + + p.validate(); + return false; + } catch (Throwable e) { + ErrorEvent.fromThrowable(e).handle(); + return true; + } + }); + + for (DataStoreProvider p : getAll()) { + TrackEvent.trace("Loaded data store provider " + p.getId()); + JacksonMapper.configure(objectMapper -> { + for (Class storeClass : p.getStoreClasses()) { + objectMapper.registerSubtypes(new NamedType(storeClass)); + } + }); + } + } + } } diff --git a/app/src/main/java/io/xpipe/app/ext/PrefsChoiceValue.java b/app/src/main/java/io/xpipe/app/ext/PrefsChoiceValue.java index cd611df51..e42f70bd2 100644 --- a/app/src/main/java/io/xpipe/app/ext/PrefsChoiceValue.java +++ b/app/src/main/java/io/xpipe/app/ext/PrefsChoiceValue.java @@ -36,9 +36,7 @@ public interface PrefsChoiceValue extends Translatable { throw new AssertionError(); } - return all.stream() - .filter(t -> ((PrefsChoiceValue) t).isSelectable()) - .toList(); + return all.stream().filter(t -> ((PrefsChoiceValue) t).isSelectable()).toList(); } default boolean isAvailable() { diff --git a/app/src/main/java/io/xpipe/app/ext/PrefsProvider.java b/app/src/main/java/io/xpipe/app/ext/PrefsProvider.java index 9dff06ccf..d1b8433f1 100644 --- a/app/src/main/java/io/xpipe/app/ext/PrefsProvider.java +++ b/app/src/main/java/io/xpipe/app/ext/PrefsProvider.java @@ -34,6 +34,5 @@ public abstract class PrefsProvider { .map(ServiceLoader.Provider::get) .collect(Collectors.toList()); } - } } 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 d7b811d09..671b8cc8c 100644 --- a/app/src/main/java/io/xpipe/app/ext/ScanProvider.java +++ b/app/src/main/java/io/xpipe/app/ext/ScanProvider.java @@ -62,6 +62,5 @@ public abstract class ScanProvider { scanProvider -> scanProvider.getClass().getName())) .collect(Collectors.toList()); } - } } diff --git a/app/src/main/java/io/xpipe/app/fxcomps/augment/ContextMenuAugment.java b/app/src/main/java/io/xpipe/app/fxcomps/augment/ContextMenuAugment.java index 8198cd69a..66993e53f 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/augment/ContextMenuAugment.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/augment/ContextMenuAugment.java @@ -18,7 +18,10 @@ public class ContextMenuAugment> implements Augment keyEventCheck; private final Supplier contextMenu; - public ContextMenuAugment(Predicate mouseEventCheck, Predicate keyEventCheck, Supplier contextMenu) { + public ContextMenuAugment( + Predicate mouseEventCheck, + Predicate keyEventCheck, + Supplier contextMenu) { this.mouseEventCheck = mouseEventCheck; this.keyEventCheck = keyEventCheck; this.contextMenu = contextMenu; diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/ContextualFileReferenceChoiceComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/ContextualFileReferenceChoiceComp.java index b9191cd95..1921ea75b 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/ContextualFileReferenceChoiceComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/ContextualFileReferenceChoiceComp.java @@ -53,16 +53,19 @@ public class ContextualFileReferenceChoiceComp extends Comp> .grow(false, true); var fileBrowseButton = new ButtonComp(null, new FontIcon("mdi2f-folder-open-outline"), () -> { - BrowserChooserComp.openSingleFile(() -> fileSystem.getValue(), fileStore -> { - if (fileStore == null) { - filePath.setValue(null); - fileSystem.setValue(null); - } else { - filePath.setValue(fileStore.getPath()); - fileSystem.setValue(fileStore.getFileSystem()); - } - }, false); - }) + BrowserChooserComp.openSingleFile( + () -> fileSystem.getValue(), + fileStore -> { + if (fileStore == null) { + filePath.setValue(null); + fileSystem.setValue(null); + } else { + filePath.setValue(fileStore.getPath()); + fileSystem.setValue(fileStore.getFileSystem()); + } + }, + false); + }) .styleClass(Styles.CENTER_PILL) .grow(false, true); @@ -85,7 +88,8 @@ public class ContextualFileReferenceChoiceComp extends Comp> return; } - if (filePath.getValue() == null || ContextualFileReference.of(filePath.getValue()).isInDataDirectory()) { + if (filePath.getValue() == null + || ContextualFileReference.of(filePath.getValue()).isInDataDirectory()) { return; } diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/LabelComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/LabelComp.java index 3556f7712..da1a559ad 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/LabelComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/LabelComp.java @@ -3,7 +3,6 @@ package io.xpipe.app.fxcomps.impl; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.SimpleCompStructure; -import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.fxcomps.util.PlatformThread; import javafx.beans.property.SimpleStringProperty; import javafx.beans.value.ObservableValue; diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/StoreCategoryComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/StoreCategoryComp.java index 6620ec31c..41c777c71 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/StoreCategoryComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/StoreCategoryComp.java @@ -71,11 +71,12 @@ public class StoreCategoryComp extends SimpleComp { var showing = new SimpleBooleanProperty(); var settings = new IconButtonComp("mdomz-settings") .styleClass("settings") - .apply(new ContextMenuAugment<>(mouseEvent -> mouseEvent.getButton() == MouseButton.PRIMARY, null, () -> { - var cm = createContextMenu(name); - showing.bind(cm.showingProperty()); - return cm; - })); + .apply(new ContextMenuAugment<>( + mouseEvent -> mouseEvent.getButton() == MouseButton.PRIMARY, null, () -> { + var cm = createContextMenu(name); + showing.bind(cm.showingProperty()); + return cm; + })); var shownList = ListBindingsHelper.filteredContentBinding( category.getContainedEntries(), storeEntryWrapper -> { @@ -102,11 +103,13 @@ public class StoreCategoryComp extends SimpleComp { .accessibleText(category.nameProperty()) .grow(true, false); categoryButton.apply(new ContextMenuAugment<>( - mouseEvent -> mouseEvent.getButton() == MouseButton.SECONDARY, keyEvent -> keyEvent.getCode() == KeyCode.SPACE, () -> createContextMenu(name))); + mouseEvent -> mouseEvent.getButton() == MouseButton.SECONDARY, + keyEvent -> keyEvent.getCode() == KeyCode.SPACE, + () -> createContextMenu(name))); var l = category.getChildren() - .sorted(Comparator.comparing( - storeCategoryWrapper -> storeCategoryWrapper.nameProperty().getValue().toLowerCase(Locale.ROOT))); + .sorted(Comparator.comparing(storeCategoryWrapper -> + storeCategoryWrapper.nameProperty().getValue().toLowerCase(Locale.ROOT))); var children = new ListBoxViewComp<>(l, l, storeCategoryWrapper -> new StoreCategoryComp(storeCategoryWrapper)); var emptyBinding = Bindings.isEmpty(category.getChildren()); diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/StringSourceComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/StringSourceComp.java index 5bff3c19b..166d47090 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/StringSourceComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/StringSourceComp.java @@ -17,7 +17,8 @@ public class StringSourceComp extends SimpleComp { private final Property> fileSystem; private final Property stringSource; - public StringSourceComp(ObservableValue> fileSystem, Property stringSource) { + public StringSourceComp( + ObservableValue> fileSystem, Property stringSource) { this.stringSource = stringSource; this.fileSystem = new SimpleObjectProperty<>(); fileSystem.subscribe(val -> { @@ -27,9 +28,13 @@ public class StringSourceComp extends SimpleComp { @Override protected Region createSimple() { - var inPlace = new SimpleObjectProperty<>(stringSource.getValue() instanceof StringSource.InPlace i ? i.get() : null); + var inPlace = + new SimpleObjectProperty<>(stringSource.getValue() instanceof StringSource.InPlace i ? i.get() : null); var fs = stringSource.getValue() instanceof StringSource.File f ? f.getFile() : null; - var file = new SimpleObjectProperty<>(stringSource.getValue() instanceof StringSource.File f ? f.getFile().serialize() : null); + var file = new SimpleObjectProperty<>( + stringSource.getValue() instanceof StringSource.File f + ? f.getFile().serialize() + : null); var showText = new SimpleBooleanProperty(inPlace.get() != null); var stringField = new TextAreaComp(inPlace); @@ -39,8 +44,9 @@ public class StringSourceComp extends SimpleComp { var tr = stringField.createRegion(); var button = new IconButtonComp("mdi2c-checkbox-marked-outline", () -> { - showText.set(!showText.getValue()); - }).createRegion(); + showText.set(!showText.getValue()); + }) + .createRegion(); AnchorPane.setBottomAnchor(button, 10.0); AnchorPane.setRightAnchor(button, 10.0); var anchorPane = new AnchorPane(tr, button); 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 8e745e31d..10847b188 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 @@ -68,7 +68,7 @@ public class SvgView { wv.setDisable(true); wv.getEngine().loadContent(svgContent.getValue() != null ? getHtml(svgContent.getValue()) : null); - svgContent.subscribe( n -> { + svgContent.subscribe(n -> { if (n == null) { wv.setOpacity(0.0); return; diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/TooltipAugment.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/TooltipAugment.java index 4301445a9..2c681be7f 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/TooltipAugment.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/TooltipAugment.java @@ -22,29 +22,19 @@ public class TooltipAugment> implements Augment { this.text = AppI18n.observable(key); } - private static class FixedTooltip extends Tooltip { - - public FixedTooltip() { - super(); - } - - @Override - protected void show() { - Window owner = getOwnerWindow(); - if (owner.isFocused()) - super.show(); - } - } - @Override public void augment(S struc) { var region = struc.get(); var tt = new FixedTooltip(); if (Shortcuts.getDisplayShortcut(region) != null) { var s = AppI18n.observable("shortcut"); - var binding = Bindings.createStringBinding(() -> { - return text.getValue() + "\n\n" + s.getValue() + ": " + Shortcuts.getDisplayShortcut(region).getDisplayText(); - }, text, s); + var binding = Bindings.createStringBinding( + () -> { + return text.getValue() + "\n\n" + s.getValue() + ": " + + Shortcuts.getDisplayShortcut(region).getDisplayText(); + }, + text, + s); tt.textProperty().bind(binding); } else { tt.textProperty().bind(text); @@ -56,4 +46,17 @@ public class TooltipAugment> implements Augment { Tooltip.install(struc.get(), tt); } + + private static class FixedTooltip extends Tooltip { + + public FixedTooltip() { + super(); + } + + @Override + protected void show() { + Window owner = getOwnerWindow(); + if (owner.isFocused()) super.show(); + } + } } 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 7dd26404a..87adc1579 100644 --- a/app/src/main/java/io/xpipe/app/launcher/LauncherInput.java +++ b/app/src/main/java/io/xpipe/app/launcher/LauncherInput.java @@ -119,7 +119,8 @@ public abstract class LauncherInput { var dir = Files.isDirectory(file) ? file : file.getParent(); AppLayoutModel.get().selectBrowser(); - BrowserSessionModel.DEFAULT.openFileSystemAsync(DataStorage.get().local().ref(), model -> dir.toString(), null); + BrowserSessionModel.DEFAULT.openFileSystemAsync( + DataStorage.get().local().ref(), model -> dir.toString(), null); } } diff --git a/app/src/main/java/io/xpipe/app/prefs/AppearanceCategory.java b/app/src/main/java/io/xpipe/app/prefs/AppearanceCategory.java index 99d880f46..09eb5645d 100644 --- a/app/src/main/java/io/xpipe/app/prefs/AppearanceCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/AppearanceCategory.java @@ -24,18 +24,6 @@ public class AppearanceCategory extends AppPrefsCategory { return "appearance"; } - private Comp languageChoice() { - var prefs = AppPrefs.get(); - var c = ChoiceComp.ofTranslatable(prefs.language, SupportedLocale.ALL, false); - var visit = new ButtonComp(AppI18n.observable("translate"), new FontIcon("mdi2w-web"), () -> { - Hyperlinks.open(Hyperlinks.TRANSLATE); - }); - return new HorizontalComp(List.of(c, visit)).apply(struc -> { - struc.get().setAlignment(Pos.CENTER_LEFT); - struc.get().setSpacing(10); - }); - } - @Override protected Comp create() { var prefs = AppPrefs.get(); @@ -43,9 +31,7 @@ public class AppearanceCategory extends AppPrefsCategory { .addTitle("uiOptions") .sub(new OptionsBuilder() .nameAndDescription("language") - .addComp( - languageChoice(), - prefs.language) + .addComp(languageChoice(), prefs.language) .nameAndDescription("theme") .addComp( ChoiceComp.ofTranslatable(prefs.theme, AppTheme.Theme.ALL, false) @@ -83,4 +69,16 @@ public class AppearanceCategory extends AppPrefsCategory { .addToggle(prefs.enforceWindowModality)) .buildComp(); } + + private Comp languageChoice() { + var prefs = AppPrefs.get(); + var c = ChoiceComp.ofTranslatable(prefs.language, SupportedLocale.ALL, false); + var visit = new ButtonComp(AppI18n.observable("translate"), new FontIcon("mdi2w-web"), () -> { + Hyperlinks.open(Hyperlinks.TRANSLATE); + }); + return new HorizontalComp(List.of(c, visit)).apply(struc -> { + struc.get().setAlignment(Pos.CENTER_LEFT); + struc.get().setSpacing(10); + }); + } } diff --git a/app/src/main/java/io/xpipe/app/prefs/ExternalEditorType.java b/app/src/main/java/io/xpipe/app/prefs/ExternalEditorType.java index a0a8f7b55..6c1827b83 100644 --- a/app/src/main/java/io/xpipe/app/prefs/ExternalEditorType.java +++ b/app/src/main/java/io/xpipe/app/prefs/ExternalEditorType.java @@ -106,8 +106,8 @@ public interface ExternalEditorType extends PrefsChoiceValue { var format = customCommand.toLowerCase(Locale.ROOT).contains("$file") ? customCommand : customCommand + " $FILE"; - ExternalApplicationHelper.startAsync( - CommandBuilder.of().add(ExternalApplicationHelper.replaceFileArgument(format, "FILE", file.toString()))); + ExternalApplicationHelper.startAsync(CommandBuilder.of() + .add(ExternalApplicationHelper.replaceFileArgument(format, "FILE", file.toString()))); } @Override @@ -199,11 +199,10 @@ public interface ExternalEditorType extends PrefsChoiceValue { throw new IOException("Application " + applicationName + ".app not found"); } - ExternalApplicationHelper.startAsync( - CommandBuilder.of() - .add("open", "-a") - .addFile(execFile.orElseThrow().toString()) - .addFile(file.toString())); + ExternalApplicationHelper.startAsync(CommandBuilder.of() + .add("open", "-a") + .addFile(execFile.orElseThrow().toString()) + .addFile(file.toString())); } } diff --git a/app/src/main/java/io/xpipe/app/prefs/ExternalRdpClientType.java b/app/src/main/java/io/xpipe/app/prefs/ExternalRdpClientType.java index 68f88a7a6..6969fe99d 100644 --- a/app/src/main/java/io/xpipe/app/prefs/ExternalRdpClientType.java +++ b/app/src/main/java/io/xpipe/app/prefs/ExternalRdpClientType.java @@ -14,44 +14,14 @@ import java.util.function.Supplier; public interface ExternalRdpClientType extends PrefsChoiceValue { - @Value - class LaunchConfiguration { - String title; - RdpConfig config; - UUID storeId; - SecretRetrievalStrategy password; - } - - abstract class PathCheckType extends ExternalApplicationType.PathApplication implements ExternalRdpClientType { - - public PathCheckType(String id, String executable, boolean explicityAsync) { - super(id, executable, explicityAsync); - } - } - - abstract class MacOsType extends ExternalApplicationType.MacApplication implements ExternalRdpClientType { - - public MacOsType(String id, String applicationName) { - super(id, applicationName); - } - } - - void launch(LaunchConfiguration configuration) throws Exception; - - default Path writeConfig(RdpConfig input) throws Exception { - var file = LocalShell.getShell().getSystemTemporaryDirectory().join("exec-" + ScriptHelper.getScriptId() + ".rdp"); - var string = input.toString(); - Files.writeString(file.toLocalPath(), string); - return file.toLocalPath(); - } - ExternalRdpClientType MSTSC = new PathCheckType("app.mstsc", "mstsc.exe", true) { @Override public void launch(LaunchConfiguration configuration) throws Exception { var adaptedRdpConfig = getAdaptedConfig(configuration); var file = writeConfig(adaptedRdpConfig); - LocalShell.getShell().executeSimpleCommand(CommandBuilder.of().add(executable).addFile(file.toString())); + LocalShell.getShell() + .executeSimpleCommand(CommandBuilder.of().add(executable).addFile(file.toString())); } private RdpConfig getAdaptedConfig(LaunchConfiguration configuration) throws Exception { @@ -85,28 +55,89 @@ public interface ExternalRdpClientType extends PrefsChoiceValue { return cmd.readStdoutOrThrow(); } }; - ExternalRdpClientType REMMINA = new PathCheckType("app.remmina", "remmina", true) { - @Override - public void launch(LaunchConfiguration configuration) throws Exception { - var file = writeConfig(configuration.getConfig()); - LocalShell.getShell().executeSimpleCommand(CommandBuilder.of().add(executable).add("-c").addFile(file.toString())); - } - }; - - ExternalRdpClientType MICROSOFT_REMOTE_DESKTOP_MACOS_APP = new MacOsType("app.microsoftRemoteDesktopApp", "Microsoft Remote Desktop.app") { - @Override public void launch(LaunchConfiguration configuration) throws Exception { var file = writeConfig(configuration.getConfig()); LocalShell.getShell() - .executeSimpleCommand(CommandBuilder.of() - .add("open", "-a") - .addQuoted("Microsoft Remote Desktop.app") - .addFile(file.toString())); + .executeSimpleCommand( + CommandBuilder.of().add(executable).add("-c").addFile(file.toString())); } }; + ExternalRdpClientType MICROSOFT_REMOTE_DESKTOP_MACOS_APP = + new MacOsType("app.microsoftRemoteDesktopApp", "Microsoft Remote Desktop.app") { + + @Override + public void launch(LaunchConfiguration configuration) throws Exception { + var file = writeConfig(configuration.getConfig()); + LocalShell.getShell() + .executeSimpleCommand(CommandBuilder.of() + .add("open", "-a") + .addQuoted("Microsoft Remote Desktop.app") + .addFile(file.toString())); + } + }; + ExternalRdpClientType CUSTOM = new CustomType(); + List WINDOWS_CLIENTS = List.of(MSTSC); + List LINUX_CLIENTS = List.of(REMMINA); + List MACOS_CLIENTS = List.of(MICROSOFT_REMOTE_DESKTOP_MACOS_APP); + @SuppressWarnings("TrivialFunctionalExpressionUsage") + List ALL = ((Supplier>) () -> { + var all = new ArrayList(); + if (OsType.getLocal().equals(OsType.WINDOWS)) { + all.addAll(WINDOWS_CLIENTS); + } + if (OsType.getLocal().equals(OsType.LINUX)) { + all.addAll(LINUX_CLIENTS); + } + if (OsType.getLocal().equals(OsType.MACOS)) { + all.addAll(MACOS_CLIENTS); + } + all.add(CUSTOM); + return all; + }) + .get(); + + static ExternalRdpClientType determineDefault() { + return ALL.stream() + .filter(t -> !t.equals(CUSTOM)) + .filter(t -> t.isAvailable()) + .findFirst() + .orElse(null); + } + + void launch(LaunchConfiguration configuration) throws Exception; + + default Path writeConfig(RdpConfig input) throws Exception { + var file = + LocalShell.getShell().getSystemTemporaryDirectory().join("exec-" + ScriptHelper.getScriptId() + ".rdp"); + var string = input.toString(); + Files.writeString(file.toLocalPath(), string); + return file.toLocalPath(); + } + + @Value + class LaunchConfiguration { + String title; + RdpConfig config; + UUID storeId; + SecretRetrievalStrategy password; + } + + abstract class PathCheckType extends ExternalApplicationType.PathApplication implements ExternalRdpClientType { + + public PathCheckType(String id, String executable, boolean explicityAsync) { + super(id, executable, explicityAsync); + } + } + + abstract class MacOsType extends ExternalApplicationType.MacApplication implements ExternalRdpClientType { + + public MacOsType(String id, String applicationName) { + super(id, applicationName); + } + } class CustomType extends ExternalApplicationType implements ExternalRdpClientType { @@ -121,8 +152,13 @@ public interface ExternalRdpClientType extends PrefsChoiceValue { throw ErrorEvent.expected(new IllegalStateException("No custom RDP command specified")); } - var format = customCommand.toLowerCase(Locale.ROOT).contains("$file") ? customCommand : customCommand + " $FILE"; - ExternalApplicationHelper.startAsync(CommandBuilder.of().add(ExternalApplicationHelper.replaceFileArgument(format, "FILE", writeConfig(configuration.getConfig()).toString()))); + var format = + customCommand.toLowerCase(Locale.ROOT).contains("$file") ? customCommand : customCommand + " $FILE"; + ExternalApplicationHelper.startAsync(CommandBuilder.of() + .add(ExternalApplicationHelper.replaceFileArgument( + format, + "FILE", + writeConfig(configuration.getConfig()).toString()))); } @Override @@ -130,34 +166,4 @@ public interface ExternalRdpClientType extends PrefsChoiceValue { return true; } } - - ExternalRdpClientType CUSTOM = new CustomType(); - - List WINDOWS_CLIENTS = List.of(MSTSC); - List LINUX_CLIENTS = List.of(REMMINA); - List MACOS_CLIENTS = List.of(MICROSOFT_REMOTE_DESKTOP_MACOS_APP); - - @SuppressWarnings("TrivialFunctionalExpressionUsage") - List ALL = ((Supplier>) () -> { - var all = new ArrayList(); - if (OsType.getLocal().equals(OsType.WINDOWS)) { - all.addAll(WINDOWS_CLIENTS); - } - if (OsType.getLocal().equals(OsType.LINUX)) { - all.addAll(LINUX_CLIENTS); - } - if (OsType.getLocal().equals(OsType.MACOS)) { - all.addAll(MACOS_CLIENTS); - } - all.add(CUSTOM); - return all; - }).get(); - - static ExternalRdpClientType determineDefault() { - return ALL.stream() - .filter(t -> !t.equals(CUSTOM)) - .filter(t -> t.isAvailable()) - .findFirst() - .orElse(null); - } } diff --git a/app/src/main/java/io/xpipe/app/prefs/RdpCategory.java b/app/src/main/java/io/xpipe/app/prefs/RdpCategory.java index 68ab53bd6..8c3a97483 100644 --- a/app/src/main/java/io/xpipe/app/prefs/RdpCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/RdpCategory.java @@ -25,8 +25,7 @@ public class RdpCategory extends AppPrefsCategory { .nameAndDescription("customRdpClientCommand") .addComp(new TextFieldComp(prefs.customRdpClientCommand, true) .apply(struc -> struc.get().setPromptText("myrdpclient -c $FILE")) - .hide(prefs.rdpClientType.isNotEqualTo(ExternalRdpClientType.CUSTOM))) - ) + .hide(prefs.rdpClientType.isNotEqualTo(ExternalRdpClientType.CUSTOM)))) .buildComp(); } } diff --git a/app/src/main/java/io/xpipe/app/prefs/SshCategory.java b/app/src/main/java/io/xpipe/app/prefs/SshCategory.java index c64a2790b..cb8750cad 100644 --- a/app/src/main/java/io/xpipe/app/prefs/SshCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/SshCategory.java @@ -21,7 +21,7 @@ public class SshCategory extends AppPrefsCategory { .nameAndDescription("useBundledTools") .addToggle(prefs.useBundledTools) .hide(new SimpleBooleanProperty(!OsType.getLocal().equals(OsType.WINDOWS))) - .addComp(prefs.getCustomComp("x11WslInstance")) + .addComp(prefs.getCustomComp("x11WslInstance")) .hide(new SimpleBooleanProperty(!OsType.getLocal().equals(OsType.WINDOWS)))) .buildComp(); } diff --git a/app/src/main/java/io/xpipe/app/prefs/SupportedLocale.java b/app/src/main/java/io/xpipe/app/prefs/SupportedLocale.java index f6cb33762..0cc3c5110 100644 --- a/app/src/main/java/io/xpipe/app/prefs/SupportedLocale.java +++ b/app/src/main/java/io/xpipe/app/prefs/SupportedLocale.java @@ -14,15 +14,19 @@ import java.util.Locale; @Getter public class SupportedLocale implements PrefsChoiceValue { - public static List ALL = AppProperties.get().getLanguages().stream().map(s -> new SupportedLocale(Locale.of(s), s)).toList(); - - public static SupportedLocale getEnglish() { - return ALL.stream().filter(supportedLocale -> supportedLocale.getId().equals("en")).findFirst().orElseThrow(); - } - + public static List ALL = AppProperties.get().getLanguages().stream() + .map(s -> new SupportedLocale(Locale.of(s), s)) + .toList(); private final Locale locale; private final String id; + public static SupportedLocale getEnglish() { + return ALL.stream() + .filter(supportedLocale -> supportedLocale.getId().equals("en")) + .findFirst() + .orElseThrow(); + } + @Override public ObservableValue toTranslatedString() { return new SimpleStringProperty(locale.getDisplayName(locale)); diff --git a/app/src/main/java/io/xpipe/app/prefs/TerminalCategory.java b/app/src/main/java/io/xpipe/app/prefs/TerminalCategory.java index 1e369e327..5bfe1ec99 100644 --- a/app/src/main/java/io/xpipe/app/prefs/TerminalCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/TerminalCategory.java @@ -30,57 +30,6 @@ public class TerminalCategory extends AppPrefsCategory { return "terminal"; } - private Comp terminalChoice() { - var prefs = AppPrefs.get(); - var c = ChoiceComp.ofTranslatable( - prefs.terminalType, PrefsChoiceValue.getSupported(ExternalTerminalType.class), false); - c.apply(struc -> { - struc.get().setCellFactory(param -> { - return new ListCell<>() { - @Override - protected void updateItem(ExternalTerminalType item, boolean empty) { - super.updateItem(item, empty); - if (empty) { - return; - } - - setText(item.toTranslatedString().getValue()); - if (item != ExternalTerminalType.CUSTOM) { - var graphic = new FontIcon(item.isRecommended() ? "mdi2c-check-decagram" : "mdi2a-alert-circle-check"); - graphic.setFill(item.isRecommended() ? Color.GREEN : Color.ORANGE); - setGraphic(graphic); - } else { - setGraphic(new FontIcon("mdi2m-minus-circle")); - } - } - }; - }); - }); - - var visit = new ButtonComp(AppI18n.observable("website"), new FontIcon("mdi2w-web"), () -> { - var t = prefs.terminalType().getValue(); - if (t == null || t.getWebsite() == null) { - return; - } - - Hyperlinks.open(t.getWebsite()); - }); - var visitVisible = Bindings.createBooleanBinding(() -> { - var t = prefs.terminalType().getValue(); - if (t == null || t.getWebsite() == null) { - return false; - } - - return true; - }, prefs.terminalType()); - visit.visible(visitVisible); - - return new HorizontalComp(List.of(c, visit)).apply(struc -> { - struc.get().setAlignment(Pos.CENTER_LEFT); - struc.get().setSpacing(10); - }); - } - @Override protected Comp create() { var prefs = AppPrefs.get(); @@ -117,4 +66,58 @@ public class TerminalCategory extends AppPrefsCategory { .addToggle(prefs.clearTerminalOnInit)) .buildComp(); } + + private Comp terminalChoice() { + var prefs = AppPrefs.get(); + var c = ChoiceComp.ofTranslatable( + prefs.terminalType, PrefsChoiceValue.getSupported(ExternalTerminalType.class), false); + c.apply(struc -> { + struc.get().setCellFactory(param -> { + return new ListCell<>() { + @Override + protected void updateItem(ExternalTerminalType item, boolean empty) { + super.updateItem(item, empty); + if (empty) { + return; + } + + setText(item.toTranslatedString().getValue()); + if (item != ExternalTerminalType.CUSTOM) { + var graphic = new FontIcon( + item.isRecommended() ? "mdi2c-check-decagram" : "mdi2a-alert-circle-check"); + graphic.setFill(item.isRecommended() ? Color.GREEN : Color.ORANGE); + setGraphic(graphic); + } else { + setGraphic(new FontIcon("mdi2m-minus-circle")); + } + } + }; + }); + }); + + var visit = new ButtonComp(AppI18n.observable("website"), new FontIcon("mdi2w-web"), () -> { + var t = prefs.terminalType().getValue(); + if (t == null || t.getWebsite() == null) { + return; + } + + Hyperlinks.open(t.getWebsite()); + }); + var visitVisible = Bindings.createBooleanBinding( + () -> { + var t = prefs.terminalType().getValue(); + if (t == null || t.getWebsite() == null) { + return false; + } + + return true; + }, + prefs.terminalType()); + visit.visible(visitVisible); + + return new HorizontalComp(List.of(c, visit)).apply(struc -> { + struc.get().setAlignment(Pos.CENTER_LEFT); + struc.get().setSpacing(10); + }); + } } diff --git a/app/src/main/java/io/xpipe/app/prefs/TroubleshootCategory.java b/app/src/main/java/io/xpipe/app/prefs/TroubleshootCategory.java index 867c26be6..c8f35968f 100644 --- a/app/src/main/java/io/xpipe/app/prefs/TroubleshootCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/TroubleshootCategory.java @@ -45,7 +45,8 @@ public class TroubleshootCategory extends AppPrefsCategory { XPipeInstallation.getCurrentInstallationBasePath() .toString(), XPipeInstallation.getDaemonDebugScriptPath(OsType.getLocal())); - TerminalLauncher.openDirect("XPipe Debug", sc -> sc.getShellDialect().runScriptCommand(sc, script)); + TerminalLauncher.openDirect("XPipe Debug", sc -> sc.getShellDialect() + .runScriptCommand(sc, script)); }); e.consume(); }) diff --git a/app/src/main/java/io/xpipe/app/terminal/AlacrittyTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/AlacrittyTerminalType.java index a80feebc6..4a3f70993 100644 --- a/app/src/main/java/io/xpipe/app/terminal/AlacrittyTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/AlacrittyTerminalType.java @@ -5,6 +5,30 @@ import io.xpipe.core.process.CommandBuilder; public interface AlacrittyTerminalType extends ExternalTerminalType { + ExternalTerminalType ALACRITTY_WINDOWS = new Windows(); + ExternalTerminalType ALACRITTY_LINUX = new Linux(); + ExternalTerminalType ALACRITTY_MAC_OS = new MacOs(); + + @Override + default boolean supportsTabs() { + return false; + } + + @Override + default String getWebsite() { + return "https://github.com/alacritty/alacritty"; + } + + @Override + default boolean isRecommended() { + return false; + } + + @Override + default boolean supportsColoredTitle() { + return false; + } + static class Windows extends SimplePathType implements AlacrittyTerminalType { public Windows() { @@ -15,11 +39,11 @@ public interface AlacrittyTerminalType extends ExternalTerminalType { protected CommandBuilder toCommand(LaunchConfiguration configuration) { var b = CommandBuilder.of(); -// if (configuration.getColor() != null) { -// b.add("-o") -// .addQuoted("colors.primary.background='%s'" -// .formatted(configuration.getColor().toHexString())); -// } + // if (configuration.getColor() != null) { + // b.add("-o") + // .addQuoted("colors.primary.background='%s'" + // .formatted(configuration.getColor().toHexString())); + // } // Alacritty is bugged and will not accept arguments with spaces even if they are correctly passed/escaped // So this will not work when the script file has spaces @@ -28,7 +52,6 @@ public interface AlacrittyTerminalType extends ExternalTerminalType { .add("-e") .add(configuration.getDialectLaunchCommand()); } - } static class Linux extends SimplePathType implements AlacrittyTerminalType { @@ -45,31 +68,6 @@ public interface AlacrittyTerminalType extends ExternalTerminalType { .add("-e") .addFile(configuration.getScriptFile()); } - - } - - ExternalTerminalType ALACRITTY_WINDOWS = new Windows(); - ExternalTerminalType ALACRITTY_LINUX = new Linux(); - ExternalTerminalType ALACRITTY_MAC_OS = new MacOs(); - - @Override - default String getWebsite() { - return "https://github.com/alacritty/alacritty"; - } - - @Override - default boolean isRecommended() { - return false; - } - - @Override - default boolean supportsTabs() { - return false; - } - - @Override - default boolean supportsColoredTitle() { - return false; } class MacOs extends MacOsType implements AlacrittyTerminalType { diff --git a/app/src/main/java/io/xpipe/app/terminal/CustomTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/CustomTerminalType.java index 2209e4258..170e443f0 100644 --- a/app/src/main/java/io/xpipe/app/terminal/CustomTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/CustomTerminalType.java @@ -39,7 +39,8 @@ public class CustomTerminalType extends ExternalApplicationType implements Exter var format = custom.toLowerCase(Locale.ROOT).contains("$cmd") ? custom : custom + " $CMD"; try (var pc = LocalShell.getShell()) { - var toExecute = ExternalApplicationHelper.replaceFileArgument(format, "CMD", configuration.getScriptFile().toString()); + var toExecute = ExternalApplicationHelper.replaceFileArgument( + format, "CMD", configuration.getScriptFile().toString()); // We can't be sure whether the command is blocking or not, so always make it not blocking if (pc.getOsType().equals(OsType.WINDOWS)) { toExecute = "start \"" + configuration.getCleanTitle() + "\" " + toExecute; diff --git a/app/src/main/java/io/xpipe/app/terminal/ExternalTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/ExternalTerminalType.java index 02cd76c00..6af87c6fe 100644 --- a/app/src/main/java/io/xpipe/app/terminal/ExternalTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/ExternalTerminalType.java @@ -3,7 +3,8 @@ package io.xpipe.app.terminal; import io.xpipe.app.ext.PrefsChoiceValue; import io.xpipe.app.prefs.ExternalApplicationType; import io.xpipe.app.storage.DataStoreColor; -import io.xpipe.app.util.*; +import io.xpipe.app.util.CommandSupport; +import io.xpipe.app.util.LocalShell; import io.xpipe.core.process.*; import io.xpipe.core.store.FilePath; import lombok.Getter; @@ -13,7 +14,10 @@ import lombok.With; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Path; -import java.util.*; +import java.util.ArrayList; +import java.util.Base64; +import java.util.Comparator; +import java.util.List; import java.util.function.Supplier; public interface ExternalTerminalType extends PrefsChoiceValue { @@ -21,12 +25,12 @@ public interface ExternalTerminalType extends PrefsChoiceValue { ExternalTerminalType CMD = new SimplePathType("app.cmd", "cmd.exe", true) { @Override - public boolean isRecommended() { + public boolean supportsTabs() { return false; } @Override - public boolean supportsTabs() { + public boolean isRecommended() { return false; } @@ -48,12 +52,12 @@ public interface ExternalTerminalType extends PrefsChoiceValue { ExternalTerminalType POWERSHELL = new SimplePathType("app.powershell", "powershell", true) { @Override - public boolean isRecommended() { + public boolean supportsTabs() { return false; } @Override - public boolean supportsTabs() { + public boolean isRecommended() { return false; } @@ -88,12 +92,12 @@ public interface ExternalTerminalType extends PrefsChoiceValue { ExternalTerminalType PWSH = new SimplePathType("app.pwsh", "pwsh", true) { @Override - public boolean isRecommended() { + public boolean supportsTabs() { return false; } @Override - public boolean supportsTabs() { + public boolean isRecommended() { return false; } @@ -118,8 +122,8 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType GNOME_TERMINAL = new PathCheckType("app.gnomeTerminal", "gnome-terminal", true) { @Override - public boolean supportsColoredTitle() { - return true; + public boolean supportsTabs() { + return false; } @Override @@ -128,8 +132,8 @@ public interface ExternalTerminalType extends PrefsChoiceValue { } @Override - public boolean supportsTabs() { - return false; + public boolean supportsColoredTitle() { + return true; } @Override @@ -152,12 +156,12 @@ public interface ExternalTerminalType extends PrefsChoiceValue { ExternalTerminalType KONSOLE = new SimplePathType("app.konsole", "konsole", true) { @Override - public boolean isRecommended() { + public boolean supportsTabs() { return true; } @Override - public boolean supportsTabs() { + public boolean isRecommended() { return true; } @@ -176,18 +180,17 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType XFCE = new SimplePathType("app.xfce", "xfce4-terminal", true) { @Override - public boolean supportsColoredTitle() { + public boolean supportsTabs() { return true; } - @Override public boolean isRecommended() { return true; } @Override - public boolean supportsTabs() { + public boolean supportsColoredTitle() { return true; } @@ -202,18 +205,17 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType ELEMENTARY = new SimplePathType("app.elementaryTerminal", "io.elementary.terminal", true) { @Override - public boolean supportsColoredTitle() { + public boolean supportsTabs() { return true; } - @Override public boolean isRecommended() { return true; } @Override - public boolean supportsTabs() { + public boolean supportsColoredTitle() { return true; } @@ -224,19 +226,18 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType TILIX = new SimplePathType("app.tilix", "tilix", true) { @Override - public boolean supportsColoredTitle() { - return true; + public boolean supportsTabs() { + return false; } - @Override public boolean isRecommended() { return false; } @Override - public boolean supportsTabs() { - return false; + public boolean supportsColoredTitle() { + return true; } @Override @@ -250,18 +251,17 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType TERMINATOR = new SimplePathType("app.terminator", "terminator", true) { @Override - public boolean supportsColoredTitle() { + public boolean supportsTabs() { return true; } - @Override public boolean isRecommended() { return true; } @Override - public boolean supportsTabs() { + public boolean supportsColoredTitle() { return true; } @@ -277,18 +277,17 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType TERMINOLOGY = new SimplePathType("app.terminology", "terminology", true) { @Override - public boolean supportsColoredTitle() { + public boolean supportsTabs() { return true; } - @Override public boolean isRecommended() { return true; } @Override - public boolean supportsTabs() { + public boolean supportsColoredTitle() { return true; } @@ -304,19 +303,18 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType COOL_RETRO_TERM = new SimplePathType("app.coolRetroTerm", "cool-retro-term", true) { @Override - public boolean supportsColoredTitle() { - return true; + public boolean supportsTabs() { + return false; } - @Override public boolean isRecommended() { return false; } @Override - public boolean supportsTabs() { - return false; + public boolean supportsColoredTitle() { + return true; } @Override @@ -330,18 +328,17 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType GUAKE = new SimplePathType("app.guake", "guake", true) { @Override - public boolean supportsColoredTitle() { + public boolean supportsTabs() { return true; } - @Override public boolean isRecommended() { return true; } @Override - public boolean supportsTabs() { + public boolean supportsColoredTitle() { return true; } @@ -357,18 +354,17 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType TILDA = new SimplePathType("app.tilda", "tilda", true) { @Override - public boolean supportsColoredTitle() { + public boolean supportsTabs() { return true; } - @Override public boolean isRecommended() { return true; } @Override - public boolean supportsTabs() { + public boolean supportsColoredTitle() { return true; } @@ -379,19 +375,18 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType XTERM = new SimplePathType("app.xterm", "xterm", true) { @Override - public boolean supportsColoredTitle() { - return true; + public boolean supportsTabs() { + return false; } - @Override public boolean isRecommended() { return false; } @Override - public boolean supportsTabs() { - return false; + public boolean supportsColoredTitle() { + return true; } @Override @@ -405,19 +400,18 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType DEEPIN_TERMINAL = new SimplePathType("app.deepinTerminal", "deepin-terminal", true) { @Override - public boolean supportsColoredTitle() { - return true; + public boolean supportsTabs() { + return false; } - @Override public boolean isRecommended() { return false; } @Override - public boolean supportsTabs() { - return false; + public boolean supportsColoredTitle() { + return true; } @Override @@ -427,8 +421,8 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType Q_TERMINAL = new SimplePathType("app.qTerminal", "qterminal", true) { @Override - public boolean supportsColoredTitle() { - return true; + public boolean supportsTabs() { + return false; } @Override @@ -436,10 +430,9 @@ public interface ExternalTerminalType extends PrefsChoiceValue { return false; } - @Override - public boolean supportsTabs() { - return false; + public boolean supportsColoredTitle() { + return true; } @Override @@ -449,8 +442,8 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType MACOS_TERMINAL = new MacOsType("app.macosTerminal", "Terminal") { @Override - public boolean supportsColoredTitle() { - return true; + public boolean supportsTabs() { + return false; } @Override @@ -459,8 +452,8 @@ public interface ExternalTerminalType extends PrefsChoiceValue { } @Override - public boolean supportsTabs() { - return false; + public boolean supportsColoredTitle() { + return true; } @Override @@ -480,7 +473,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue { }; ExternalTerminalType ITERM2 = new MacOsType("app.iterm2", "iTerm") { @Override - public boolean supportsColoredTitle() { + public boolean supportsTabs() { return true; } @@ -490,7 +483,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue { } @Override - public boolean supportsTabs() { + public boolean supportsColoredTitle() { return true; } @@ -519,7 +512,11 @@ public interface ExternalTerminalType extends PrefsChoiceValue { create window with default profile command "%s" end tell """, - a, a, a, a, configuration.getScriptFile().toString().replaceAll("\"", "\\\\\""))) + a, + a, + a, + a, + configuration.getScriptFile().toString().replaceAll("\"", "\\\\\""))) .execute(); } } @@ -527,7 +524,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue { ExternalTerminalType WARP = new MacOsType("app.warp", "Warp") { @Override - public boolean supportsColoredTitle() { + public boolean supportsTabs() { return true; } @@ -537,7 +534,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue { } @Override - public boolean supportsTabs() { + public boolean supportsColoredTitle() { return true; } @@ -582,8 +579,14 @@ public interface ExternalTerminalType extends PrefsChoiceValue { XTERM, DEEPIN_TERMINAL, Q_TERMINAL); - List MACOS_TERMINALS = - List.of(ITERM2, TabbyTerminalType.TABBY_MAC_OS, AlacrittyTerminalType.ALACRITTY_MAC_OS, KittyTerminalType.KITTY_MACOS, WARP, WezTerminalType.WEZTERM_MAC_OS, MACOS_TERMINAL); + List MACOS_TERMINALS = List.of( + ITERM2, + TabbyTerminalType.TABBY_MAC_OS, + AlacrittyTerminalType.ALACRITTY_MAC_OS, + KittyTerminalType.KITTY_MACOS, + WARP, + WezTerminalType.WEZTERM_MAC_OS, + MACOS_TERMINAL); @SuppressWarnings("TrivialFunctionalExpressionUsage") List ALL = ((Supplier>) () -> { @@ -714,5 +717,4 @@ public interface ExternalTerminalType extends PrefsChoiceValue { protected abstract CommandBuilder toCommand(LaunchConfiguration configuration) throws Exception; } - } diff --git a/app/src/main/java/io/xpipe/app/terminal/KittyTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/KittyTerminalType.java index 08c7d073c..a38d8fce6 100644 --- a/app/src/main/java/io/xpipe/app/terminal/KittyTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/KittyTerminalType.java @@ -11,14 +11,61 @@ import io.xpipe.core.util.XPipeInstallation; public interface KittyTerminalType extends ExternalTerminalType { - @Override - default boolean supportsColoredTitle() { - return true; + public static final ExternalTerminalType KITTY_LINUX = new Linux(); + public static final ExternalTerminalType KITTY_MACOS = new MacOs(); + + private static FilePath getSocket() throws Exception { + try (var sc = LocalShell.getShell().start()) { + var temp = ShellTemp.getUserSpecificTempDataDirectory(sc, null); + sc.executeSimpleCommand(sc.getShellDialect().getMkdirsCommand(temp.toString())); + return temp.join("xpipe_kitty"); + } } - @Override - default boolean isRecommended() { - return true; + private static void open(ExternalTerminalType.LaunchConfiguration configuration, CommandBuilder socketWrite) + throws Exception { + try (var sc = LocalShell.getShell().start()) { + var payload = JsonNodeFactory.instance.objectNode(); + var args = configuration.getDialectLaunchCommand().buildBaseParts(sc); + var argsArray = payload.putArray("args"); + args.forEach(argsArray::add); + payload.put("tab_title", configuration.getColoredTitle()); + payload.put("type", "tab"); + payload.put("logo_alpha", 0.01); + payload.put( + "logo", XPipeInstallation.getLocalDefaultInstallationIcon().toString()); + + var json = JsonNodeFactory.instance.objectNode(); + json.put("cmd", "launch"); + json.set("payload", payload); + json.putArray("version").add(0).add(14).add(2); + var jsonString = json.toString(); + var echoString = "'\\eP@kitty-cmd" + jsonString + "\\e\\\\'"; + + sc.executeSimpleCommand(CommandBuilder.of() + .add("echo", "-en", echoString, "|") + .add(socketWrite) + .addFile(getSocket())); + } + } + + private static void closeInitial(CommandBuilder socketWrite) throws Exception { + try (var sc = LocalShell.getShell().start()) { + var payload = JsonNodeFactory.instance.objectNode(); + payload.put("match", "not recent:0"); + + var json = JsonNodeFactory.instance.objectNode(); + json.put("cmd", "close-tab"); + json.set("payload", payload); + json.putArray("version").add(0).add(14).add(2); + var jsonString = json.toString(); + var echoString = "'\\eP@kitty-cmd" + jsonString + "\\e\\\\'"; + + sc.executeSimpleCommand(CommandBuilder.of() + .add("echo", "-en", echoString, "|") + .add(socketWrite) + .addFile(getSocket())); + } } @Override @@ -31,55 +78,14 @@ public interface KittyTerminalType extends ExternalTerminalType { return "https://github.com/kovidgoyal/kitty"; } - - public static final ExternalTerminalType KITTY_LINUX = new Linux(); - - public static final ExternalTerminalType KITTY_MACOS = new MacOs(); - - private static FilePath getSocket() throws Exception { - try (var sc = LocalShell.getShell().start()) { - var temp = ShellTemp.getUserSpecificTempDataDirectory(sc, null); - sc.executeSimpleCommand(sc.getShellDialect().getMkdirsCommand(temp.toString())); - return temp.join("xpipe_kitty"); - } + @Override + default boolean isRecommended() { + return true; } - private static void open(ExternalTerminalType.LaunchConfiguration configuration, CommandBuilder socketWrite) throws Exception { - try (var sc = LocalShell.getShell().start()) { - var payload = JsonNodeFactory.instance.objectNode(); - var args = configuration.getDialectLaunchCommand().buildBaseParts(sc); - var argsArray = payload.putArray("args"); - args.forEach(argsArray::add); - payload.put("tab_title",configuration.getColoredTitle()); - payload.put("type", "tab"); - payload.put("logo_alpha", 0.01); - payload.put("logo", XPipeInstallation.getLocalDefaultInstallationIcon().toString()); - - var json = JsonNodeFactory.instance.objectNode(); - json.put("cmd", "launch"); - json.set("payload", payload); - json.putArray("version").add(0).add(14).add(2); - var jsonString = json.toString(); - var echoString = "'\\eP@kitty-cmd" + jsonString + "\\e\\\\'"; - - sc.executeSimpleCommand(CommandBuilder.of().add("echo", "-en", echoString, "|").add(socketWrite).addFile(getSocket())); - } - } - - private static void closeInitial( CommandBuilder socketWrite) throws Exception { - try (var sc = LocalShell.getShell().start()) { - var payload = JsonNodeFactory.instance.objectNode(); - payload.put("match", "not recent:0"); - - var json = JsonNodeFactory.instance.objectNode(); - json.put("cmd", "close-tab"); - json.set("payload", payload); - json.putArray("version").add(0).add(14).add(2); - var jsonString = json.toString(); - var echoString = "'\\eP@kitty-cmd" + jsonString + "\\e\\\\'"; - - sc.executeSimpleCommand(CommandBuilder.of().add("echo", "-en", echoString, "|").add(socketWrite).addFile(getSocket())); - } + @Override + default boolean supportsColoredTitle() { + return true; } class Linux implements KittyTerminalType { @@ -107,11 +113,19 @@ public interface KittyTerminalType extends ExternalTerminalType { private boolean prepare() throws Exception { var socket = getSocket(); try (var sc = LocalShell.getShell().start()) { - if (sc.executeSimpleBooleanCommand("test -w " + sc.getShellDialect().fileArgument(socket))) { + if (sc.executeSimpleBooleanCommand( + "test -w " + sc.getShellDialect().fileArgument(socket))) { return false; } - sc.executeSimpleCommand(CommandBuilder.of().add("kitty").add("-o", "allow_remote_control=socket-only", "--listen-on", "unix:" + getSocket(), "--detach")); + sc.executeSimpleCommand(CommandBuilder.of() + .add("kitty") + .add( + "-o", + "allow_remote_control=socket-only", + "--listen-on", + "unix:" + getSocket(), + "--detach")); ThreadHelper.sleep(1500); return true; } @@ -120,7 +134,9 @@ public interface KittyTerminalType extends ExternalTerminalType { class MacOs extends MacOsType implements KittyTerminalType { - public MacOs() {super("app.kitty", "kitty");} + public MacOs() { + super("app.kitty", "kitty"); + } @Override public void launch(LaunchConfiguration configuration) throws Exception { @@ -139,11 +155,14 @@ public interface KittyTerminalType extends ExternalTerminalType { private boolean prepare() throws Exception { var socket = getSocket(); try (var sc = LocalShell.getShell().start()) { - if (sc.executeSimpleBooleanCommand("test -w " + sc.getShellDialect().fileArgument(socket))) { + if (sc.executeSimpleBooleanCommand( + "test -w " + sc.getShellDialect().fileArgument(socket))) { return false; } - sc.executeSimpleCommand(CommandBuilder.of().add("open", "-a", "kitty.app", "--args").add("-o", "allow_remote_control=socket-only", "--listen-on", "unix:" + getSocket())); + sc.executeSimpleCommand(CommandBuilder.of() + .add("open", "-a", "kitty.app", "--args") + .add("-o", "allow_remote_control=socket-only", "--listen-on", "unix:" + getSocket())); ThreadHelper.sleep(1000); return true; } diff --git a/app/src/main/java/io/xpipe/app/terminal/TabbyTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/TabbyTerminalType.java index 0ee04a312..cffade904 100644 --- a/app/src/main/java/io/xpipe/app/terminal/TabbyTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/TabbyTerminalType.java @@ -10,52 +10,14 @@ import java.util.Optional; public interface TabbyTerminalType extends ExternalTerminalType { - static class Windows extends ExternalTerminalType.WindowsType implements TabbyTerminalType { - - public Windows() { - super("app.tabby", "Tabby.exe"); - } - - - @Override - protected void execute(Path file, LaunchConfiguration configuration) throws Exception { - // Tabby has a very weird handling of output, even detaching with start does not prevent it from printing - if (configuration.getScriptDialect().equals(ShellDialects.CMD)) { - // It also freezes with any other input than .bat files, why? - LocalShell.getShell().executeSimpleCommand(CommandBuilder.of() - .addFile(file.toString()) - .add("run") - .addFile(configuration.getScriptFile()) - .discardOutput()); - } - - // This is probably not going to work as it does not launch a bat file - LocalShell.getShell().executeSimpleCommand(CommandBuilder.of() - .addFile(file.toString()) - .add("run") - .add(configuration.getDialectLaunchCommand()) - .discardOutput()); - } - - @Override - protected Optional determineInstallation() { - var perUser = WindowsRegistry.readString(WindowsRegistry.HKEY_CURRENT_USER, "SOFTWARE\\71445fac-d6ef-5436-9da7-5a323762d7f5", - "InstallLocation").map(p -> p + "\\Tabby.exe").map(Path::of); - if (perUser.isPresent()) { - return perUser; - } - - var systemWide = WindowsRegistry.readString(WindowsRegistry.HKEY_LOCAL_MACHINE, "SOFTWARE\\71445fac-d6ef-5436-9da7-5a323762d7f5", - "InstallLocation").map(p -> p + "\\Tabby.exe").map(Path::of); - return systemWide; - } - - } - ExternalTerminalType TABBY_WINDOWS = new Windows(); - ExternalTerminalType TABBY_MAC_OS = new MacOs(); + @Override + default boolean supportsTabs() { + return true; + } + @Override default String getWebsite() { return "https://tabby.sh"; @@ -67,13 +29,58 @@ public interface TabbyTerminalType extends ExternalTerminalType { } @Override - default boolean supportsTabs() { + default boolean supportsColoredTitle() { return true; } - @Override - default boolean supportsColoredTitle() { - return true; + static class Windows extends ExternalTerminalType.WindowsType implements TabbyTerminalType { + + public Windows() { + super("app.tabby", "Tabby.exe"); + } + + @Override + protected void execute(Path file, LaunchConfiguration configuration) throws Exception { + // Tabby has a very weird handling of output, even detaching with start does not prevent it from printing + if (configuration.getScriptDialect().equals(ShellDialects.CMD)) { + // It also freezes with any other input than .bat files, why? + LocalShell.getShell() + .executeSimpleCommand(CommandBuilder.of() + .addFile(file.toString()) + .add("run") + .addFile(configuration.getScriptFile()) + .discardOutput()); + } + + // This is probably not going to work as it does not launch a bat file + LocalShell.getShell() + .executeSimpleCommand(CommandBuilder.of() + .addFile(file.toString()) + .add("run") + .add(configuration.getDialectLaunchCommand()) + .discardOutput()); + } + + @Override + protected Optional determineInstallation() { + var perUser = WindowsRegistry.readString( + WindowsRegistry.HKEY_CURRENT_USER, + "SOFTWARE\\71445fac-d6ef-5436-9da7-5a323762d7f5", + "InstallLocation") + .map(p -> p + "\\Tabby.exe") + .map(Path::of); + if (perUser.isPresent()) { + return perUser; + } + + var systemWide = WindowsRegistry.readString( + WindowsRegistry.HKEY_LOCAL_MACHINE, + "SOFTWARE\\71445fac-d6ef-5436-9da7-5a323762d7f5", + "InstallLocation") + .map(p -> p + "\\Tabby.exe") + .map(Path::of); + return systemWide; + } } class MacOs extends MacOsType implements TabbyTerminalType { diff --git a/app/src/main/java/io/xpipe/app/terminal/WezTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/WezTerminalType.java index bbf5451d6..60698c581 100644 --- a/app/src/main/java/io/xpipe/app/terminal/WezTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/WezTerminalType.java @@ -10,47 +10,15 @@ import java.util.Optional; public interface WezTerminalType extends ExternalTerminalType { - static class Windows extends WindowsType implements WezTerminalType { - - public Windows() { - super("app.wezterm", "wezterm-gui"); - } - - @Override - protected void execute(Path file, LaunchConfiguration configuration) throws Exception { - LocalShell.getShell().executeSimpleCommand(CommandBuilder.of().addFile(file.toString()).add("start").add(configuration.getDialectLaunchCommand())); - } - - @Override - protected Optional determineInstallation() { - Optional launcherDir; - launcherDir = WindowsRegistry.readString( - WindowsRegistry.HKEY_LOCAL_MACHINE, - "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{BCF6F0DA-5B9A-408D-8562-F680AE6E1EAF}_is1", - "InstallLocation") - .map(p -> p + "\\wezterm-gui.exe"); - return launcherDir.map(Path::of); - } - - } - - static class Linux extends SimplePathType implements WezTerminalType { - - public Linux() { - super("app.wezterm", "wezterm-gui", true); - } - - @Override - protected CommandBuilder toCommand(LaunchConfiguration configuration) { - return CommandBuilder.of().add("start").addFile(configuration.getScriptFile()); - } - - } - ExternalTerminalType WEZTERM_WINDOWS = new Windows(); ExternalTerminalType WEZTERM_LINUX = new Linux(); ExternalTerminalType WEZTERM_MAC_OS = new MacOs(); + @Override + default boolean supportsTabs() { + return false; + } + @Override default String getWebsite() { return "https://wezfurlong.org/wezterm/index.html"; @@ -61,16 +29,50 @@ public interface WezTerminalType extends ExternalTerminalType { return false; } - @Override - default boolean supportsTabs() { - return false; - } - @Override default boolean supportsColoredTitle() { return true; } + static class Windows extends WindowsType implements WezTerminalType { + + public Windows() { + super("app.wezterm", "wezterm-gui"); + } + + @Override + protected void execute(Path file, LaunchConfiguration configuration) throws Exception { + LocalShell.getShell() + .executeSimpleCommand(CommandBuilder.of() + .addFile(file.toString()) + .add("start") + .add(configuration.getDialectLaunchCommand())); + } + + @Override + protected Optional determineInstallation() { + Optional launcherDir; + launcherDir = WindowsRegistry.readString( + WindowsRegistry.HKEY_LOCAL_MACHINE, + "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{BCF6F0DA-5B9A-408D-8562-F680AE6E1EAF}_is1", + "InstallLocation") + .map(p -> p + "\\wezterm-gui.exe"); + return launcherDir.map(Path::of); + } + } + + static class Linux extends SimplePathType implements WezTerminalType { + + public Linux() { + super("app.wezterm", "wezterm-gui", true); + } + + @Override + protected CommandBuilder toCommand(LaunchConfiguration configuration) { + return CommandBuilder.of().add("start").addFile(configuration.getScriptFile()); + } + } + class MacOs extends MacOsType implements WezTerminalType { public MacOs() { diff --git a/app/src/main/java/io/xpipe/app/terminal/WindowsTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/WindowsTerminalType.java index a5ab1fc39..605151719 100644 --- a/app/src/main/java/io/xpipe/app/terminal/WindowsTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/WindowsTerminalType.java @@ -10,23 +10,7 @@ import java.nio.file.Path; public interface WindowsTerminalType extends ExternalTerminalType { - @Override - default boolean isRecommended() { - return true; - } - - @Override - default boolean supportsTabs() { - return true; - } - - @Override - default boolean supportsColoredTitle() { - return false; - } - public static final ExternalTerminalType WINDOWS_TERMINAL = new Standard(); - public static final ExternalTerminalType WINDOWS_TERMINAL_PREVIEW = new Preview(); private static CommandBuilder toCommand(ExternalTerminalType.LaunchConfiguration configuration) throws Exception { @@ -48,9 +32,26 @@ public interface WindowsTerminalType extends ExternalTerminalType { return cmd.add("--title").addQuoted(fixedName).add(toExec); } + @Override + default boolean supportsTabs() { + return true; + } + + @Override + default boolean isRecommended() { + return true; + } + + @Override + default boolean supportsColoredTitle() { + return false; + } + class Standard extends SimplePathType implements WindowsTerminalType { - public Standard() {super("app.windowsTerminal", "wt.exe", false);} + public Standard() { + super("app.windowsTerminal", "wt.exe", false); + } @Override public String getWebsite() { diff --git a/app/src/main/java/io/xpipe/app/util/DesktopShortcuts.java b/app/src/main/java/io/xpipe/app/util/DesktopShortcuts.java index 592271f83..99c67b8cc 100644 --- a/app/src/main/java/io/xpipe/app/util/DesktopShortcuts.java +++ b/app/src/main/java/io/xpipe/app/util/DesktopShortcuts.java @@ -68,7 +68,9 @@ public class DesktopShortcuts { .createTextFileWriteCommand(pc, "APPL????", base + "/Contents/PkgInfo") .execute(); pc.getShellDialect() - .createTextFileWriteCommand(pc, """ + .createTextFileWriteCommand( + pc, + """ @@ -77,7 +79,8 @@ public class DesktopShortcuts { icon.icns - """, base + "/Contents/Info.plist") + """, + base + "/Contents/Info.plist") .execute(); pc.executeSimpleCommand("cp \"" + icon + "\" \"" + base + "/Contents/Resources/icon.icns\""); } diff --git a/app/src/main/java/io/xpipe/app/util/InputHelper.java b/app/src/main/java/io/xpipe/app/util/InputHelper.java index 73459c621..31c8a239c 100644 --- a/app/src/main/java/io/xpipe/app/util/InputHelper.java +++ b/app/src/main/java/io/xpipe/app/util/InputHelper.java @@ -38,9 +38,21 @@ public class InputHelper { } public static void onNavigationInput(EventTarget target, Consumer r) { - target.addEventFilter(KeyEvent.KEY_PRESSED, event -> { + target.addEventFilter(KeyEvent.KEY_PRESSED, event -> { var c = event.getCode(); - var list = List.of(KeyCode.LEFT, KeyCode.RIGHT, KeyCode.UP, KeyCode.DOWN, KeyCode.SPACE, KeyCode.ENTER, KeyCode.SHIFT, KeyCode.TAB, KeyCode.NUMPAD2, KeyCode.NUMPAD4, KeyCode.NUMPAD6, KeyCode.NUMPAD8); + var list = List.of( + KeyCode.LEFT, + KeyCode.RIGHT, + KeyCode.UP, + KeyCode.DOWN, + KeyCode.SPACE, + KeyCode.ENTER, + KeyCode.SHIFT, + KeyCode.TAB, + KeyCode.NUMPAD2, + KeyCode.NUMPAD4, + KeyCode.NUMPAD6, + KeyCode.NUMPAD8); r.accept(list.stream().anyMatch(keyCode -> keyCode == c)); }); target.addEventFilter(MouseEvent.MOUSE_PRESSED, event -> { diff --git a/app/src/main/java/io/xpipe/app/util/LicenseProvider.java b/app/src/main/java/io/xpipe/app/util/LicenseProvider.java index fe06efd5d..effa90a3a 100644 --- a/app/src/main/java/io/xpipe/app/util/LicenseProvider.java +++ b/app/src/main/java/io/xpipe/app/util/LicenseProvider.java @@ -41,6 +41,5 @@ public abstract class LicenseProvider { .findFirst() .orElseThrow(() -> ExtensionException.corrupt("Missing license provider")); } - } } diff --git a/app/src/main/java/io/xpipe/app/util/PlatformState.java b/app/src/main/java/io/xpipe/app/util/PlatformState.java index 23dd3a204..7c0bf40c3 100644 --- a/app/src/main/java/io/xpipe/app/util/PlatformState.java +++ b/app/src/main/java/io/xpipe/app/util/PlatformState.java @@ -26,15 +26,15 @@ public enum PlatformState { public static void teardown() { // This is bad and can get sometimes stuck -// PlatformThread.runLaterIfNeededBlocking(() -> { -// try { -// // Fix to preserve clipboard contents after shutdown -// var string = Clipboard.getSystemClipboard().getString(); -// var s = new StringSelection(string); -// Toolkit.getDefaultToolkit().getSystemClipboard().setContents(s, s); -// } catch (IllegalStateException ignored) { -// } -// }); + // PlatformThread.runLaterIfNeededBlocking(() -> { + // try { + // // Fix to preserve clipboard contents after shutdown + // var string = Clipboard.getSystemClipboard().getString(); + // var s = new StringSelection(string); + // Toolkit.getDefaultToolkit().getSystemClipboard().setContents(s, s); + // } catch (IllegalStateException ignored) { + // } + // }); Platform.exit(); setCurrent(PlatformState.EXITED); diff --git a/app/src/main/java/io/xpipe/app/util/RdpConfig.java b/app/src/main/java/io/xpipe/app/util/RdpConfig.java index 6e7174d9d..e89b68ce5 100644 --- a/app/src/main/java/io/xpipe/app/util/RdpConfig.java +++ b/app/src/main/java/io/xpipe/app/util/RdpConfig.java @@ -13,6 +13,8 @@ import java.util.stream.Collectors; @Value public class RdpConfig { + Map content; + public static RdpConfig parseFile(String file) throws IOException { var content = Files.readString(Path.of(file)); return parseContent(content); @@ -30,7 +32,6 @@ public class RdpConfig { map.put(split[0].trim(), new RdpConfig.TypedValue("s", split[1].trim())); } - if (split.length == 3) { map.put(split[0].trim(), new RdpConfig.TypedValue(split[1].trim(), split[2].trim())); } @@ -38,14 +39,6 @@ public class RdpConfig { return new RdpConfig(map); } - @Value - public static class TypedValue { - String type; - String value; - } - - Map content; - public RdpConfig overlay(Map override) { var newMap = new LinkedHashMap<>(content); newMap.putAll(override); @@ -53,12 +46,21 @@ public class RdpConfig { } public String toString() { - return content.entrySet().stream().map(e -> { - return e.getKey() + ":" + e.getValue().getType() + ":" + e.getValue().getValue(); - }).collect(Collectors.joining("\n")); + return content.entrySet().stream() + .map(e -> { + return e.getKey() + ":" + e.getValue().getType() + ":" + + e.getValue().getValue(); + }) + .collect(Collectors.joining("\n")); } public Optional get(String key) { return Optional.ofNullable(content.get(key)); } + + @Value + public static class TypedValue { + String type; + String value; + } } diff --git a/app/src/main/java/io/xpipe/app/util/ScriptHelper.java b/app/src/main/java/io/xpipe/app/util/ScriptHelper.java index 4318f18bb..9e963bb75 100644 --- a/app/src/main/java/io/xpipe/app/util/ScriptHelper.java +++ b/app/src/main/java/io/xpipe/app/util/ScriptHelper.java @@ -104,7 +104,8 @@ public class ScriptHelper { } @SneakyThrows - public static FilePath createExecScript(ShellDialect type, ShellControl processControl, FilePath file, String content) { + public static FilePath createExecScript( + ShellDialect type, ShellControl processControl, FilePath file, String content) { content = type.prepareScriptContent(content); TrackEvent.withTrace("Writing exec script") diff --git a/app/src/main/java/io/xpipe/app/util/ShellTemp.java b/app/src/main/java/io/xpipe/app/util/ShellTemp.java index 7be0c9bc8..eeacef7b9 100644 --- a/app/src/main/java/io/xpipe/app/util/ShellTemp.java +++ b/app/src/main/java/io/xpipe/app/util/ShellTemp.java @@ -59,7 +59,8 @@ public class ShellTemp { var d = proc.getShellDialect(); var systemTemp = proc.getSystemTemporaryDirectory(); - if (!d.directoryExists(proc, systemTemp.toString()).executeAndCheck() || !checkDirectoryPermissions(proc, systemTemp.toString())) { + if (!d.directoryExists(proc, systemTemp.toString()).executeAndCheck() + || !checkDirectoryPermissions(proc, systemTemp.toString())) { throw ErrorEvent.expected(new IOException("No permissions to access %s".formatted(systemTemp))); } @@ -87,7 +88,7 @@ public class ShellTemp { var base = proc.getSystemTemporaryDirectory(); var arr = Stream.concat(Stream.of(base.toString()), Arrays.stream(sub)).toArray(String[]::new); var dir = FileNames.join(arr); - + // We assume that this directory does not exist yet and therefore don't perform any checks proc.getShellDialect().prepareUserTempDirectory(proc, dir).execute(); diff --git a/app/src/main/java/io/xpipe/app/util/StringSource.java b/app/src/main/java/io/xpipe/app/util/StringSource.java index 746b141a1..6be190226 100644 --- a/app/src/main/java/io/xpipe/app/util/StringSource.java +++ b/app/src/main/java/io/xpipe/app/util/StringSource.java @@ -38,8 +38,7 @@ public abstract class StringSource { try (var sc = host.control().start()) { var path = file.toAbsoluteFilePath(sc); if (!sc.getShellDialect().createFileExistsCommand(sc, path).executeAndCheck()) { - throw ErrorEvent.expected( - new IllegalArgumentException("File " + path + " does not exist")); + throw ErrorEvent.expected(new IllegalArgumentException("File " + path + " does not exist")); } var abs = file.toAbsoluteFilePath(sc); diff --git a/app/src/main/java/io/xpipe/app/util/TerminalLauncher.java b/app/src/main/java/io/xpipe/app/util/TerminalLauncher.java index 4ee4a3209..59d37368e 100644 --- a/app/src/main/java/io/xpipe/app/util/TerminalLauncher.java +++ b/app/src/main/java/io/xpipe/app/util/TerminalLauncher.java @@ -18,14 +18,23 @@ import java.util.UUID; public class TerminalLauncher { - public static void openDirect(String title, FailableFunction command) throws Exception { + public static void openDirect(String title, FailableFunction command) + throws Exception { try (var sc = LocalShell.getShell().start()) { var type = AppPrefs.get().terminalType().getValue(); if (type == null) { throw ErrorEvent.expected(new IllegalStateException(AppI18n.get("noTerminalSet"))); } - var script = ScriptHelper.constructTerminalInitFile(sc.getShellDialect(), sc, ignored -> null, List.of(), - command.apply(sc), new TerminalInitScriptConfig(title, type.shouldClear() && AppPrefs.get().clearTerminalOnInit().get())); + var script = ScriptHelper.constructTerminalInitFile( + sc.getShellDialect(), + sc, + ignored -> null, + List.of(), + command.apply(sc), + new TerminalInitScriptConfig( + title, + type.shouldClear() + && AppPrefs.get().clearTerminalOnInit().get())); var config = new ExternalTerminalType.LaunchConfiguration(null, title, title, script, sc.getShellDialect()); type.launch(config); } diff --git a/app/src/main/java/io/xpipe/app/util/WindowControl.java b/app/src/main/java/io/xpipe/app/util/WindowControl.java index 85c4788ae..867b241bc 100644 --- a/app/src/main/java/io/xpipe/app/util/WindowControl.java +++ b/app/src/main/java/io/xpipe/app/util/WindowControl.java @@ -15,18 +15,6 @@ import java.lang.reflect.Method; @Getter public class WindowControl { - public interface DwmSupport extends Library { - - DwmSupport INSTANCE = Native.load("dwmapi", DwmSupport.class); - - WinNT.HRESULT DwmSetWindowAttribute( - WinDef.HWND hwnd, - int dwAttribute, - PointerType pvAttribute, - int cbAttribute - ); - } - private final WinDef.HWND windowHandle; public WindowControl(Window stage) throws Exception { @@ -48,16 +36,20 @@ public class WindowControl { } public void move(int x, int y, int w, int h) { - User32.INSTANCE.SetWindowPos(windowHandle, new WinDef.HWND(), x,y,w,h, 0); + User32.INSTANCE.SetWindowPos(windowHandle, new WinDef.HWND(), x, y, w, h, 0); } public void setWindowAttribute(int attribute, boolean attributeValue) { DwmSupport.INSTANCE.DwmSetWindowAttribute( - windowHandle, - attribute, - new WinDef.BOOLByReference(new WinDef.BOOL(attributeValue)), - WinDef.BOOL.SIZE - ); + windowHandle, attribute, new WinDef.BOOLByReference(new WinDef.BOOL(attributeValue)), WinDef.BOOL.SIZE); User32.INSTANCE.UpdateWindow(windowHandle); } + + public interface DwmSupport extends Library { + + DwmSupport INSTANCE = Native.load("dwmapi", DwmSupport.class); + + WinNT.HRESULT DwmSetWindowAttribute( + WinDef.HWND hwnd, int dwAttribute, PointerType pvAttribute, int cbAttribute); + } } diff --git a/app/src/main/java/module-info.java b/app/src/main/java/module-info.java index 26300e20f..4320a8533 100644 --- a/app/src/main/java/module-info.java +++ b/app/src/main/java/module-info.java @@ -117,7 +117,8 @@ open module io.xpipe.app { provides Module with StorageJacksonModule; provides ModuleLayerLoader with - MessageExchangeImpls.Loader, DataStoreProviders.Loader, + MessageExchangeImpls.Loader, + DataStoreProviders.Loader, ActionProvider.Loader, PrefsProvider.Loader, BrowserAction.Loader, diff --git a/core/src/main/java/io/xpipe/core/util/ModuleLayerLoader.java b/core/src/main/java/io/xpipe/core/util/ModuleLayerLoader.java index 11d86d7c0..216c97ec1 100644 --- a/core/src/main/java/io/xpipe/core/util/ModuleLayerLoader.java +++ b/core/src/main/java/io/xpipe/core/util/ModuleLayerLoader.java @@ -5,8 +5,7 @@ import java.util.function.Consumer; public interface ModuleLayerLoader { - static void loadAll( - ModuleLayer layer, Consumer errorHandler) { + static void loadAll(ModuleLayer layer, Consumer errorHandler) { ServiceLoader.load(layer, ModuleLayerLoader.class).stream().forEach(moduleLayerLoaderProvider -> { var instance = moduleLayerLoaderProvider.get(); try { @@ -20,5 +19,4 @@ public interface ModuleLayerLoader { default void init(ModuleLayer layer) {} default void reset() {} - } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/BackAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/BackAction.java index e3fc9d661..5b6a2ddca 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/BackAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/BackAction.java @@ -1,8 +1,8 @@ package io.xpipe.ext.base.browser; +import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.browser.file.BrowserEntry; import io.xpipe.app.browser.fs.OpenFileSystemModel; -import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.core.AppI18n; import javafx.beans.value.ObservableValue; import javafx.scene.Node; diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/BrowseInNativeManagerAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/BrowseInNativeManagerAction.java index 94db6d9f9..d6212caac 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/BrowseInNativeManagerAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/BrowseInNativeManagerAction.java @@ -1,8 +1,8 @@ package io.xpipe.ext.base.browser; +import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.browser.file.BrowserEntry; import io.xpipe.app.browser.fs.OpenFileSystemModel; -import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.core.AppI18n; import io.xpipe.core.process.OsType; import io.xpipe.core.process.ShellControl; diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/ChmodAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/ChmodAction.java index 290c2fd75..4d8c958da 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/ChmodAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/ChmodAction.java @@ -1,9 +1,9 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.file.BrowserEntry; -import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.browser.action.BranchAction; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.core.AppI18n; import io.xpipe.core.process.CommandBuilder; import io.xpipe.core.process.OsType; diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/CopyAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/CopyAction.java index c485a291f..d88268b4c 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/CopyAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/CopyAction.java @@ -1,9 +1,9 @@ package io.xpipe.ext.base.browser; import io.xpipe.app.browser.BrowserClipboard; +import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.browser.file.BrowserEntry; import io.xpipe.app.browser.fs.OpenFileSystemModel; -import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.core.AppI18n; import javafx.beans.value.ObservableValue; import javafx.scene.Node; diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/CopyPathAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/CopyPathAction.java index d2e3c01e3..fd792d9a9 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/CopyPathAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/CopyPathAction.java @@ -1,11 +1,11 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.file.BrowserEntry; -import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.browser.action.BranchAction; import io.xpipe.app.browser.action.BrowserAction; import io.xpipe.app.browser.action.BrowserActionFormatter; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.core.AppI18n; import io.xpipe.app.util.ClipboardHelper; import io.xpipe.core.store.FileKind; @@ -49,7 +49,7 @@ public class CopyPathAction implements BrowserAction, BranchAction { public ObservableValue getName(OpenFileSystemModel model, List entries) { if (entries.size() == 1) { return new SimpleObjectProperty<>(BrowserActionFormatter.centerEllipsis( - entries.getFirst().getRawFileEntry().getPath(), 50)); + entries.getFirst().getRawFileEntry().getPath(), 50)); } return AppI18n.observable("absolutePaths"); @@ -68,7 +68,7 @@ public class CopyPathAction implements BrowserAction, BranchAction { public ObservableValue getName(OpenFileSystemModel model, List entries) { if (entries.size() == 1) { return new SimpleObjectProperty<>(BrowserActionFormatter.centerEllipsis( - entries.getFirst().getRawFileEntry().getPath(), 50)); + entries.getFirst().getRawFileEntry().getPath(), 50)); } return AppI18n.observable("absoluteLinkPaths"); @@ -133,10 +133,9 @@ public class CopyPathAction implements BrowserAction, BranchAction { public ObservableValue getName(OpenFileSystemModel model, List entries) { if (entries.size() == 1) { return new SimpleObjectProperty<>(BrowserActionFormatter.centerEllipsis( - FileNames.getFileName(entries.getFirst() - .getRawFileEntry() - .getPath()), - 50)); + FileNames.getFileName( + entries.getFirst().getRawFileEntry().getPath()), + 50)); } return AppI18n.observable("fileNames"); @@ -156,10 +155,9 @@ public class CopyPathAction implements BrowserAction, BranchAction { public ObservableValue getName(OpenFileSystemModel model, List entries) { if (entries.size() == 1) { return new SimpleObjectProperty<>(BrowserActionFormatter.centerEllipsis( - FileNames.getFileName(entries.getFirst() - .getRawFileEntry() - .getPath()), - 50)); + FileNames.getFileName( + entries.getFirst().getRawFileEntry().getPath()), + 50)); } return AppI18n.observable("linkFileNames"); diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/DeleteAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/DeleteAction.java index 7f178ffa4..b5a86ea68 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/DeleteAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/DeleteAction.java @@ -1,10 +1,10 @@ package io.xpipe.ext.base.browser; +import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.browser.file.BrowserAlerts; import io.xpipe.app.browser.file.BrowserEntry; import io.xpipe.app.browser.file.FileSystemHelper; import io.xpipe.app.browser.fs.OpenFileSystemModel; -import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.core.AppI18n; import io.xpipe.core.store.FileKind; import javafx.beans.value.ObservableValue; @@ -46,10 +46,12 @@ public class DeleteAction implements LeafAction { @Override public ObservableValue getName(OpenFileSystemModel model, List entries) { - return AppI18n.observable("deleteFile",entries.stream() - .allMatch(browserEntry -> - browserEntry.getRawFileEntry().getKind() == FileKind.LINK) - ? " link" - : ""); + return AppI18n.observable( + "deleteFile", + entries.stream() + .allMatch(browserEntry -> + browserEntry.getRawFileEntry().getKind() == FileKind.LINK) + ? " link" + : ""); } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/DeleteLinkAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/DeleteLinkAction.java index d28c21c71..be7e0e62e 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/DeleteLinkAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/DeleteLinkAction.java @@ -1,9 +1,9 @@ package io.xpipe.ext.base.browser; +import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.browser.file.BrowserEntry; import io.xpipe.app.browser.file.FileSystemHelper; import io.xpipe.app.browser.fs.OpenFileSystemModel; -import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.core.AppI18n; import io.xpipe.core.store.FileKind; import javafx.beans.value.ObservableValue; diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/EditFileAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/EditFileAction.java index 0f56c12c9..50c1d7f8a 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/EditFileAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/EditFileAction.java @@ -1,8 +1,8 @@ package io.xpipe.ext.base.browser; +import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.browser.file.BrowserEntry; import io.xpipe.app.browser.fs.OpenFileSystemModel; -import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.core.AppI18n; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.util.FileOpener; diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/FileTypeAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/FileTypeAction.java index a65ea5c86..44363cc63 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/FileTypeAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/FileTypeAction.java @@ -1,8 +1,8 @@ package io.xpipe.ext.base.browser; +import io.xpipe.app.browser.action.BrowserAction; import io.xpipe.app.browser.file.BrowserEntry; import io.xpipe.app.browser.fs.OpenFileSystemModel; -import io.xpipe.app.browser.action.BrowserAction; import io.xpipe.app.browser.icon.BrowserIconFileType; import io.xpipe.app.browser.icon.BrowserIcons; import javafx.scene.Node; diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/ForwardAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/ForwardAction.java index 83ed5627e..0aa860955 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/ForwardAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/ForwardAction.java @@ -1,8 +1,8 @@ package io.xpipe.ext.base.browser; +import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.browser.file.BrowserEntry; import io.xpipe.app.browser.fs.OpenFileSystemModel; -import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.core.AppI18n; import javafx.beans.value.ObservableValue; import javafx.scene.Node; diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/JarAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/JarAction.java index a02c94981..12e13b85d 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/JarAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/JarAction.java @@ -1,9 +1,9 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.file.BrowserEntry; -import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.browser.action.BrowserActionFormatter; import io.xpipe.app.browser.action.MultiExecuteAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.browser.icon.BrowserIconFileType; import io.xpipe.core.process.CommandBuilder; import io.xpipe.core.process.ShellControl; @@ -31,7 +31,9 @@ public class JarAction extends MultiExecuteAction implements JavaAction, FileTyp @Override protected CommandBuilder createCommand(ShellControl sc, OpenFileSystemModel model, BrowserEntry entry) { - return CommandBuilder.of().add("java", "-jar").addFile(entry.getRawFileEntry().getPath()); + return CommandBuilder.of() + .add("java", "-jar") + .addFile(entry.getRawFileEntry().getPath()); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/JavapAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/JavapAction.java index 8150e9ecf..2d30c0162 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/JavapAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/JavapAction.java @@ -1,9 +1,9 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.file.BrowserEntry; -import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.browser.action.BrowserActionFormatter; import io.xpipe.app.browser.action.ToFileCommandAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.browser.icon.BrowserIconFileType; import javafx.beans.property.SimpleStringProperty; import javafx.beans.value.ObservableValue; diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/NewItemAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/NewItemAction.java index fb915ccbc..eb5a17411 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/NewItemAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/NewItemAction.java @@ -1,10 +1,10 @@ package io.xpipe.ext.base.browser; -import io.xpipe.app.browser.file.BrowserEntry; -import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.browser.action.BranchAction; import io.xpipe.app.browser.action.BrowserAction; import io.xpipe.app.browser.action.LeafAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.browser.icon.BrowserIcons; import io.xpipe.app.comp.base.ModalOverlayComp; import io.xpipe.app.core.AppI18n; diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryAction.java index 3f286fc93..b2e9e7dbc 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryAction.java @@ -1,8 +1,8 @@ package io.xpipe.ext.base.browser; +import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.browser.file.BrowserEntry; import io.xpipe.app.browser.fs.OpenFileSystemModel; -import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.core.AppI18n; import io.xpipe.core.store.FileKind; import javafx.beans.value.ObservableValue; 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 973397ad2..541be09ea 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 @@ -1,8 +1,8 @@ package io.xpipe.ext.base.browser; +import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.browser.file.BrowserEntry; import io.xpipe.app.browser.fs.OpenFileSystemModel; -import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.browser.session.BrowserSessionModel; import io.xpipe.app.core.AppI18n; import io.xpipe.core.store.FileKind; @@ -17,7 +17,8 @@ public class OpenDirectoryInNewTabAction implements LeafAction { @Override public void execute(OpenFileSystemModel model, List entries) { if (model.getBrowserModel() instanceof BrowserSessionModel bm) { - bm.openFileSystemAsync(model.getEntry(), m -> entries.getFirst().getRawFileEntry().getPath(), null); + bm.openFileSystemAsync( + model.getEntry(), m -> entries.getFirst().getRawFileEntry().getPath(), null); } } @@ -43,7 +44,8 @@ public class OpenDirectoryInNewTabAction implements LeafAction { @Override public boolean isApplicable(OpenFileSystemModel model, List entries) { - return model.getBrowserModel() instanceof BrowserSessionModel && entries.size() == 1 + return model.getBrowserModel() instanceof BrowserSessionModel + && entries.size() == 1 && entries.stream().allMatch(entry -> entry.getRawFileEntry().getKind() == FileKind.DIRECTORY); } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenFileDefaultAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenFileDefaultAction.java index 4eba05b0f..132fc2ec5 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenFileDefaultAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenFileDefaultAction.java @@ -1,8 +1,8 @@ package io.xpipe.ext.base.browser; +import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.browser.file.BrowserEntry; import io.xpipe.app.browser.fs.OpenFileSystemModel; -import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.core.AppI18n; import io.xpipe.app.util.FileOpener; import io.xpipe.core.store.FileKind; diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenFileWithAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenFileWithAction.java index 0dfaa0bbd..5a30be795 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenFileWithAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenFileWithAction.java @@ -1,8 +1,8 @@ package io.xpipe.ext.base.browser; +import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.browser.file.BrowserEntry; import io.xpipe.app.browser.fs.OpenFileSystemModel; -import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.core.AppI18n; import io.xpipe.app.util.FileOpener; import io.xpipe.core.process.OsType; diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenNativeFileDetailsAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenNativeFileDetailsAction.java index 221f9efa7..ea4519ad3 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenNativeFileDetailsAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenNativeFileDetailsAction.java @@ -1,8 +1,8 @@ package io.xpipe.ext.base.browser; +import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.browser.file.BrowserEntry; import io.xpipe.app.browser.fs.OpenFileSystemModel; -import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.core.AppI18n; import io.xpipe.app.util.LocalShell; import io.xpipe.core.process.OsType; diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenTerminalAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenTerminalAction.java index c303d5109..f80fb474c 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenTerminalAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenTerminalAction.java @@ -1,8 +1,8 @@ package io.xpipe.ext.base.browser; +import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.browser.file.BrowserEntry; import io.xpipe.app.browser.fs.OpenFileSystemModel; -import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.core.AppI18n; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.core.store.FileKind; diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/PasteAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/PasteAction.java index 759b8d796..4c4051970 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/PasteAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/PasteAction.java @@ -1,9 +1,9 @@ package io.xpipe.ext.base.browser; import io.xpipe.app.browser.BrowserClipboard; +import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.browser.file.BrowserEntry; import io.xpipe.app.browser.fs.OpenFileSystemModel; -import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.core.AppI18n; import io.xpipe.core.store.FileKind; import javafx.beans.value.ObservableValue; diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/RefreshDirectoryAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/RefreshDirectoryAction.java index e5036d700..2afec70bb 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/RefreshDirectoryAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/RefreshDirectoryAction.java @@ -1,8 +1,8 @@ package io.xpipe.ext.base.browser; +import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.browser.file.BrowserEntry; import io.xpipe.app.browser.fs.OpenFileSystemModel; -import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.core.AppI18n; import javafx.beans.value.ObservableValue; import javafx.scene.Node; diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/RenameAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/RenameAction.java index 79fe068e0..72883f5fe 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/RenameAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/RenameAction.java @@ -1,8 +1,8 @@ package io.xpipe.ext.base.browser; +import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.browser.file.BrowserEntry; import io.xpipe.app.browser.fs.OpenFileSystemModel; -import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.core.AppI18n; import io.xpipe.core.store.FileKind; import javafx.beans.value.ObservableValue; diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/RunAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/RunAction.java index f60603e6c..4bc60f1ea 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/RunAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/RunAction.java @@ -1,8 +1,8 @@ package io.xpipe.ext.base.browser; +import io.xpipe.app.browser.action.MultiExecuteAction; import io.xpipe.app.browser.file.BrowserEntry; import io.xpipe.app.browser.fs.OpenFileSystemModel; -import io.xpipe.app.browser.action.MultiExecuteAction; import io.xpipe.app.core.AppI18n; import io.xpipe.core.process.CommandBuilder; import io.xpipe.core.process.OsType; @@ -73,6 +73,8 @@ public class RunAction extends MultiExecuteAction { } protected CommandBuilder createCommand(ShellControl sc, OpenFileSystemModel model, BrowserEntry entry) { - return CommandBuilder.of().add(sc.getShellDialect().runScriptCommand(sc, entry.getRawFileEntry().getPath())); + return CommandBuilder.of() + .add(sc.getShellDialect() + .runScriptCommand(sc, entry.getRawFileEntry().getPath())); } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/UnzipAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/UnzipAction.java index 16dbb45c2..2acc313e7 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/UnzipAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/UnzipAction.java @@ -1,8 +1,8 @@ package io.xpipe.ext.base.browser; +import io.xpipe.app.browser.action.ExecuteApplicationAction; import io.xpipe.app.browser.file.BrowserEntry; import io.xpipe.app.browser.fs.OpenFileSystemModel; -import io.xpipe.app.browser.action.ExecuteApplicationAction; import io.xpipe.app.browser.icon.BrowserIconFileType; import io.xpipe.core.process.OsType; import io.xpipe.core.store.FileNames; diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptStore.java b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptStore.java index 5098e1602..548b6c2bb 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptStore.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptStore.java @@ -114,7 +114,9 @@ public abstract class ScriptStore extends JacksonizedValue implements DataStore, .mapToInt(value -> value.get().getName().hashCode() + value.getStore().hashCode()) .sum(); - var targetDir = ShellTemp.getUserSpecificTempDataDirectory(proc, "scripts").join(proc.getShellDialect().getId()).toString(); + var targetDir = ShellTemp.getUserSpecificTempDataDirectory(proc, "scripts") + .join(proc.getShellDialect().getId()) + .toString(); var hashFile = FileNames.join(targetDir, "hash"); var d = proc.getShellDialect(); if (d.createFileExistsCommand(proc, hashFile).executeAndCheck()) { @@ -136,8 +138,9 @@ public abstract class ScriptStore extends JacksonizedValue implements DataStore, for (DataStoreEntryRef scriptStore : refs) { var content = d.prepareScriptContent(scriptStore.getStore().getCommands()); - var fileName = proc.getOsType().makeFileSystemCompatible( - scriptStore.get().getName().toLowerCase(Locale.ROOT).replaceAll(" ", "_")); + var fileName = proc.getOsType() + .makeFileSystemCompatible( + scriptStore.get().getName().toLowerCase(Locale.ROOT).replaceAll(" ", "_")); var scriptFile = FileNames.join(targetDir, fileName + "." + d.getScriptFileEnding()); d.createScriptTextFileWriteCommand(proc, content, scriptFile).execute(); } diff --git a/lang/app/strings/translations_fr.properties b/lang/app/strings/translations_fr.properties new file mode 100644 index 000000000..5b6dcad91 --- /dev/null +++ b/lang/app/strings/translations_fr.properties @@ -0,0 +1,420 @@ +delete=Effacer +rename=Renommer +properties=Propriétés +usedDate=Utilisé $DATE$ +openDir=Répertoire ouvert +sortLastUsed=Trier par date de dernière utilisation +sortAlphabetical=Tri alphabétique par nom +restart=Redémarrer XPipe +restartDescription=Un redémarrage peut souvent être une solution rapide +reportIssue=Signaler un problème +reportIssueDescription=Ouvre le rapporteur de questions intégré +usefulActions=Actions utiles +stored=Sauvegardé +troubleshootingOptions=Outils de dépannage +troubleshoot=Dépannage +remote=Fichier distant +addShellStore=Ajouter une coquille ... +addShellTitle=Ajouter une connexion Shell +savedConnections=Connexions sauvegardées +save=Sauvegarde +clean=Nettoyer +refresh=Rafraîchir +moveTo=Déplacer vers ... +addDatabase=Base de données ... +browseInternalStorage=Parcourir la mémoire interne +addTunnel=Tunnel ... +addScript=Script ... +addHost=Hôte distant ... +addShell=Environnement Shell ... +addCommand=Commande personnalisée ... +addAutomatically=Recherche automatique ... +addOther=Ajouter d'autres... +addConnection=Ajouter une connexion +skip=Sauter +addConnections=Nouveau +selectType=Sélectionner un type +selectTypeDescription=Sélectionne le type de connexion +selectShellType=Type de coquille +selectShellTypeDescription=Sélectionne le type de connexion Shell +name=Nom +storeIntroTitle=Hub de connexion +storeIntroDescription=Ici, tu peux gérer toutes tes connexions shell locales et distantes en un seul endroit. Pour commencer, tu peux rapidement détecter automatiquement les connexions disponibles et choisir celles que tu veux ajouter. +detectConnections=Recherche de connexions +configuration=Configuration +dragAndDropFilesHere=Ou bien tu peux simplement glisser et déposer un fichier ici +confirmDsCreationAbortTitle=Confirmer l'abandon +confirmDsCreationAbortHeader=Veux-tu interrompre la création de la source de données ? +confirmDsCreationAbortContent=Tout progrès dans la création de la source de données sera perdu. +confirmInvalidStoreTitle=Échec de la connexion +confirmInvalidStoreHeader=Veux-tu ignorer la validation de la connexion ? +confirmInvalidStoreContent=Tu peux ajouter cette connexion même si elle n'a pas pu être validée et régler les problèmes de connexion ultérieurement. +none=Aucun +expand=Élargir +accessSubConnections=Accès aux sous-connexions +common=Commun +color=Couleur +alwaysConfirmElevation=Toujours confirmer l'élévation de la permission +alwaysConfirmElevationDescription=Contrôle la façon de gérer les cas où des autorisations élevées sont nécessaires pour exécuter une commande sur un système, par exemple avec sudo.\n\nPar défaut, toutes les informations d'identification sudo sont mises en cache au cours d'une session et fournies automatiquement en cas de besoin. Si cette option est activée, il te sera demandé de confirmer l'accès en élévation à chaque fois. +allow=Permettre +ask=Demande +deny=Refuser +share=Ajouter au dépôt git +unshare=Retirer du dépôt git +remove=Enlever +newCategory=Nouvelle sous-catégorie +passwordManager=Gestionnaire de mots de passe +prompt=Invite +customCommand=Commande personnalisée +other=Autre +setLock=Verrouiller +selectConnection=Sélectionner une connexion +changeLock=Changer de phrase de passe +test=Test +lockCreationAlertTitle=Définir une phrase de passe +lockCreationAlertHeader=Définis ta nouvelle phrase de passe principale +finish=Finir +error=Une erreur s'est produite +downloadStageDescription=Télécharge les fichiers sur ta machine locale, afin que tu puisses les faire glisser et les déposer dans ton environnement de bureau natif. +ok=Ok +search=Rechercher +newFile=Nouveau fichier +newDirectory=Nouveau répertoire +passphrase=Phrase de passe +repeatPassphrase=Répéter la phrase de passe +password=Mot de passe +unlockAlertTitle=Déverrouiller l'espace de travail +unlockAlertHeader=Saisis ta phrase d'authentification du coffre-fort pour continuer +enterLockPassword=Saisir le mot de passe de la serrure +repeatPassword=Répéter le mot de passe +askpassAlertTitle=Askpass +unsupportedOperation=Opération non prise en charge : $MSG$ +fileConflictAlertTitle=Résoudre un conflit +fileConflictAlertHeader=Un conflit a été rencontré. Comment veux-tu procéder ? +fileConflictAlertContent=Le fichier $FILE$ existe déjà sur le système cible. +fileConflictAlertContentMultiple=Le fichier $FILE$ existe déjà. Il peut y avoir d'autres conflits que tu peux résoudre automatiquement en choisissant une option qui s'applique à tous. +moveAlertTitle=Confirmer un mouvement +moveAlertHeader=Veux-tu déplacer les ($COUNT$) éléments sélectionnés dans $TARGET$? +deleteAlertTitle=Confirmer la suppression +deleteAlertHeader=Veux-tu supprimer les ($COUNT$) éléments sélectionnés ? +selectedElements=Éléments sélectionnés : +mustNotBeEmpty=$VALUE$ ne doit pas être vide +valueMustNotBeEmpty=La valeur ne doit pas être vide +transferDescription=Dépose des fichiers à transférer +dragFiles=Faire glisser des fichiers dans le navigateur +dragLocalFiles=Fais glisser des fichiers locaux à partir d'ici +null=$VALUE$ doit être non nul +roots=Racines +scripts=Scripts +searchFilter=Recherche ... +recent=Récent +shortcut=Raccourci +browserWelcomeEmpty=Ici, tu pourras voir où tu t'es arrêté la dernière fois. +browserWelcomeSystems=Tu as récemment été connecté aux systèmes suivants : +hostFeatureUnsupported=$FEATURE$ n'est pas installé sur l'hôte +missingStore=$NAME$ n'existe pas +connectionName=Nom de la connexion +connectionNameDescription=Donne un nom personnalisé à cette connexion +openFileTitle=Ouvrir un fichier +unknown=Inconnu +scanAlertTitle=Ajouter des connexions +scanAlertChoiceHeader=Cible +scanAlertChoiceHeaderDescription=Choisis où rechercher les connexions. Cela permet de rechercher d'abord toutes les connexions disponibles. +scanAlertHeader=Types de connexion +scanAlertHeaderDescription=Sélectionne les types de connexions que tu veux ajouter automatiquement pour le système. +noInformationAvailable=Aucune information disponible +localMachine=Machine locale +yes=Oui +no=Non +errorOccured=Une erreur s'est produite +terminalErrorOccured=Une erreur de terminal s'est produite +errorTypeOccured=Une exception de type $TYPE$ a été lancée +permissionsAlertTitle=Permissions requises +permissionsAlertHeader=Des autorisations supplémentaires sont nécessaires pour effectuer cette opération. +permissionsAlertContent=Suis le pop-up pour donner à XPipe les autorisations nécessaires dans le menu des paramètres. +errorDetails=Afficher les détails +updateReadyAlertTitle=Prêt pour la mise à jour +updateReadyAlertHeader=Une mise à jour de la version $VERSION$ est prête à être installée +updateReadyAlertContent=Cela installera la nouvelle version et redémarrera XPipe une fois l'installation terminée. +errorNoDetail=Aucun détail d'erreur n'est disponible +updateAvailableTitle=Mise à jour disponible +updateAvailableHeader=Une mise à jour de XPipe vers la version $VERSION$ est disponible à l'installation +updateAvailableContent=Même si XPipe n'a pas pu être démarré, tu peux essayer d'installer la mise à jour pour éventuellement résoudre le problème. +clipboardActionDetectedTitle=Action du presse-papiers détectée +clipboardActionDetectedHeader=Veux-tu importer le contenu de ton presse-papiers ? +clipboardActionDetectedContent=XPipe a détecté dans ton presse-papiers un contenu qui peut être ouvert. Veux-tu l'ouvrir maintenant ? +install=Installer ... +ignore=Ignorer +possibleActions=Actions possibles +reportError=Erreur de rapport +reportOnGithub=Créer un rapport de problème sur GitHub +reportOnGithubDescription=Ouvre un nouveau problème dans le dépôt GitHub +reportErrorDescription=Envoyer un rapport d'erreur avec un retour d'information optionnel de l'utilisateur et des informations de diagnostic +ignoreError=Ignorer l'erreur +ignoreErrorDescription=Ignore cette erreur et continue comme si de rien n'était +provideEmail=Comment te contacter (facultatif, uniquement si tu veux être informé des correctifs) +additionalErrorInfo=Fournir des informations supplémentaires (facultatif) +additionalErrorAttachments=Sélectionne les pièces jointes (facultatif) +dataHandlingPolicies=Politique de confidentialité +sendReport=Envoyer un rapport +errorHandler=Gestionnaire d'erreurs +events=Les événements +method=Méthode +validate=Valider +stackTrace=Trace de pile +previousStep=< Précédent +nextStep=Suivant > +finishStep=Finir +edit=Éditer +browseInternal=Parcourir l'intérieur +checkOutUpdate=Vérifier la mise à jour +open=Ouvrir +quit=Quitter +noTerminalSet=Aucune application de terminal n'a été réglée automatiquement. Tu peux le faire manuellement dans le menu des paramètres. +connections=Raccordements +settings=Paramètres +explorePlans=Licence +help=Aide +about=A propos de +developer=Développeur +browseFileTitle=Parcourir le fichier +browse=Parcourir +browser=Navigateur +selectFileFromComputer=Sélectionne un fichier sur cet ordinateur +links=Liens utiles +website=Site web +documentation=Documentation +discordDescription=Rejoins le serveur Discord +security=Sécurité +securityPolicy=Informations de sécurité +securityPolicyDescription=Lire la politique de sécurité détaillée +privacy=Politique de confidentialité +privacyDescription=Lis la politique de confidentialité de l'application XPipe +slackDescription=Rejoins l'espace de travail Slack +support=Support +githubDescription=Jette un coup d'œil au dépôt GitHub +openSourceNotices=Avis Open Source +xPipeClient=XPipe Desktop +checkForUpdates=Vérifier les mises à jour +checkForUpdatesDescription=Télécharger une mise à jour s'il y en a une +lastChecked=Dernière vérification +version=Version +build=Version de construction +runtimeVersion=Version d'exécution +virtualMachine=Machine virtuelle +updateReady=Installer une mise à jour +updateReadyPortable=Vérifier la mise à jour +updateReadyDescription=Une mise à jour a été téléchargée et est prête à être installée +updateReadyDescriptionPortable=Une mise à jour est disponible au téléchargement +updateRestart=Redémarre pour mettre à jour +never=Jamais +updateAvailableTooltip=Mise à jour disponible +visitGithubRepository=Visiter le dépôt GitHub +updateAvailable=Mise à jour disponible : $VERSION$ +downloadUpdate=Télécharger la mise à jour +legalAccept=J'accepte le contrat de licence de l'utilisateur final +confirm=Confirmer +print=Imprimer +whatsNew=Nouveautés de la version $VERSION$ ($DATE$) +antivirusNoticeTitle=Une note sur les programmes antivirus +updateChangelogAlertTitle=Changelog +greetingsAlertTitle=Bienvenue à XPipe +gotIt=Compris +eula=Contrat de licence de l'utilisateur final +news=Nouvelles +introduction=Introduction +privacyPolicy=Politique de confidentialité +agree=Accepte +disagree=Ne pas être d'accord +directories=Répertoires +logFile=Fichier journal +logFiles=Fichiers journaux +logFilesAttachment=Fichiers journaux +issueReporter=Rapporteur de problèmes +openCurrentLogFile=Fichiers journaux +openCurrentLogFileDescription=Ouvrir le fichier journal de la session en cours +openLogsDirectory=Ouvrir le répertoire des journaux +installationFiles=Fichiers d'installation +openInstallationDirectory=Fichiers d'installation +openInstallationDirectoryDescription=Ouvrir le répertoire d'installation de XPipe +launchDebugMode=Mode débogage +launchDebugModeDescription=Redémarre XPipe en mode débogage +extensionInstallTitle=Télécharger +extensionInstallDescription=Cette action nécessite des bibliothèques tierces supplémentaires qui ne sont pas distribuées par XPipe. Tu peux les installer automatiquement ici. Les composants sont ensuite téléchargés à partir du site web du fournisseur : +extensionInstallLicenseNote=En effectuant le téléchargement et l'installation automatique, tu acceptes les termes des licences des tiers : +license=Licence +installRequired=Installation requise +restore=Restaurer +restoreAllSessions=Restaurer toutes les sessions +connectionTimeout=Délai de démarrage de la connexion +connectionTimeoutDescription=Le temps en secondes à attendre une réponse avant de considérer qu'une connexion est dépassée. Si certains de tes systèmes distants mettent du temps à se connecter, tu peux essayer d'augmenter cette valeur. +useBundledTools=Utilise les outils OpenSSH fournis +useBundledToolsDescription=Préfère utiliser la version fournie du client openssh plutôt que celle installée localement.\n\nCette version est généralement plus à jour que celles livrées sur ton système et peut prendre en charge des fonctionnalités supplémentaires. Cela élimine également la nécessité d'installer ces outils en premier lieu.\n\nUn redémarrage est nécessaire pour l'appliquer. +appearance=Apparence +integrations=Intégrations +uiOptions=Options de l'interface utilisateur +theme=Thème +rdp=Bureau à distance +rdpConfiguration=Configuration du bureau à distance +rdpClient=Client RDP +rdpClientDescription=Le programme client RDP à appeler lors du lancement des connexions RDP.\n\nNote que les divers clients ont différents degrés de capacités et d'intégrations. Certains clients ne prennent pas en charge le passage automatique des mots de passe, tu dois donc toujours les remplir au lancement. +localShell=Shell local +themeDescription=Ton thème d'affichage préféré +dontAutomaticallyStartVmSshServer=Ne démarre pas automatiquement le serveur SSH pour les machines virtuelles lorsque c'est nécessaire +dontAutomaticallyStartVmSshServerDescription=Toute connexion shell à une VM fonctionnant dans un hyperviseur se fait par l'intermédiaire de SSH. XPipe peut démarrer automatiquement le serveur SSH installé lorsque cela est nécessaire. Si tu ne le souhaites pas pour des raisons de sécurité, tu peux simplement désactiver ce comportement avec cette option. +confirmGitShareTitle=Confirmer le partage git +confirmGitShareHeader=Cela copiera le fichier dans ton coffre-fort git et validera tes modifications. Veux-tu continuer ? +gitShareFileTooltip=Ajoute un fichier au répertoire de données de git vault pour qu'il soit automatiquement synchronisé.\n\nCette action ne peut être utilisée que lorsque le git vault est activé dans les paramètres. +performanceMode=Mode performance +performanceModeDescription=Désactive tous les effets visuels qui ne sont pas nécessaires afin d'améliorer les performances de l'application. +dontAcceptNewHostKeys=N'accepte pas automatiquement les nouvelles clés d'hôte SSH +dontAcceptNewHostKeysDescription=XPipe acceptera automatiquement par défaut les clés d'hôte des systèmes pour lesquels ton client SSH n'a pas de clé d'hôte connue déjà enregistrée. Cependant, si une clé d'hôte connue a changé, il refusera de se connecter si tu n'acceptes pas la nouvelle.\n\nLa désactivation de ce comportement te permet de vérifier toutes les clés d'hôte, même s'il n'y a pas de conflit au départ. +uiScale=Échelle de l'interface utilisateur +uiScaleDescription=Une valeur d'échelle personnalisée qui peut être définie indépendamment de l'échelle d'affichage du système. Les valeurs sont exprimées en pourcentage. Ainsi, une valeur de 150 se traduira par une échelle d'affichage de 150 %.\n\nIl faut redémarrer l'ordinateur pour l'appliquer. +editorProgram=Programme d'édition +editorProgramDescription=L'éditeur de texte par défaut à utiliser lors de l'édition de n'importe quel type de données textuelles. +windowOpacity=Opacité de la fenêtre +windowOpacityDescription=Modifie l'opacité de la fenêtre pour suivre ce qui se passe en arrière-plan. +useSystemFont=Utilise la police du système +openDataDir=Répertoire de données de voûte +openDataDirButton=Répertoire de données ouvertes +openDataDirDescription=Si tu veux synchroniser des fichiers supplémentaires, comme les clés SSH, entre les systèmes avec ton dépôt git, tu peux les mettre dans le répertoire storage data. Tous les fichiers qui y sont référencés verront leur chemin de fichier automatiquement adapté sur n'importe quel système synchronisé. +updates=Mises à jour +passwordKey=Clé de mot de passe +selectAll=Sélectionne tout +command=Commande +advanced=Avancé +thirdParty=Avis de source ouverte +eulaDescription=Lis le contrat de licence de l'utilisateur final pour l'application XPipe +thirdPartyDescription=Voir les licences open source des bibliothèques tierces +workspaceLock=Phrase de passe principale +enableGitStorage=Activer la synchronisation git +sharing=Partage +sync=Synchronisation +enableGitStorageDescription=Lorsqu'il est activé, XPipe initialisera un dépôt git pour le stockage des données de connexion et y livrera toutes les modifications. Note que cela nécessite l'installation de git et peut ralentir les opérations de chargement et d'enregistrement.\n\nToutes les catégories qui doivent être synchronisées doivent être explicitement désignées comme partagées.\n\nNécessite un redémarrage pour être appliqué. +storageGitRemote=URL distante de Git +storageGitRemoteDescription=Lorsque cette option est activée, XPipe récupère automatiquement toutes les modifications lors du chargement et les transfère vers le référentiel distant lors de l'enregistrement.\n\nCela te permet de partager tes données de configuration entre plusieurs installations de XPipe. Les URL HTTP et SSH sont prises en charge. Note que cela peut ralentir les opérations de chargement et d'enregistrement.\n\nL'application nécessite un redémarrage. +vault=Voûte +workspaceLockDescription=Définit un mot de passe personnalisé pour crypter toute information sensible stockée dans XPipe.\n\nCela se traduit par une sécurité accrue car cela fournit une couche supplémentaire de cryptage pour tes informations sensibles stockées. Tu seras alors invité à saisir le mot de passe au démarrage de XPipe. +useSystemFontDescription=Contrôle l'utilisation de la police de ton système ou de la police Roboto fournie avec XPipe. +tooltipDelay=Délai de l'infobulle +tooltipDelayDescription=Le nombre de millisecondes à attendre avant l'affichage d'une info-bulle. +fontSize=Taille de la police +windowOptions=Options de la fenêtre +saveWindowLocation=Emplacement de la fenêtre de sauvegarde +saveWindowLocationDescription=Contrôle si les coordonnées de la fenêtre doivent être sauvegardées et restaurées lors des redémarrages. +startupShutdown=Démarrage / Arrêt +showChildCategoriesInParentCategory=Afficher les catégories enfants dans la catégorie parent +showChildCategoriesInParentCategoryDescription=Inclure ou non toutes les connexions situées dans les sous-catégories lorsqu'une certaine catégorie parentale est sélectionnée.\n\nSi cette option est désactivée, les catégories se comportent davantage comme des dossiers classiques qui n'affichent que leur contenu direct sans inclure les sous-dossiers. +condenseConnectionDisplay=Condenser l'affichage des connexions +condenseConnectionDisplayDescription=Faire en sorte que chaque connexion de niveau supérieur prenne moins d'espace vertical pour permettre une liste de connexions plus condensée. +enforceWindowModality=Modalité de la fenêtre d'application +enforceWindowModalityDescription=Fait en sorte que les fenêtres secondaires, telles que la boîte de dialogue de création de connexion, bloquent toute saisie pour la fenêtre principale tant qu'elles sont ouvertes. C'est utile s'il t'arrive de mal cliquer. +openConnectionSearchWindowOnConnectionCreation=Ouvrir la fenêtre de recherche de connexion lors de la création de la connexion +openConnectionSearchWindowOnConnectionCreationDescription=Ouverture automatique ou non de la fenêtre de recherche des sous-connexions disponibles lors de l'ajout d'une nouvelle connexion shell. +workflow=Flux de travail +system=Système +application=Application +storage=Stockage +runOnStartup=Exécuter au démarrage +closeBehaviour=Fermer le comportement +closeBehaviourDescription=Contrôle la façon dont XPipe doit procéder à la fermeture de sa fenêtre principale. +language=Langue +languageDescription=La langue d'affichage à utiliser.\n\nNote que celles-ci utilisent les traductions automatiques comme base et sont corrigées et améliorées manuellement par les contributeurs. Tu peux également contribuer à l'effort de traduction en soumettant des correctifs de traduction sur GitHub. +lightTheme=Thème lumineux +darkTheme=Thème sombre +exit=Quitter XPipe +continueInBackground=Continue en arrière-plan +minimizeToTray=Minimiser dans la barre d'état +closeBehaviourAlertTitle=Définir le comportement de fermeture +closeBehaviourAlertTitleHeader=Sélectionne ce qui doit se passer lors de la fermeture de la fenêtre. Toutes les connexions actives seront fermées lorsque l'application sera arrêtée. +startupBehaviour=Comportement au démarrage +startupBehaviourDescription=Contrôle le comportement par défaut de l'application de bureau lorsque XPipe est démarré. +clearCachesAlertTitle=Nettoyer le cache +clearCachesAlertTitleHeader=Veux-tu nettoyer tous les caches de XPipe ? +clearCachesAlertTitleContent=Note que cela supprimera toutes les données qui sont stockées pour améliorer l'expérience de l'utilisateur. +startGui=Démarrer l'interface graphique +startInTray=Démarrer dans la barre d'état +startInBackground=Démarrer en arrière-plan +clearCaches=Vider les caches ... +clearCachesDescription=Efface toutes les données du cache +apply=Appliquer +cancel=Annuler +notAnAbsolutePath=Pas un chemin absolu +notADirectory=Pas un répertoire +notAnEmptyDirectory=Pas un répertoire vide +automaticallyUpdate=Vérifier les mises à jour +automaticallyUpdateDescription=Lorsque cette option est activée, les informations sur les nouvelles versions sont automatiquement récupérées lorsque XPipe est en cours d'exécution. Aucun programme de mise à jour n'est exécuté en arrière-plan, et tu dois toujours confirmer explicitement l'installation d'une mise à jour. +sendAnonymousErrorReports=Envoyer des rapports d'erreur anonymes +sendUsageStatistics=Envoyer des statistiques d'utilisation anonymes +storageDirectory=Répertoire de stockage +storageDirectoryDescription=L'emplacement où XPipe doit stocker toutes les informations de connexion. Ce paramètre ne sera appliqué qu'au prochain redémarrage. Lorsqu'on le modifie, les données de l'ancien répertoire ne sont pas copiées dans le nouveau. +logLevel=Niveau du journal +appBehaviour=Comportement de l'application +logLevelDescription=Le niveau de journal qui doit être utilisé lors de l'écriture des fichiers journaux. +developerMode=Mode développeur +developerModeDescription=Lorsque cette option est activée, tu as accès à toute une série d'options supplémentaires utiles pour le développement. N'est actif qu'après un redémarrage. +editor=Éditeur +custom=Personnalisé +passwordManagerCommand=Commande du gestionnaire de mots de passe +passwordManagerCommandDescription=La commande à exécuter pour récupérer les mots de passe. La chaîne de caractères de remplacement $KEY sera remplacée par la clé de mot de passe citée lorsqu'elle sera appelée. Cette commande devrait appeler ton gestionnaire de mots de passe CLI pour imprimer le mot de passe sur stdout, par exemple mypassmgr get $KEY.\n\nTu peux ensuite configurer la clé pour qu'elle soit récupérée chaque fois que tu établis une connexion qui nécessite un mot de passe. +passwordManagerCommandTest=Test du gestionnaire de mot de passe +passwordManagerCommandTestDescription=Tu peux tester ici si la sortie semble correcte si tu as mis en place une commande de gestionnaire de mot de passe. La commande ne doit sortir que le mot de passe lui-même sur stdout, aucun autre formatage ne doit être inclus dans la sortie. +preferEditorTabs=Préfère ouvrir de nouveaux onglets +preferEditorTabsDescription=Contrôle si XPipe essaiera d'ouvrir de nouveaux onglets dans l'éditeur que tu as choisi au lieu de nouvelles fenêtres.\n\nNote que ce n'est pas le cas de tous les éditeurs. +customRdpClientCommand=Commande personnalisée +customRdpClientCommandDescription=La commande à exécuter pour démarrer le client RDP personnalisé.\n\nLa chaîne de caractères $FILE sera remplacée par le nom du fichier .rdp absolu entre guillemets lorsqu'elle sera appelée. N'oublie pas de citer ton chemin d'accès à l'exécutable s'il contient des espaces. +customEditorCommand=Commande personnalisée de l'éditeur +customEditorCommandDescription=La commande à exécuter pour démarrer l'éditeur personnalisé.\n\nLa chaîne de caractères de remplacement $FILE sera remplacée par le nom de fichier absolu entre guillemets lorsqu'elle sera appelée. N'oublie pas de citer le chemin d'accès à l'exécutable de ton éditeur s'il contient des espaces. +editorReloadTimeout=Délai de rechargement de l'éditeur +editorReloadTimeoutDescription=Le nombre de millisecondes à attendre avant de lire un fichier après sa mise à jour. Cela permet d'éviter les problèmes dans les cas où ton éditeur est lent à écrire ou à libérer les verrous de fichiers. +encryptAllVaultData=Crypte toutes les données du coffre-fort +encryptAllVaultDataDescription=Lorsque cette option est activée, toutes les données de connexion au coffre-fort sont cryptées, alors que seuls les secrets contenus dans ces données le sont. Cela ajoute une couche de sécurité supplémentaire pour d'autres paramètres tels que les noms d'utilisateur, les noms d'hôte, etc. qui ne sont pas cryptés par défaut dans le coffre-fort.\n\nCette option rendra l'historique de ton coffre-fort git et les diffs inutiles car tu ne pourras plus voir les modifications originales, seulement les modifications binaires. +vaultSecurity=Sécurité des voûtes +developerDisableUpdateVersionCheck=Désactiver la vérification de la version de la mise à jour +developerDisableUpdateVersionCheckDescription=Contrôle si le vérificateur de mise à jour ignore le numéro de version lorsqu'il recherche une mise à jour. +developerDisableGuiRestrictions=Désactiver les restrictions de l'interface graphique +developerDisableGuiRestrictionsDescription=Contrôle si certaines actions désactivées peuvent encore être exécutées à partir de l'interface utilisateur. +developerShowHiddenEntries=Afficher les entrées cachées +developerShowHiddenEntriesDescription=Lorsque cette option est activée, les sources de données cachées et internes sont affichées. +developerShowHiddenProviders=Afficher les fournisseurs cachés +developerShowHiddenProvidersDescription=Contrôle si les fournisseurs de connexion et de source de données cachés et internes seront affichés dans la boîte de dialogue de création. +developerDisableConnectorInstallationVersionCheck=Désactiver la vérification de la version du connecteur +developerDisableConnectorInstallationVersionCheckDescription=Contrôle si le vérificateur de mise à jour ignore le numéro de version lorsqu'il inspecte la version d'un connecteur XPipe installé sur une machine distante. +shellCommandTest=Test de commande Shell +shellCommandTestDescription=Exécute une commande dans la session shell utilisée en interne par XPipe. +terminal=Terminal +terminalEmulator=Émulateur de terminal +terminalConfiguration=Configuration du terminal +editorConfiguration=Configuration de l'éditeur +defaultApplication=Application par défaut +terminalEmulatorDescription=Le terminal par défaut à utiliser lors de l'ouverture de tout type de connexion shell. Cette application n'est utilisée qu'à des fins d'affichage, le programme shell démarré dépend de la connexion shell elle-même.\n\nLe niveau de prise en charge des fonctionnalités varie d'un terminal à l'autre, c'est pourquoi chacun d'entre eux est marqué comme recommandé ou non recommandé. Tous les terminaux non recommandés fonctionnent avec XPipe mais peuvent manquer de fonctionnalités comme les onglets, les couleurs de titre, la prise en charge de l'interpréteur de commandes, et plus encore. Ton expérience d'utilisateur sera meilleure si tu utilises un terminal recommandé. +program=Programme +customTerminalCommand=Commande de terminal personnalisée +customTerminalCommandDescription=La commande à exécuter pour ouvrir le terminal personnalisé avec une commande donnée.\n\nXPipe créera un script de lancement temporaire pour ton terminal à exécuter. La chaîne de caractères de remplacement $CMD dans la commande que tu fournis sera remplacée par le script de lancement réel lorsqu'il sera appelé. N'oublie pas de citer le chemin d'accès à l'exécutable de ton terminal s'il contient des espaces. +clearTerminalOnInit=Effacer le terminal au démarrage +clearTerminalOnInitDescription=Lorsque cette option est activée, XPipe exécute une commande d'effacement lorsqu'une nouvelle session de terminal est lancée afin de supprimer toute sortie inutile. +enableFastTerminalStartup=Activation du démarrage rapide du terminal +enableFastTerminalStartupDescription=Lorsque cette option est activée, on essaie de démarrer les sessions de terminal plus rapidement lorsque c'est possible.\n\nCela permet d'ignorer plusieurs vérifications au démarrage et de ne pas mettre à jour les informations système affichées. Toute erreur de connexion ne sera affichée que dans le terminal. +dontCachePasswords=Ne pas mettre en cache les mots de passe demandés +dontCachePasswordsDescription=Contrôle si les mots de passe demandés doivent être mis en cache en interne par XPipe afin que tu n'aies pas à les saisir à nouveau dans la session en cours.\n\nSi ce comportement est désactivé, tu devras saisir à nouveau les informations d'identification demandées chaque fois qu'elles seront exigées par le système. +denyTempScriptCreation=Refuser la création de scripts temporaires +denyTempScriptCreationDescription=Pour réaliser certaines de ses fonctionnalités, XPipe crée parfois des scripts shell temporaires sur un système cible pour permettre une exécution facile de commandes simples. Ceux-ci ne contiennent aucune information sensible et sont simplement créés à des fins de mise en œuvre.\n\nSi ce comportement est désactivé, XPipe ne créera aucun fichier temporaire sur un système distant. Cette option est utile dans les contextes de haute sécurité où chaque modification du système de fichiers est surveillée. Si cette option est désactivée, certaines fonctionnalités, par exemple les environnements shell et les scripts, ne fonctionneront pas comme prévu. +disableCertutilUse=Désactiver l'utilisation de certutil sur Windows +useLocalFallbackShell=Utiliser le shell local de secours +useLocalFallbackShellDescription=Passe à l'utilisation d'un autre shell local pour gérer les opérations locales. Il s'agirait de PowerShell sur Windows et de l'interpréteur de commandes bourne sur d'autres systèmes.\n\nCette option peut être utilisée dans le cas où le shell local normal par défaut est désactivé ou cassé dans une certaine mesure. Certaines fonctionnalités peuvent ne pas fonctionner comme prévu lorsque cette option est activée.\n\nUn redémarrage est nécessaire pour l'appliquer. +disableCertutilUseDescription=En raison de plusieurs lacunes et bogues dans cmd.exe, des scripts shell temporaires sont créés avec certutil en l'utilisant pour décoder l'entrée base64 car cmd.exe s'interrompt sur l'entrée non ASCII. XPipe peut également utiliser PowerShell pour cela, mais cela sera plus lent.\n\nCela désactive toute utilisation de certutil sur les systèmes Windows pour réaliser certaines fonctionnalités et se rabat sur PowerShell à la place. Cela pourrait plaire à certains antivirus, car certains d'entre eux bloquent l'utilisation de certutil. +disableTerminalRemotePasswordPreparation=Désactiver la préparation du mot de passe à distance du terminal +disableTerminalRemotePasswordPreparationDescription=Dans les situations où une connexion shell à distance qui passe par plusieurs systèmes intermédiaires doit être établie dans le terminal, il peut être nécessaire de préparer tous les mots de passe requis sur l'un des systèmes intermédiaires pour permettre un remplissage automatique de toutes les invites.\n\nSi tu ne veux pas que les mots de passe soient transférés vers un système intermédiaire, tu peux désactiver ce comportement. Tout mot de passe intermédiaire requis sera alors demandé dans le terminal lui-même lorsqu'il sera ouvert. +more=Plus +translate=Traductions +allConnections=Toutes les connexions +allScripts=Tous les scripts +predefined=Prédéfini +default=Défaut +goodMorning=Bonjour +goodAfternoon=Bon après-midi +goodEvening=Bonne soirée +addVisual=Visual ... +ssh=SSH +sshConfiguration=Configuration SSH diff --git a/lang/base/strings/translations_fr.properties b/lang/base/strings/translations_fr.properties new file mode 100644 index 000000000..18c112892 --- /dev/null +++ b/lang/base/strings/translations_fr.properties @@ -0,0 +1,108 @@ +localMachine=Machine locale +destination=Destination +configuration=Configuration +launch=Lancer +start=Démarrer +stop=Arrêter +pause=Pause +refresh=Rafraîchir +options=Options +newFile=Nouveau fichier +newLink=Nouveau lien +linkName=Nom du lien +scanConnections=Trouver les connexions disponibles ... +observe=Commencer à observer +stopObserve=Arrêter d'observer +createShortcut=Créer un raccourci sur le bureau +browseFiles=Parcourir les fichiers +clone=Clone +targetPath=Chemin cible +newDirectory=Nouveau répertoire +copyShareLink=Copier le lien +selectStore=Sélectionner un magasin +saveSource=Sauvegarder pour plus tard +execute=Exécuter +deleteChildren=Enlève tous les enfants +descriptionDescription=Donne à ce groupe une description facultative +selectSource=Sélectionner la source +commandLineRead=Mise à jour +commandLineWrite=Ecris +wslHost=Hôte WSL +timeout=Délai d'attente +additionalOptions=Options supplémentaires +type=Type de texte +input=Entrée +machine=Machine +container=Conteneur +host=Hôte +port=Port +user=Utilisateur +password=Mot de passe +method=Méthode +uri=URL +distribution=Distribution +username=Nom d'utilisateur +shellType=Type de coquille +command=Commande +browseFile=Parcourir le fichier +openShell=Ouvrir le shell +editFile=Editer un fichier +usage=Utilisation +description=Description +open=Ouvrir +edit=Éditer +scriptContents=Contenu du script +scriptContentsDescription=Les commandes de script à exécuter +snippets=Dépendances des scripts +snippetsDescription=Autres scripts à exécuter en premier +snippetsDependenciesDescription=Tous les scripts possibles qui doivent être exécutés le cas échéant +isDefault=S'exécute en mode init dans tous les shells compatibles +bringToShells=Apporte à tous les coquillages compatibles +isDefaultGroup=Exécute tous les scripts de groupe au démarrage de l'interpréteur de commandes +executionType=Type d'exécution +executionTypeDescription=Quand exécuter cet extrait +minimumShellDialect=Type de coquille +minimumShellDialectDescription=Le type d'interpréteur de commandes requis pour ce script +dumbOnly=Muet +terminalOnly=Terminal +both=Les deux +shouldElevate=Devrait s'élever +shouldElevateDescription=Si ce script doit être exécuté avec des autorisations élevées +script.displayName=Écriture +script.displayDescription=Créer un script réutilisable +scriptGroup.displayName=Groupe de scripts +scriptGroup.displayDescription=Créer un groupe pour les scripts +scriptGroup=Groupe +scriptGroupDescription=Le groupe à qui attribuer ce texte +openInNewTab=Ouvrir dans un nouvel onglet +executeInBackground=en arrière-plan +executeInTerminal=dans $TERM$ +back=Retourner +browseInWindowsExplorer=Naviguer dans l'explorateur Windows +browseInDefaultFileManager=Parcourir dans le gestionnaire de fichiers par défaut +browseInFinder=Parcourir dans finder +chmod=Chmod +copy=Copie +paste=Coller +copyLocation=Emplacement de la copie +absolutePaths=Chemins absolus +absoluteLinkPaths=Chemins d'accès absolus +absolutePathsQuoted=Chemins d'accès absolus entre guillemets +fileNames=Noms de fichiers +linkFileNames=Noms de fichiers de liaison +fileNamesQuoted=Noms de fichiers (cités) +deleteFile=Effacer $FILE$ +deleteLink=Supprimer le lien +editWithEditor=Éditer avec $EDITOR +followLink=Suivre le lien +goForward=Aller de l'avant +showDetails=Afficher les détails +openFileWith=Ouvrir avec ... +openWithDefaultApplication=Ouvrir avec l'application par défaut +rename=Renommer +run=Exécuter +new=Nouveau +openInTerminal=Ouvrir dans le terminal +file=Fichier +directory=Répertoire +symbolicLink=Lien symbolique diff --git a/lang/base/texts/elevation_fr.md b/lang/base/texts/elevation_fr.md new file mode 100644 index 000000000..481cbf871 --- /dev/null +++ b/lang/base/texts/elevation_fr.md @@ -0,0 +1,14 @@ +## Élévation + +Le processus d'élévation est spécifique au système d'exploitation. + +### Linux et macOS + +Toute commande élevée est exécutée avec `sudo`. Le mot de passe facultatif `sudo` est interrogé via XPipe lorsque cela est nécessaire. +Tu as la possibilité d'ajuster le comportement d'élévation dans les paramètres pour contrôler si tu veux saisir ton mot de passe à chaque fois qu'il est nécessaire ou si tu veux le mettre en cache pour la session en cours. + +### Windows + +Sous Windows, il n'est pas possible d'élever un processus enfant si le processus parent n'est pas lui aussi élevé. +Par conséquent, si XPipe n'est pas exécuté en tant qu'administrateur, tu ne pourras pas utiliser d'élévation localement. +Pour les connexions à distance, le compte utilisateur connecté doit avoir des privilèges d'administrateur. \ No newline at end of file diff --git a/lang/base/texts/executionType_fr.md b/lang/base/texts/executionType_fr.md new file mode 100644 index 000000000..0a502bb3a --- /dev/null +++ b/lang/base/texts/executionType_fr.md @@ -0,0 +1,15 @@ +## Types d'exécution + +Il existe deux types d'exécution distincts lorsque XPipe se connecte à un système. + +### En arrière-plan + +La première connexion à un système est effectuée en arrière-plan dans une session de terminal muet. + +Les commandes de blocage qui nécessitent une entrée de la part de l'utilisateur peuvent geler le processus de l'interpréteur de commandes lorsque XPipe le démarre d'abord en interne en arrière-plan. Pour éviter cela, tu ne dois appeler ces commandes bloquantes qu'en mode terminal. + +Le navigateur de fichiers, par exemple, utilise entièrement le mode d'arrière-plan muet pour gérer ses opérations, donc si tu veux que l'environnement de ton script s'applique à la session du navigateur de fichiers, il doit s'exécuter en mode muet. + +### Dans les terminaux + +Une fois que la connexion initiale au terminal muet a réussi, XPipe ouvre une connexion séparée dans le terminal réel. Si tu veux que le script soit exécuté lorsque tu ouvres la connexion dans un terminal, choisis le mode terminal. diff --git a/lang/base/texts/scriptCompatibility_fr.md b/lang/base/texts/scriptCompatibility_fr.md new file mode 100644 index 000000000..9e8c583e4 --- /dev/null +++ b/lang/base/texts/scriptCompatibility_fr.md @@ -0,0 +1,13 @@ +## Compatibilité des scripts + +Le type de shell contrôle l'endroit où ce script peut être exécuté. +Outre une correspondance exacte, c'est-à-dire l'exécution d'un script `zsh` dans `zsh`, XPipe inclura également une vérification plus large de la compatibilité. + +### Shells Posix + +Tout script déclaré comme un script `sh` est capable de s'exécuter dans n'importe quel environnement shell lié à Posix, tel que `bash` ou `zsh`. +Si tu as l'intention d'exécuter un script de base sur de nombreux systèmes différents, utiliser uniquement des scripts de syntaxe `sh` est la meilleure solution pour cela. + +### PowerShell + +Les scripts déclarés comme des scripts `powershell` normaux sont également capables de s'exécuter dans des environnements `pwsh`. diff --git a/lang/base/texts/scriptDependencies_fr.md b/lang/base/texts/scriptDependencies_fr.md new file mode 100644 index 000000000..336826fff --- /dev/null +++ b/lang/base/texts/scriptDependencies_fr.md @@ -0,0 +1,5 @@ +## Dépendances du script + +Les scripts et les groupes de scripts à exécuter en premier. Si un groupe entier devient une dépendance, tous les scripts de ce groupe seront considérés comme des dépendances. + +Le graphe de dépendance résolu des scripts est aplati, filtré et rendu unique. C'est-à-dire que seuls les scripts compatibles seront exécutés et que si un script devait être exécuté plusieurs fois, il ne sera exécuté que la première fois. diff --git a/lang/base/texts/script_fr.md b/lang/base/texts/script_fr.md new file mode 100644 index 000000000..636ae2b81 --- /dev/null +++ b/lang/base/texts/script_fr.md @@ -0,0 +1,5 @@ +## Contenu du script + +Le contenu du script à exécuter. Tu peux choisir de le modifier sur place ou d'utiliser le bouton d'édition externe dans le coin supérieur droit pour lancer un éditeur de texte externe. + +Tu n'as pas besoin de spécifier une ligne shebang pour les shells qui la prennent en charge, une ligne est ajoutée automatiquement avec le type de shell approprié. diff --git a/lang/jdbc/strings/translations_fr.properties b/lang/jdbc/strings/translations_fr.properties new file mode 100644 index 000000000..2ccb9c259 --- /dev/null +++ b/lang/jdbc/strings/translations_fr.properties @@ -0,0 +1,20 @@ +postgres.displayName=PostgreSQL +postgres.displayDescription=Ouvrir un shell psql sur un serveur PostgreSQL +query=Requête +proxy=Proxy +peerAuth=Authentification par les pairs +port=Port +url=URL +instance=Instance +username=Nom d'utilisateur +usernameDescription=L'utilisateur à connecter en tant que +password=Mot de passe +passwordDescription=Le mot de passe pour s'authentifier +authentication=Authentification +authenticationType=Méthode +connection=Connexion +connectionUrl=URL de connexion +connectionString=Chaîne de connexion +passwordAuth=Authentification par mot de passe +windowsAuth=Authentification Windows +psqlShell=Ouvrir le shell PSQL dans le terminal diff --git a/lang/proc/strings/translations_fr.properties b/lang/proc/strings/translations_fr.properties new file mode 100644 index 000000000..79d28b1db --- /dev/null +++ b/lang/proc/strings/translations_fr.properties @@ -0,0 +1,299 @@ +showInternalPods=Montre les cosses internes +showAllNamespaces=Afficher tous les espaces de noms +showInternalContainers=Afficher les conteneurs internes +refresh=Rafraîchir +vmwareGui=Démarrer l'interface graphique +monitorVm=Moniteur VM +addCluster=Ajouter une grappe ... +showNonRunningInstances=Afficher les instances non exécutées +vmwareGuiDescription=S'il faut démarrer une machine virtuelle en arrière-plan ou dans une fenêtre. +vmwareEncryptionPassword=Mot de passe de cryptage +vmwareEncryptionPasswordDescription=Le mot de passe facultatif utilisé pour crypter la VM. +vmwarePasswordDescription=Le mot de passe requis pour l'utilisateur invité. +vmwarePassword=Mot de passe de l'utilisateur +vmwareUser=Utilisateur invité +runTempContainer=Exécuter un conteneur temporaire +vmwareUserDescription=Le nom d'utilisateur de l'invité principal +dockerTempRunAlertTitle=Exécuter un conteneur temporaire +dockerTempRunAlertHeader=Cela permet d'exécuter un processus shell dans un conteneur temporaire qui sera automatiquement supprimé une fois qu'il aura été arrêté. +imageName=Nom de l'image +imageNameDescription=L'identifiant de l'image du conteneur à utiliser +containerName=Nom du conteneur +containerNameDescription=Le nom facultatif du conteneur personnalisé +vm=Machine virtuelle +yubikeyPiv=Yubikey PIV (Pro) +vmDescription=Le fichier de configuration associé. +vmwareScan=Hyperviseurs de bureau VMware +library=Bibliothèque +customPkcs11Library=Bibliothèque PKCS#11 personnalisée (Pro) +vmwareMachine.displayName=Machine virtuelle VMware +vmwareMachine.displayDescription=Se connecter à une machine virtuelle via SSH +vmwareInstallation.displayName=Installation de l'hyperviseur de bureau VMware +vmwareInstallation.displayDescription=Interagir avec les machines virtuelles installées par l'intermédiaire de son CLI +start=Démarrer +stop=Arrêter +pause=Pause +rdpTunnelHost=Hôte du tunnel +rdpTunnelHostDescription=La connexion SSH optionnelle à utiliser comme tunnel +rdpFileLocation=Emplacement du fichier +rdpFileLocationDescription=Le chemin d'accès au fichier .rdp +rdpPasswordAuthentication=Authentification par mot de passe +rdpPasswordAuthenticationDescription=Le mot de passe à remplir automatiquement s'il est pris en charge +rdpFile.displayName=Fichier RDP +rdpFile.displayDescription=Se connecter à un système via un fichier .rdp existant +requiredSshServerAlertTitle=Configurer le serveur SSH +requiredSshServerAlertHeader=Impossible de trouver un serveur SSH installé dans la VM. +requiredSshServerAlertContent=Pour se connecter à la VM, XPipe recherche un serveur SSH en cours d'exécution mais aucun serveur SSH disponible n'a été détecté pour la VM... +computerName=Nom de l'ordinateur +pssComputerNameDescription=Le nom de l'ordinateur auquel se connecter. On suppose qu'il est déjà inclus dans tes hôtes de confiance. +credentialUser=Utilisateur de justificatifs +pssCredentialUserDescription=L'utilisateur sous lequel tu dois te connecter. +credentialPassword=Mot de passe d'identification +pssCredentialPasswordDescription=Le mot de passe de l'utilisateur. +sshConfig=Fichiers de configuration SSH +autostart=Se connecter automatiquement au démarrage de XPipe +acceptHostKey=Accepter la clé de l'hôte +modifyHostKeyPermissions=Modifier les permissions de la clé de l'hôte +attachContainer=Attacher à un contenant +openInVsCode=Ouvrir en VSCode +containerLogs=Afficher les journaux des conteneurs +openSftpClient=Ouvrir dans un client SFTP externe +openTermius=Ouvrir dans Termius +showInternalInstances=Afficher les instances internes +editPod=Editer le pod +acceptHostKeyDescription=Fais confiance à la nouvelle clé de l'hôte et continue +modifyHostKeyPermissionsDescription=Tente de supprimer les permissions du fichier d'origine pour que OpenSSH soit satisfait +psSession.displayName=Session à distance PowerShell +psSession.displayDescription=Se connecter via New-PSSession et Enter-PSSession +sshLocalTunnel.displayName=Tunnel SSH local +sshLocalTunnel.displayDescription=Établir un tunnel SSH vers un hôte distant +sshRemoteTunnel.displayName=Tunnel SSH à distance +sshRemoteTunnel.displayDescription=Établir un tunnel SSH inverse à partir d'un hôte distant +sshDynamicTunnel.displayName=Tunnel SSH dynamique +sshDynamicTunnel.displayDescription=Établir un proxy SOCKS par le biais d'une connexion SSH +shellEnvironmentGroup.displayName=Environnements Shell +shellEnvironmentGroup.displayDescription=Environnements Shell +shellEnvironment.displayName=Environnement Shell personnalisé +shellEnvironment.displayDescription=Créer un environnement d'initialisation de l'interpréteur de commandes personnalisé +shellEnvironment.informationFormat=$TYPE$ l'environnement +shellEnvironment.elevatedInformationFormat=$ELEVATION$ $TYPE$ l'environnement +environmentConnectionDescription=La connexion de base pour créer un environnement pour +environmentScriptDescription=Le script d'initialisation personnalisé facultatif à exécuter dans l'interpréteur de commandes +environmentSnippets=Extraits de scripts +commandSnippetsDescription=Les extraits de scripts prédéfinis facultatifs à exécuter en premier +environmentSnippetsDescription=Les extraits de scripts prédéfinis facultatifs à exécuter lors de l'initialisation +shellTypeDescription=Le type de shell explicite à lancer +originPort=Port d'origine +originAddress=Adresse d'origine +remoteAddress=Adresse à distance +remotePort=Port distant +remoteSourceAddress=Adresse de la source distante +remoteSourcePort=Port source à distance +originDestinationPort=Origine destination port +originDestinationAddress=Adresse d'origine et de destination +origin=Origine +remoteHost=Hôte distant +address=Adresse +proxmox=Proxmox +proxmox.displayName=Proxmox +proxmox.displayDescription=Se connecter à des systèmes dans un environnement virtuel Proxmox +proxmoxVm.displayName=Proxmox VM +proxmoxVm.displayDescription=Se connecter à une machine virtuelle dans un Proxmox VE via SSH +proxmoxContainer.displayName=Conteneur Proxmox +proxmoxContainer.displayDescription=Se connecter à un conteneur dans un Proxmox VE +sshDynamicTunnel.originDescription=Le système à partir duquel ouvrir la connexion ssh +sshDynamicTunnel.hostDescription=Le système à utiliser comme proxy SOCKS +sshDynamicTunnel.bindingDescription=A quelles adresses lier le tunnel +sshRemoteTunnel.originDescription=Le système à partir duquel il faut ouvrir la connexion ssh et ouvrir le tunnel vers.. +sshRemoteTunnel.hostDescription=Le système à partir duquel démarrer le tunnel à distance vers l'origine +sshRemoteTunnel.bindingDescription=A quelles adresses lier le tunnel +sshLocalTunnel.originDescription=Le système à partir duquel il faut commencer le tunnel +sshLocalTunnel.hostDescription=Le système pour ouvrir le tunnel vers +sshLocalTunnel.bindingDescription=A quelles adresses lier le tunnel +sshLocalTunnel.localAddressDescription=L'adresse locale à lier +sshLocalTunnel.remoteAddressDescription=L'adresse distante à lier +active=Actif +inactive=Inactif +cmd.displayName=Commande personnalisée du terminal +cmd.displayDescription=Exécute une commande personnalisée sur un système dans ton terminal +k8sPod.displayName=Pod Kubernetes +k8sPod.displayDescription=Se connecter à un pod et à ses conteneurs via kubectl +k8sContainer.displayName=Conteneur Kubernetes +k8sContainer.displayDescription=Ouvrir un shell à un conteneur +k8sCluster.displayName=Cluster Kubernetes +k8sCluster.displayDescription=Se connecter à un cluster et à ses pods via kubectl +sshTunnelGroup.displayName=Tunnels SSH +sshTunnelGroup.displayCategory=Tous les types de tunnels SSH +podmanCmd.displayName=Podman CLI +podmanCmd.displayCategory=Accéder aux conteneurs Podman via le client CLI +podmanContainers=Conteneurs Podman +local.displayName=Machine locale +local.displayDescription=Le shell de la machine locale +cygwin=Cygwin +msys2=MSYS2 +gitWindows=Git pour Windows +gitForWindows.displayName=Git pour Windows +gitForWindows.displayDescription=Accède à ton environnement local Git pour Windows +msys2.displayName=MSYS2 +msys2.displayDescription=Les shells d'accès de ton environnement MSYS2 +cygwin.displayName=Cygwin +cygwin.displayDescription=Accède aux shells de ton environnement Cygwin +namespace=Espace de noms +gitVaultIdentityStrategy=Identité SSH Git +gitVaultIdentityStrategyDescription=Si tu as choisi d'utiliser une URL SSH git comme distant et que ton dépôt distant nécessite une identité SSH, alors définis cette option.\n\nSi tu as fourni une URL HTTP, tu peux ignorer cette option. +dockerContainers=Conteneurs Docker +lxdContainers=Conteneurs LXD +dockerCmd.displayName=client CLI de docker +dockerCmd.displayDescription=Accède aux conteneurs Docker via le client CLI de Docker +lxdCmd.displayName=Client CLI LXD +lxdCmd.displayDescription=Accéder aux conteneurs LXD via le CLI lxc cient +wslCmd.displayName=client wsl +wslCmd.displayDescription=Accéder aux instances WSL via le CLI wsl cient +k8sCmd.displayName=client kubectl +k8sCmd.displayDescription=Accéder aux clusters Kubernetes via kubectl +k8sClusters=Clusters Kubernetes +shells=Coquilles disponibles +startContainer=Conteneur de départ +stopContainer=Arrêter le conteneur +inspectContainer=Inspecter le conteneur +k8sClusterNameDescription=Le nom du contexte dans lequel se trouve le cluster. +pod=Cosse +podName=Nom du pod +k8sClusterContext=Contexte +k8sClusterContextDescription=Le nom du contexte dans lequel se trouve le cluster +k8sClusterNamespace=Espace de noms +k8sClusterNamespaceDescription=L'espace de noms personnalisé ou l'espace de noms par défaut s'il est vide +k8sConfigLocation=Fichier de configuration +k8sConfigLocationDescription=Le fichier kubeconfig personnalisé ou celui par défaut s'il est laissé vide +inspectPod=Inspecter la capsule +showAllContainers=Afficher les conteneurs qui ne fonctionnent pas +showAllPods=Afficher les pods qui ne fonctionnent pas +wsl=WSL +docker=Docker +k8sPodHostDescription=L'hôte sur lequel se trouve le pod +k8sContainerDescription=Le nom du conteneur Kubernetes +k8sPodDescription=Le nom du pod Kubernetes +podDescription=Le pod sur lequel se trouve le conteneur +k8sClusterHostDescription=L'hôte par lequel il faut accéder au cluster. Doit avoir kubectl installé et configuré pour pouvoir accéder au cluster. +script=Script d'initialisation +connection=Connexion +shellCommand.displayName=Commande d'ouverture de shell personnalisée +shellCommand.displayDescription=Ouvrir un shell standard par le biais d'une commande personnalisée +ssh.displayName=Connexion SSH simple +ssh.displayDescription=Se connecter via un client de ligne de commande SSH +sshConfig.displayName=Fichier de configuration SSH +sshConfig.displayDescription=Se connecter aux hôtes définis dans un fichier de configuration SSH +sshConfigHost.displayName=Fichier de configuration SSH Hôte +sshConfigHost.displayDescription=Se connecter à un hôte défini dans un fichier de configuration SSH +sshConfigHost.password=Mot de passe +sshConfigHost.passwordDescription=Fournir le mot de passe facultatif pour la connexion de l'utilisateur. +sshConfigHost.identityPassphrase=Phrase d'identité +sshConfigHost.identityPassphraseDescription=Indique la phrase de passe facultative pour ta clé d'identité. +binary.displayName=Binaire +binary.displayDescription=Données binaires +text.displayName=Texte +shellCommand.hostDescription=L'hôte sur lequel exécuter la commande +shellCommand.commandDescription=La commande qui ouvre un shell +sshAgent=Agent SSH +none=Aucun +commandDescription=Les commandes à exécuter dans un script shell sur l'hôte. +commandHostDescription=L'hôte sur lequel exécuter la commande +commandDataFlowDescription=Comment cette commande gère les entrées et les sorties +commandElevationDescription=Exécute cette commande avec des autorisations élevées +commandShellTypeDescription=L'interpréteur de commandes à utiliser pour cette commande +ssh.passwordDescription=Le mot de passe facultatif à utiliser lors de l'authentification +keyAuthentication=Authentification par clé +keyAuthenticationDescription=La méthode d'authentification à utiliser si l'authentification par clé est requise. +dontInteractWithSystem=Ne pas interagir avec le système (Pro) +dontInteractWithSystemDescription=N'essaie pas d'identifier le type de shell et de système d'exploitation +sshForwardX11=Faire suivre X11 +sshForwardX11Description=Active le transfert X11 pour la connexion +customAgent=Agent personnalisé +identityAgent=Agent d'identité +ssh.proxyDescription=L'hôte proxy facultatif à utiliser lors de l'établissement de la connexion SSH. Un client ssh doit être installé. +usage=Utilisation +wslHostDescription=L'hôte sur lequel se trouve l'instance WSL. Doit avoir installé wsl. +wslDistributionDescription=Le nom de l'instance WSL +wslUsernameDescription=Le nom d'utilisateur explicite sous lequel se connecter. S'il n'est pas spécifié, le nom d'utilisateur par défaut sera utilisé. +wslPasswordDescription=Le mot de passe de l'utilisateur qui peut être utilisé pour les commandes sudo. +dockerHostDescription=L'hôte sur lequel se trouve le conteneur docker. Doit avoir installé docker. +dockerContainerDescription=Le nom du conteneur docker +lxdHostDescription=L'hôte sur lequel se trouve le conteneur LXD. Lxc doit être installé. +lxdContainerDescription=Le nom du conteneur LXD +localMachine=Machine locale +rootScan=Environnement de l'interpréteur de commandes racine +loginEnvironmentScan=Environnement de connexion personnalisé +k8sScan=Cluster Kubernetes +options=Options +dockerRunningScan=Exécuter des conteneurs docker +dockerAllScan=Tous les conteneurs docker +wslScan=Instances WSL +sshScan=Connexions de configuration SSH +requiresElevation=Exécuter en hauteur +default=Défaut +wslHost=Hôte WSL +timeout=Délai d'attente +installLocation=Emplacement de l'installation +installLocationDescription=L'endroit où ton environnement $NAME$ est installé +wsl.displayName=Sous-système Windows pour Linux +wsl.displayDescription=Se connecter à une instance WSL fonctionnant sous Windows +docker.displayName=Conteneur Docker +docker.displayDescription=Se connecter à un conteneur docker +podman.displayName=Conteneur Podman +podman.displayDescription=Se connecter à un conteneur Podman +lxd.displayName=Conteneur LXD +lxd.displayDescription=Se connecter à un conteneur LXD via lxc +container=Conteneur +host=Hôte +port=Port +user=Utilisateur +password=Mot de passe +method=Méthode +uri=URL +proxy=Proxy +distribution=Distribution +username=Nom d'utilisateur +shellType=Type de coquille +browseFile=Parcourir le fichier +openShell=Ouvrir le shell dans le terminal +openCommand=Exécuter une commande dans le terminal +editFile=Editer le fichier +description=Description +keyFile=Fichier d'identité +keyPassword=Phrase de passe +key=Clé +furtherCustomization=Personnalisation supplémentaire +furtherCustomizationDescription=Pour plus d'options de configuration, utilise les fichiers de configuration ssh +location=Lieu +browse=Parcourir +locationDescription=Le chemin d'accès au fichier de ta clé privée correspondante +configHost=Hôte +configHostDescription=L'hôte sur lequel se trouve le config +configLocation=Emplacement de la configuration +configLocationDescription=Le chemin d'accès au fichier de configuration +pageant=Pageant +gpgAgent=Agent GPG (Pro) +gateway=Passerelle +gatewayDescription=La passerelle optionnelle à utiliser lors de la connexion. +connectionInformation=Informations sur la connexion +connectionInformationDescription=A quel système se connecter +passwordAuthentication=Authentification par mot de passe +passwordDescription=Le mot de passe facultatif à utiliser pour s'authentifier. +sshConfigString.displayName=Connexion SSH personnalisée +sshConfigString.displayDescription=Créer une connexion SSH entièrement personnalisée +sshConfigStringContent=Configuration +sshConfigStringContentDescription=Options SSH pour la connexion au format OpenSSH config +vnc.displayName=Connexion VNC +vnc.displayDescription=Ouvrir une session VNC via un tunnel SSH +binding=Reliure +vncPortDescription=Le port sur lequel le serveur VNC écoute +vncUsername=Nom d'utilisateur +vncUsernameDescription=Le nom d'utilisateur optionnel de VNC +vncPassword=Mot de passe +vncPasswordDescription=Le mot de passe VNC +x11WslInstance=Instance X11 Forward WSL +x11WslInstanceDescription=La distribution locale du sous-système Windows pour Linux à utiliser comme serveur X11 lors de l'utilisation du transfert X11 dans une connexion SSH. Cette distribution doit être une distribution WSL2.\n\nUn redémarrage est nécessaire pour l'appliquer. +openAsRoot=Ouvrir en tant que racine +openInVsCodeRemote=Ouvrir en VSCode à distance +openInWSL=Ouvrir en WSL +launch=Lancer diff --git a/lang/proc/texts/elevation_fr.md b/lang/proc/texts/elevation_fr.md new file mode 100644 index 000000000..c2a08fe1f --- /dev/null +++ b/lang/proc/texts/elevation_fr.md @@ -0,0 +1,11 @@ +## Élévation + +Le processus d'élévation des permissions est spécifique au système d'exploitation. + +### Linux et macOS + +Toute commande élevée est exécutée avec `sudo`. Le mot de passe facultatif `sudo` est interrogé via XPipe lorsque cela est nécessaire. Tu as la possibilité d'ajuster le comportement d'élévation dans les paramètres pour contrôler si tu veux saisir ton mot de passe à chaque fois qu'il est nécessaire ou si tu veux le mettre en cache pour la session en cours. + +### Windows + +Sous Windows, il n'est pas possible d'élever les permissions d'un processus enfant si le processus parent ne s'exécute pas également avec des permissions élevées. Par conséquent, si XPipe n'est pas exécuté en tant qu'administrateur, tu ne pourras pas utiliser d'élévation localement. Pour les connexions à distance, le compte d'utilisateur connecté doit avoir des privilèges d'administrateur. \ No newline at end of file diff --git a/lang/proc/texts/environmentScript_fr.md b/lang/proc/texts/environmentScript_fr.md new file mode 100644 index 000000000..119fd8174 --- /dev/null +++ b/lang/proc/texts/environmentScript_fr.md @@ -0,0 +1,9 @@ +## Script d'initialisation + +Les commandes facultatives à exécuter après que les fichiers et profils init de l'interpréteur de commandes ont été exécutés. + +Tu peux traiter ce script comme un script shell normal, c'est-à-dire utiliser toute la syntaxe que le shell prend en charge dans les scripts. Toutes les commandes que tu exécutes sont générées par l'interpréteur de commandes et modifient l'environnement. Ainsi, si tu définis par exemple une variable, tu auras accès à cette variable dans cette session de l'interpréteur de commandes. + +### Commandes bloquantes + +Note que les commandes de blocage qui nécessitent une entrée de la part de l'utilisateur peuvent geler le processus de l'interpréteur de commandes lorsque XPipe le démarre d'abord en interne en arrière-plan. Pour éviter cela, n'appelle ces commandes bloquantes que si la variable `TERM` n'est pas définie sur `dumb`. XPipe définit automatiquement la variable `TERM=dumb` lorsqu'il prépare la session shell en arrière-plan, puis définit `TERM=xterm-256color` lors de l'ouverture effective du terminal. \ No newline at end of file diff --git a/lang/proc/texts/proxmoxPassword_fr.md b/lang/proc/texts/proxmoxPassword_fr.md new file mode 100644 index 000000000..22aa59950 --- /dev/null +++ b/lang/proc/texts/proxmoxPassword_fr.md @@ -0,0 +1,3 @@ +## Mot de passe + +Si tu utilises une authentification SSH plus complexe sur ta VM plutôt qu'un simple mot de passe, tu peux simplement ajouter le système comme une connexion SSH normale dans XPipe. S'il n'est pas accessible de l'extérieur, tu peux définir le système PVE parent comme une passerelle SSH. diff --git a/lang/proc/texts/proxmoxUsername_fr.md b/lang/proc/texts/proxmoxUsername_fr.md new file mode 100644 index 000000000..664982e6d --- /dev/null +++ b/lang/proc/texts/proxmoxUsername_fr.md @@ -0,0 +1,5 @@ +## Nom d'utilisateur + +Le nom d'utilisateur sous lequel se connecter. XPipe tentera de se connecter via SSH en utilisant les informations d'identification fournies. + +Si aucun serveur SSH n'est en cours d'exécution, il tentera de démarrer le serveur SSH installé. Note que tu peux désactiver ce comportement dans le menu des paramètres de sécurité. diff --git a/lang/proc/texts/rdpPasswordAuthentication_fr.md b/lang/proc/texts/rdpPasswordAuthentication_fr.md new file mode 100644 index 000000000..cc9ee01b9 --- /dev/null +++ b/lang/proc/texts/rdpPasswordAuthentication_fr.md @@ -0,0 +1,3 @@ +## Authentification par mot de passe RDP + +Tous les clients RDP disponibles ne prennent pas en charge la fourniture automatique de mots de passe. Si le client que tu as sélectionné ne prend pas en charge cette fonction, tu devras toujours saisir le mot de passe manuellement lors de la connexion. \ No newline at end of file diff --git a/lang/proc/texts/rdpTunnelHost_fr.md b/lang/proc/texts/rdpTunnelHost_fr.md new file mode 100644 index 000000000..112f6674b --- /dev/null +++ b/lang/proc/texts/rdpTunnelHost_fr.md @@ -0,0 +1,5 @@ +## Hôte du tunnel RDP + +Tu peux choisir de te connecter à un hôte RDP distant via un tunnel SSH. Cela te permet d'utiliser les fonctions d'authentification SSH les plus avancées avec RDP. + +Lorsque cette option est utilisée, l'adresse de l'hôte dans le fichier RDP sera remplacée par le nom d'hôte choisi pour la connexion SSH. Lors de la première connexion, un tunnel SSH sera établi et le client RDP se connectera à la connexion via localhost. \ No newline at end of file diff --git a/lang/proc/texts/runTempContainer_fr.md b/lang/proc/texts/runTempContainer_fr.md new file mode 100644 index 000000000..eba564912 --- /dev/null +++ b/lang/proc/texts/runTempContainer_fr.md @@ -0,0 +1,5 @@ +## Conteneurs temporaires + +Cette commande lance un conteneur temporaire à l'aide de l'image spécifiée, qui sera automatiquement supprimé une fois arrêté. Le conteneur continuera à fonctionner même si l'image du conteneur n'a pas de commande spécifiée qui s'exécutera. + +Cela peut être utile si tu veux rapidement mettre en place un certain environnement en utilisant une certaine image de conteneur. Tu peux alors entrer dans le conteneur comme d'habitude dans XPipe, effectuer tes opérations, et arrêter le conteneur une fois qu'il n'est plus nécessaire. Il est alors supprimé automatiquement. \ No newline at end of file diff --git a/lang/proc/texts/shellCommand_fr.md b/lang/proc/texts/shellCommand_fr.md new file mode 100644 index 000000000..ead89eba0 --- /dev/null +++ b/lang/proc/texts/shellCommand_fr.md @@ -0,0 +1,30 @@ +## Connexions shell personnalisées + +Ouvre un shell à l'aide de la commande personnalisée en exécutant la commande donnée sur le système hôte sélectionné. Ce shell peut être local ou distant. + +Note que cette fonctionnalité s'attend à ce que le shell soit d'un type standard tel que `cmd`, `bash`, etc. Si tu veux ouvrir d'autres types de shells et de commandes dans un terminal, tu peux utiliser le type de commande custom terminal à la place. L'utilisation de shells standard te permet également d'ouvrir cette connexion dans le navigateur de fichiers. + +### Invites interactives + +Le processus de l'interpréteur de commandes peut s'interrompre ou se bloquer en cas d'invite de saisie inattendue, comme une invite de mot de passe +inattendue, comme une invite de mot de passe. Par conséquent, tu dois toujours t'assurer qu'il n'y a pas d'invite de saisie interactive. + +Par exemple, une commande comme `ssh user@host` fonctionnera bien ici tant qu'il n'y a pas de mot de passe requis. + +### Les interpréteurs de commandes locaux personnalisés + +Dans de nombreux cas, il est utile de lancer un shell avec certaines options qui sont généralement désactivées par défaut afin que certains scripts et certaines commandes fonctionnent correctement. Par exemple : + +- [Expansion retardée dans + cmd](https://ss64.com/nt/delayedexpansion.html) +- [Exécution Powershell + powershell](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-7.3) +- [Mode POSIX de Bash + Mode](https://www.gnu.org/software/bash/manual/html_node/Bash-POSIX-Mode.html) +- Et toute autre option de lancement possible pour un shell de ton choix + +Cela peut être réalisé en créant des commandes shell personnalisées avec par exemple les commandes suivantes : + +- `cmd /v` +- `powershell -ExecutionMode Bypass` +- `bash --posix` \ No newline at end of file diff --git a/lang/proc/texts/sshConfigs_fr.md b/lang/proc/texts/sshConfigs_fr.md new file mode 100644 index 000000000..ccb01ab99 --- /dev/null +++ b/lang/proc/texts/sshConfigs_fr.md @@ -0,0 +1,13 @@ +### Configurations SSH + +XPipe charge tous les hôtes et applique tous les paramètres que tu as configurés dans le fichier sélectionné. Ainsi, en spécifiant une option de configuration globale ou spécifique à un hôte, elle sera automatiquement appliquée à la connexion établie par XPipe. + +Si tu veux en savoir plus sur l'utilisation des configs SSH, tu peux utiliser `man ssh_config` ou lire ce [guide](https://www.ssh.com/academy/ssh/config). + +### Identités + +Note que tu peux également spécifier une option `IdentityFile` ici. Si une identité est spécifiée ici, toute autre identité spécifiée plus bas sera ignorée. + +### Redirection X11 + +Si des options pour la redirection X11 sont spécifiées ici, XPipe tentera automatiquement de mettre en place la redirection X11 sur Windows par l'intermédiaire de WSL. \ No newline at end of file diff --git a/lang/proc/texts/sshDontInteractWithSystem_fr.md b/lang/proc/texts/sshDontInteractWithSystem_fr.md new file mode 100644 index 000000000..c98a7fe4d --- /dev/null +++ b/lang/proc/texts/sshDontInteractWithSystem_fr.md @@ -0,0 +1,7 @@ +## Détection du type de coquille + +XPipe fonctionne en détectant le type de shell de la connexion et en interagissant ensuite avec le shell actif. Cette approche ne fonctionne cependant que lorsque le type de shell est connu et qu'il prend en charge un certain nombre d'actions et de commandes. Tous les shells courants comme `bash`, `cmd`, `powershell`, et bien d'autres, sont pris en charge. + +## Types d'interprètes de commandes inconnus + +Si tu te connectes à un système qui n'exécute pas un shell de commande connu, par exemple un routeur, un lien ou un appareil IOT, XPipe sera incapable de détecter le type de shell et se trompera au bout d'un certain temps. En activant cette option, XPipe n'essaiera pas d'identifier le type de shell et lancera le shell tel quel. Cela te permet d'ouvrir la connexion sans erreur, mais de nombreuses fonctionnalités, par exemple le navigateur de fichiers, les scripts, les sous-connexions, et plus encore, ne seront pas prises en charge pour cette connexion. diff --git a/lang/proc/texts/sshDynamicTunnelBinding_fr.md b/lang/proc/texts/sshDynamicTunnelBinding_fr.md new file mode 100644 index 000000000..567a295f4 --- /dev/null +++ b/lang/proc/texts/sshDynamicTunnelBinding_fr.md @@ -0,0 +1,5 @@ +## Liaison par tunnel + +Les informations de liaison que tu fournis sont transmises directement au client `ssh` de la manière suivante : `-D [adresse :]port`. + +Par défaut, l'adresse sera liée à l'interface loopback. Tu peux également utiliser des caractères génériques, par exemple en définissant l'adresse sur `0.0.0.0` afin de lier toutes les interfaces réseau accessibles via IPv4. Lorsque tu omets complètement l'adresse, le caractère générique `*`, qui autorise les connexions sur toutes les interfaces réseau, sera utilisé. Note que certaines notations d'interfaces réseau peuvent ne pas être prises en charge par tous les systèmes d'exploitation. Les serveurs Windows, par exemple, ne prennent pas en charge le caractère générique `*`. diff --git a/lang/proc/texts/sshDynamicTunnelOrigin_fr.md b/lang/proc/texts/sshDynamicTunnelOrigin_fr.md new file mode 100644 index 000000000..c7dabeeeb --- /dev/null +++ b/lang/proc/texts/sshDynamicTunnelOrigin_fr.md @@ -0,0 +1,5 @@ +## Origine du tunnel + +XPipe est totalement flexible en ce qui concerne l'endroit où exécuter une commande. Tu peux donc établir un tunnel sur n'importe quel système en plus de ta machine locale. + +La commande d'ouverture du tunnel sera exécutée sur le système que tu spécifies ici, tu dois donc avoir un client `ssh` installé sur ce système. Si l'origine n'est pas la machine locale, XPipe gardera une connexion ouverte vers ce système distant en arrière-plan pour gérer le tunnel. \ No newline at end of file diff --git a/lang/proc/texts/sshForwardX11_fr.md b/lang/proc/texts/sshForwardX11_fr.md new file mode 100644 index 000000000..a622b703f --- /dev/null +++ b/lang/proc/texts/sshForwardX11_fr.md @@ -0,0 +1,9 @@ +## X11 Forwarding + +Lorsque cette option est activée, la connexion SSH sera lancée avec une redirection X11. Sous Linux, cela fonctionne généralement d'emblée et ne nécessite aucune configuration. Sur macOS, tu as besoin d'un serveur X11 comme [XQuartz] (https://www.xquartz.org/) sur ta machine locale. + +### X11 sur Windows + +XPipe te permet d'utiliser les capacités X11 de WSL2 pour ta connexion SSH. La seule chose dont tu as besoin pour cela est une distribution [WSL2](https://learn.microsoft.com/en-us/windows/wsl/install) installée sur ton système local. XPipe choisira automatiquement une distribution installée compatible si possible, mais tu peux aussi en utiliser une autre dans le menu des paramètres. + +Cela signifie que tu n'as pas besoin d'installer un serveur X11 séparé sur Windows. Cependant, si tu en utilises un de toute façon, XPipe le détectera et utilisera le serveur X11 en cours d'exécution. diff --git a/lang/proc/texts/sshGateway_fr.md b/lang/proc/texts/sshGateway_fr.md new file mode 100644 index 000000000..4089ed95f --- /dev/null +++ b/lang/proc/texts/sshGateway_fr.md @@ -0,0 +1,9 @@ +## Passerelles de connexion Shell + +Si cette option est activée, XPipe ouvre d'abord une connexion shell à la passerelle et, à partir de là, une connexion SSH à l'hôte spécifié. La commande `ssh` doit être disponible et se trouver dans le `PATH` sur la passerelle que tu as choisie. + +### Sauter les serveurs + +Ce mécanisme est similaire aux serveurs de saut, mais il n'est pas équivalent. Il est complètement indépendant du protocole SSH, tu peux donc utiliser n'importe quelle connexion shell comme passerelle. + +Si tu cherches des serveurs de saut SSH proprement dits, peut-être aussi en combinaison avec le transfert d'agent, utilise la fonctionnalité de connexion SSH personnalisée avec l'option de configuration `ProxyJump`. \ No newline at end of file diff --git a/lang/proc/texts/sshInteraction_fr.md b/lang/proc/texts/sshInteraction_fr.md new file mode 100644 index 000000000..114c31ab9 --- /dev/null +++ b/lang/proc/texts/sshInteraction_fr.md @@ -0,0 +1,5 @@ +## Interaction avec le système + +XPipe essaie de détecter le type de shell dans lequel il s'est connecté pour vérifier que tout a fonctionné correctement et pour afficher des informations sur le système. Cela fonctionne pour les shells de commande normaux comme bash, mais échoue pour les shells de connexion non standard et personnalisés de nombreux systèmes embarqués. Tu dois désactiver ce comportement pour que les connexions à ces systèmes réussissent. + +Lorsque cette interaction est désactivée, elle n'essaiera pas d'identifier les informations du système. Cela empêchera le système d'être utilisé dans le navigateur de fichiers ou comme système proxy/passerelle pour d'autres connexions. XPipe agira alors essentiellement comme un lanceur de connexion. diff --git a/lang/proc/texts/sshKey_fr.md b/lang/proc/texts/sshKey_fr.md new file mode 100644 index 000000000..7eaff9229 --- /dev/null +++ b/lang/proc/texts/sshKey_fr.md @@ -0,0 +1,55 @@ +### Aucun + +Désactive l'authentification par `publickey`. + +### SSH-Agent + +Dans le cas où tes identités sont stockées dans le SSH-Agent, l'exécutable ssh peut les utiliser si l'agent est démarré. +XPipe démarrera automatiquement le processus de l'agent s'il n'est pas encore en cours d'exécution. + +### Pageant (Windows) + +Si tu utilises pageant sous Windows, XPipe vérifiera d'abord si pageant est en cours d'exécution. +En raison de la nature de pageant, il est de ta responsabilité de le faire fonctionner +tu dois en effet spécifier manuellement toutes les clés que tu souhaites ajouter à chaque fois. +S'il fonctionne, XPipe passera le bon tuyau nommé via +`-oIdentityAgent=...` à ssh, tu n'as pas besoin d'inclure de fichiers de configuration personnalisés. + +Note qu'il y a quelques bogues d'implémentation dans le client OpenSSH qui peuvent causer des problèmes +si ton nom d'utilisateur contient des espaces ou est trop long, alors essaie d'utiliser la dernière version. + +### Pageant (Linux & macOS) + +Dans le cas où tes identités sont stockées dans l'agent pageant, l'exécutable ssh peut les utiliser si l'agent est démarré. +XPipe démarrera automatiquement le processus de l'agent s'il n'est pas encore en cours d'exécution. + +### Fichier d'identité + +Tu peux également spécifier un fichier d'identité avec une phrase de passe optionnelle. +Cette option est l'équivalent de `ssh -i `. + +Note qu'il doit s'agir de la clé *privée*, et non de la clé publique. +Si tu confonds les deux, ssh ne te donnera que des messages d'erreur énigmatiques. + +### Agent GPG + +Si tes identités sont stockées par exemple sur une carte à puce, tu peux choisir de les fournir au client SSH via le `gpg-agent`. +Cette option activera automatiquement la prise en charge SSH de l'agent si elle n'est pas encore activée et redémarrera le démon de l'agent GPG avec les bons paramètres. + +### Yubikey PIV + +Si tes identités sont stockées avec la fonction de carte à puce PIV du Yubikey, tu peux les récupérer à l'aide du logiciel Yubico +les récupérer avec la bibliothèque YKCS11 de Yubico, qui est fournie avec Yubico PIV Tool. + +Note que tu as besoin d'une version à jour d'OpenSSH pour utiliser cette fonction. + +### Agent personnalisé + +Tu peux également utiliser un agent personnalisé en indiquant ici l'emplacement de la prise ou l'emplacement du tuyau nommé. +Ceci sera transmis via l'option `IdentityAgent`. + +### Bibliothèque PKCS#11 personnalisée + +Ceci demandera au client OpenSSH de charger le fichier de bibliothèque partagée spécifié, qui gérera l'authentification. + +Note que tu as besoin d'une version à jour d'OpenSSH pour utiliser cette fonction. diff --git a/lang/proc/texts/sshLocalTunnelBinding_fr.md b/lang/proc/texts/sshLocalTunnelBinding_fr.md new file mode 100644 index 000000000..85035959f --- /dev/null +++ b/lang/proc/texts/sshLocalTunnelBinding_fr.md @@ -0,0 +1,5 @@ +## Reliure + +Les informations de liaison que tu fournis sont transmises directement au client `ssh` de la manière suivante : `-L [origin_address :]origin_port:remote_address:remote_port`. + +Par défaut, l'origine se lie à l'interface de bouclage si elle n'est pas spécifiée autrement. Tu peux également utiliser des caractères génériques, par exemple en fixant l'adresse à `0.0.0.0` afin de lier toutes les interfaces réseau accessibles via IPv4. Lorsque tu omets complètement l'adresse, le caractère générique `*`, qui autorise les connexions sur toutes les interfaces réseau, sera utilisé. Note que certaines notations d'interfaces réseau peuvent ne pas être prises en charge par tous les systèmes d'exploitation. Les serveurs Windows, par exemple, ne prennent pas en charge le caractère générique `*`. diff --git a/lang/proc/texts/sshLocalTunnelOrigin_fr.md b/lang/proc/texts/sshLocalTunnelOrigin_fr.md new file mode 100644 index 000000000..abfda4c61 --- /dev/null +++ b/lang/proc/texts/sshLocalTunnelOrigin_fr.md @@ -0,0 +1,7 @@ +## Origine du tunnel + +XPipe est totalement flexible en ce qui concerne le lieu d'exécution d'une commande. +Tu peux donc établir un tunnel à partir de n'importe quel système distant en plus de ta machine locale. + +La commande d'ouverture du tunnel sera exécutée sur le système que tu spécifies ici, tu dois donc avoir un client `ssh` installé sur ce système. +Si l'origine n'est pas la machine locale, XPipe gardera une connexion ouverte vers ce système distant en arrière-plan pour gérer le tunnel. \ No newline at end of file diff --git a/lang/proc/texts/sshOptions_fr.md b/lang/proc/texts/sshOptions_fr.md new file mode 100644 index 000000000..b1957cd3d --- /dev/null +++ b/lang/proc/texts/sshOptions_fr.md @@ -0,0 +1,27 @@ +## Configurations SSH + +Ici, tu peux spécifier toutes les options SSH qui doivent être transmises à la connexion. +Alors que certaines options sont essentiellement nécessaires pour établir avec succès une connexion, comme `HostName`, +de nombreuses autres options sont purement facultatives. + +Pour avoir une vue d'ensemble de toutes les options possibles, tu peux utiliser [`man ssh_config`](https://linux.die.net/man/5/ssh_config) ou lire ce [guide](https://www.ssh.com/academy/ssh/config). +Le nombre exact d'options prises en charge dépend purement du client SSH que tu as installé. + +### Formatage + +Le contenu ici est équivalent à une section d'hôte dans un fichier de configuration SSH. +Note que tu n'as pas besoin de définir explicitement la clé `Host`, car cela sera fait automatiquement. + +Si tu as l'intention de définir plus d'une section d'hôte, par exemple avec des connexions dépendantes telles qu'un hôte de saut de proxy qui dépend d'un autre hôte de configuration, tu peux définir plusieurs entrées d'hôte ici aussi. XPipe lancera alors la première entrée d'hôte. + +Tu n'as pas à effectuer de formatage avec des espaces blancs ou des indentations, ce n'est pas nécessaire pour que cela fonctionne. + +Note que tu dois prendre soin de mettre les valeurs entre guillemets si elles contiennent des espaces, sinon elles seront transmises de manière incorrecte. + +### Fiches d'identité + +Note que tu peux également spécifier une option `IdentityFile` ici. +Si cette option est spécifiée ici, toute option d'authentification par clé spécifiée par ailleurs plus bas sera ignorée. + +Si tu choisis de faire référence à un fichier d'identité géré dans le coffre-fort git de XPipe, tu peux également le faire. +XPipe détectera les fichiers d'identité partagés et adaptera automatiquement le chemin du fichier sur chaque système sur lequel tu as cloné le coffre-fort git. diff --git a/lang/proc/texts/sshRemoteTunnelBinding_fr.md b/lang/proc/texts/sshRemoteTunnelBinding_fr.md new file mode 100644 index 000000000..142e30855 --- /dev/null +++ b/lang/proc/texts/sshRemoteTunnelBinding_fr.md @@ -0,0 +1,5 @@ +## Reliure + +Les informations de liaison que tu fournis sont transmises directement au client `ssh` de la manière suivante : `-R [remote_source_address :]remote_source_port:origin_destination_address:origin_destination_port`. + +Par défaut, l'adresse source distante se lie à l'interface de bouclage. Tu peux également utiliser des caractères génériques, par exemple en fixant l'adresse à `0.0.0.0` afin de lier toutes les interfaces réseau accessibles via IPv4. Lorsque tu omets complètement l'adresse, le caractère générique `*`, qui autorise les connexions sur toutes les interfaces réseau, sera utilisé. Note que certaines notations d'interfaces réseau peuvent ne pas être prises en charge par tous les systèmes d'exploitation. Les serveurs Windows, par exemple, ne prennent pas en charge le caractère générique `*`. diff --git a/lang/proc/texts/sshRemoteTunnelOrigin_fr.md b/lang/proc/texts/sshRemoteTunnelOrigin_fr.md new file mode 100644 index 000000000..a5cfa4831 --- /dev/null +++ b/lang/proc/texts/sshRemoteTunnelOrigin_fr.md @@ -0,0 +1,7 @@ +## Origine du tunnel + +XPipe est totalement flexible en ce qui concerne l'endroit où exécuter une commande. +Tu peux donc établir un tunnel sur n'importe quel système en plus de ta machine locale. + +La commande d'ouverture du tunnel sera exécutée sur le système que tu spécifies ici, tu dois donc avoir un client `ssh` installé sur ce système. +Si l'origine n'est pas la machine locale, XPipe gardera une connexion ouverte vers ce système distant en arrière-plan pour gérer le tunnel. \ No newline at end of file diff --git a/lang/proc/texts/vmwarePassword_fr.md b/lang/proc/texts/vmwarePassword_fr.md new file mode 100644 index 000000000..614c229cd --- /dev/null +++ b/lang/proc/texts/vmwarePassword_fr.md @@ -0,0 +1,4 @@ +### Mot de passe + +Il est nécessaire d'avoir un mot de passe pour pouvoir utiliser cette fonctionnalité via l'interface VMware. +Si ton compte d'utilisateur invité n'a pas encore de mot de passe, définis-en un. diff --git a/lang/proc/texts/vncTunnelHost_fr.md b/lang/proc/texts/vncTunnelHost_fr.md new file mode 100644 index 000000000..ba094ef77 --- /dev/null +++ b/lang/proc/texts/vncTunnelHost_fr.md @@ -0,0 +1,5 @@ +## Hôte du tunnel VNC + +Tu peux te connecter à un hôte VNC distant via un tunnel SSH. Cela te permet d'utiliser les fonctions d'authentification SSH les plus avancées avec VNC. C'est important car VNC est un protocole fondamentalement non sécurisé et non crypté. Le tunnel fournit la couche de sécurité nécessaire. + +Tu n'as pas non plus à te soucier d'exposer le port VNC sur ton système distant puisqu'il doit seulement être accessible via SSH. \ No newline at end of file diff --git a/lang/uacc/strings/translations_fr.properties b/lang/uacc/strings/translations_fr.properties new file mode 100644 index 000000000..cb9e120a8 --- /dev/null +++ b/lang/uacc/strings/translations_fr.properties @@ -0,0 +1,30 @@ +communityDescription=Un outil puissant de connexion parfait pour tes cas d'utilisation personnels. +professionalDescription=Gestion professionnelle des connexions pour l'ensemble de ton infrastructure de serveurs. +buyProfessional=Essaie XPipe professional +extendProfessional=Mise à jour vers les dernières fonctionnalités professionnelles +communityItem1=Connexions illimitées à des systèmes et outils non commerciaux +communityItem2=Intégration transparente avec les terminaux et les éditeurs que tu as installés +communityItem3=Navigateur de fichiers à distance complet +communityItem4=Système de script puissant pour tous les shells +communityItem5=Intégration Git pour la synchronisation et le partage des informations de connexion +professionalItem1=Toutes les fonctionnalités de l'édition communautaire +professionalItem2=Connexions illimitées à tous les systèmes et outils commerciaux +professionalItem3=Prise en charge des schémas d'authentification d'entreprise pour les connexions à distance +professionalItem4=Comprend toutes les futures fonctionnalités de l'édition professionnelle pendant 1 an +professionalItem5=Reçoit les mises à jour des fonctionnalités et de la sécurité pour toujours +status=Statut +type=Type de texte +licenseAlertTitle=Usage commercial +useCommunity=Continue avec la communauté +previewDescription=Essaie les nouvelles fonctionnalités pendant quelques semaines après leur publication. +tryPreview=Activer l'aperçu de XPipe +previewItem1=Accès complet aux fonctionnalités professionnelles nouvellement publiées pendant 2 semaines après la sortie de la version +previewItem2=Comprend toutes les fonctionnalités de l'édition communautaire +licensedTo=Sous licence +email=Adresse électronique +apply=Appliquer +clear=Effacer +activate=Activer +validUntil=Valable jusqu'au +licenseActivated=Licence activée +restart=Redémarrer diff --git a/lang/uacc/texts/contact_fr.md b/lang/uacc/texts/contact_fr.md new file mode 100644 index 000000000..7491c4915 --- /dev/null +++ b/lang/uacc/texts/contact_fr.md @@ -0,0 +1,6 @@ +Si tu as des questions, si tu rencontres des problèmes, ou quoi que ce soit d'autre, tu peux nous contacter : + +- Envoie-nous un courriel à [hello@xpipe.io](mailto://hello@xpipe.io) +- Rejoindre le [Serveur XPipe Discord](https://discord.gg/8y89vS8cRb) +- Rejoins le [Serveur XPipe Slack](https://join.slack.com/t/XPipe/shared_invite/zt-1awjq0t5j-5i4UjNJfNe1VN4b_auu6Cg) +- Ouvre un problème dans le [dépôt GitHub](https://github.com/xpipe-io/xpipe) \ No newline at end of file diff --git a/lang/uacc/texts/licenseActivated_fr.md b/lang/uacc/texts/licenseActivated_fr.md new file mode 100644 index 000000000..8da67ab09 --- /dev/null +++ b/lang/uacc/texts/licenseActivated_fr.md @@ -0,0 +1,3 @@ +## Ta licence a été activée avec succès ! + +Pour avoir accès à tes nouvelles fonctionnalités, redémarre l'application XPipe. \ No newline at end of file diff --git a/lang/uacc/texts/preview_fr.md b/lang/uacc/texts/preview_fr.md new file mode 100644 index 000000000..8d68d25ea --- /dev/null +++ b/lang/uacc/texts/preview_fr.md @@ -0,0 +1,11 @@ +# Aperçu de XPipe Pro + +La fonction que tu essayes d'utiliser est disponible dans l'aperçu pro, qui permet à toute personne intéressée d'essayer les nouvelles fonctions réservées aux professionnels pendant deux semaines après leur sortie. Cela te permet également d'expérimenter, de partager tes commentaires et d'avoir un aperçu de toutes les nouvelles fonctionnalités sans avoir à acheter quoi que ce soit. + +Par ailleurs, les nouvelles fonctionnalités bénéficient également d'une meilleure couverture de test que ce qui serait possible sans la prévisualisation pour tout le monde. + +## Vérification + +Une fois que le plan de prévisualisation est activé, l'application communique avec le serveur de licences à chaque démarrage pour vérifier que tout est en ordre. De là, elle récupère également les informations actuelles sur les fonctionnalités qui sont actuellement nouvelles et qui sont encore incluses dans la prévisualisation. + +Tu peux également désactiver à nouveau la prévisualisation à tout moment.