From 3a9788fa76354fd97421163f422d8ae1210d114a Mon Sep 17 00:00:00 2001 From: crschnick Date: Sat, 13 Apr 2024 15:26:56 +0000 Subject: [PATCH] Various fixes --- .../app/browser/BrowserTransferComp.java | 30 ++++++++------ .../app/browser/file/FileSystemHelper.java | 25 +++++++----- app/src/main/java/io/xpipe/app/core/App.java | 6 +-- .../io/xpipe/app/core/check/AppPtbCheck.java | 2 +- .../java/io/xpipe/core/process/OsType.java | 16 ++++---- .../java/io/xpipe/core/store/FilePath.java | 40 +++++++++++++++++++ dist/licenses/vernacular-vnc.license | 19 +++++++++ dist/licenses/vernacular-vnc.properties | 4 ++ lang/app/strings/translations_de.properties | 1 + lang/app/strings/translations_en.properties | 1 + lang/app/strings/translations_es.properties | 1 + lang/app/strings/translations_fr.properties | 1 + lang/app/strings/translations_it.properties | 1 + lang/app/strings/translations_ja.properties | 1 + lang/app/strings/translations_nl.properties | 1 + lang/app/strings/translations_pt.properties | 1 + lang/app/strings/translations_ru.properties | 1 + lang/app/strings/translations_zh.properties | 1 + 18 files changed, 119 insertions(+), 33 deletions(-) create mode 100644 dist/licenses/vernacular-vnc.license create mode 100644 dist/licenses/vernacular-vnc.properties 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 01b12d6d7..652431b1c 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserTransferComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserTransferComp.java @@ -38,18 +38,22 @@ public class BrowserTransferComp extends SimpleComp { @Override protected Region createSimple() { + var syncItems = PlatformThread.sync(model.getItems()); + var syncDownloaded = PlatformThread.sync(model.getDownloading()); + var syncAllDownloaded = PlatformThread.sync(model.getAllDownloaded()); + var background = new LabelComp(AppI18n.observable("transferDescription")) .apply(struc -> struc.get().setGraphic(new FontIcon("mdi2d-download-outline"))) - .visible(Bindings.isEmpty(model.getItems())); + .visible(Bindings.isEmpty(syncItems)); var backgroundStack = new StackComp(List.of(background)).grow(true, true).styleClass("download-background"); - var binding = ListBindingsHelper.mappedContentBinding(model.getItems(), item -> item.getFileEntry()); + var binding = ListBindingsHelper.mappedContentBinding(syncItems, item -> item.getFileEntry()); var list = new BrowserSelectionListComp( binding, entry -> Bindings.createStringBinding( () -> { - var sourceItem = model.getItems().stream() + var sourceItem = syncItems.stream() .filter(item -> item.getFileEntry() == entry) .findAny(); if (sourceItem.isEmpty()) { @@ -64,27 +68,27 @@ public class BrowserTransferComp extends SimpleComp { .orElse("?"); return FileNames.getFileName(entry.getPath()) + " (" + name + ")"; }, - model.getAllDownloaded())) + syncAllDownloaded)) .apply(struc -> struc.get().setMinHeight(150)) .grow(false, true); - var dragNotice = new LabelComp(model.getAllDownloaded() + var dragNotice = new LabelComp(syncAllDownloaded .flatMap(aBoolean -> aBoolean ? AppI18n.observable("dragLocalFiles") : AppI18n.observable("dragFiles"))) .apply(struc -> struc.get().setGraphic(new FontIcon("mdi2h-hand-left"))) - .hide(PlatformThread.sync(Bindings.isEmpty(model.getItems()))) + .hide(Bindings.isEmpty(syncItems)) .grow(true, false) .apply(struc -> struc.get().setPadding(new Insets(8))); var downloadButton = new IconButtonComp("mdi2d-download", () -> { model.download(); }) - .hide(Bindings.isEmpty(model.getItems())) - .disable(PlatformThread.sync(model.getAllDownloaded())) + .hide(Bindings.isEmpty(syncItems)) + .disable(syncAllDownloaded) .apply(new TooltipAugment<>("downloadStageDescription")); var clearButton = new IconButtonComp("mdi2c-close", () -> { model.clear(); }) - .hide(Bindings.isEmpty(model.getItems())); + .hide(Bindings.isEmpty(syncItems)); var clearPane = Comp.derive( new HorizontalComp(List.of(downloadButton, clearButton)) .apply(struc -> struc.get().setSpacing(10)), @@ -144,11 +148,11 @@ public class BrowserTransferComp extends SimpleComp { } }); struc.get().setOnDragDetected(event -> { - if (model.getDownloading().get()) { + if (syncDownloaded.getValue()) { return; } - var selected = model.getItems().stream() + var selected = syncItems.stream() .map(BrowserTransferModel.Item::getFileEntry) .toList(); Dragboard db = struc.get().startDragAndDrop(TransferMode.COPY); @@ -158,7 +162,7 @@ public class BrowserTransferComp extends SimpleComp { return; } - var files = model.getItems().stream() + var files = syncItems.stream() .filter(item -> item.downloadFinished().get()) .map(item -> { try { @@ -195,7 +199,7 @@ public class BrowserTransferComp extends SimpleComp { event.consume(); }); }), - PlatformThread.sync(model.getDownloading())); + syncDownloaded); return stack.styleClass("transfer").createRegion(); } } 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 6dab09a9d..6698b962c 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 @@ -4,16 +4,14 @@ import io.xpipe.app.browser.BrowserTransferProgress; import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.core.process.OsType; -import io.xpipe.core.store.FileKind; -import io.xpipe.core.store.FileNames; -import io.xpipe.core.store.FileSystem; -import io.xpipe.core.store.LocalStore; +import io.xpipe.core.store.*; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; +import java.time.Instant; import java.util.LinkedHashMap; import java.util.List; import java.util.concurrent.atomic.AtomicLong; @@ -153,6 +151,18 @@ public class FileSystemHelper { Files.isDirectory(file) ? FileKind.DIRECTORY : FileKind.FILE); } + public static FileSystem.FileEntry getRemoteWrapper(FileSystem fileSystem, String file) throws Exception { + return new FileSystem.FileEntry( + fileSystem, + file, + Instant.now(), + false, + false, + fileSystem.getFileSize(file), + null, + fileSystem.directoryExists(file) ? FileKind.DIRECTORY : FileKind.FILE); + } + public static void dropLocalFilesInto( FileSystem.FileEntry entry, List files, @@ -296,11 +306,8 @@ 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 fixedRelPath = new FilePath(e.getValue()).fileSystemCompatible(target.getFileSystem().getShell().orElseThrow().getOsType()); + var targetFile = FileNames.join(target.getPath(), fixedRelPath.toString()); if (sourceFile.getFileSystem().equals(target.getFileSystem())) { throw new IllegalStateException(); } diff --git a/app/src/main/java/io/xpipe/app/core/App.java b/app/src/main/java/io/xpipe/app/core/App.java index 99a9e6171..df6873f9c 100644 --- a/app/src/main/java/io/xpipe/app/core/App.java +++ b/app/src/main/java/io/xpipe/app/core/App.java @@ -65,13 +65,13 @@ public class App extends Application { "XPipe %s (%s)", t.getValue(), AppProperties.get().getVersion()); var prefix = AppProperties.get().isStaging() ? "[Public Test Build, Not a proper release] " : ""; var suffix = u.getValue() != null - ? String.format( - " (Update to %s ready)", u.getValue().getVersion()) + ? AppI18n.get("updateReadyTitle", u.getValue().getVersion()) : ""; return prefix + base + suffix; }, u, - t); + t, + AppPrefs.get().language()); var appWindow = AppMainWindow.init(stage); appWindow.getStage().titleProperty().bind(PlatformThread.sync(titleBinding)); diff --git a/app/src/main/java/io/xpipe/app/core/check/AppPtbCheck.java b/app/src/main/java/io/xpipe/app/core/check/AppPtbCheck.java index 0dc00b6c7..458fd1505 100644 --- a/app/src/main/java/io/xpipe/app/core/check/AppPtbCheck.java +++ b/app/src/main/java/io/xpipe/app/core/check/AppPtbCheck.java @@ -18,7 +18,7 @@ public class AppPtbCheck { .setContent(AppWindowHelper.alertContentText("You are running a PTB build of XPipe." + " This version is unstable and might contain bugs." + " You should not use it as a daily driver." - + " It will also not receive regular updates." + + " It will also not receive regular updates after its testing period." + " You will have to install and launch the normal XPipe release for that.")); }); } diff --git a/core/src/main/java/io/xpipe/core/process/OsType.java b/core/src/main/java/io/xpipe/core/process/OsType.java index 735247ce5..30765336d 100644 --- a/core/src/main/java/io/xpipe/core/process/OsType.java +++ b/core/src/main/java/io/xpipe/core/process/OsType.java @@ -28,7 +28,7 @@ public interface OsType { } } - String makeFileSystemCompatible(String path); + String makeFileSystemCompatible(String name); List determineInterestingPaths(ShellControl pc) throws Exception; @@ -57,8 +57,8 @@ public interface OsType { final class Windows implements OsType, Local, Any { @Override - public String makeFileSystemCompatible(String path) { - return path.replaceAll("[<>:\"/\\\\|?*]", "_").replaceAll("\\p{C}", ""); + public String makeFileSystemCompatible(String name) { + return name.replaceAll("[<>:\"/\\\\|?*]", "_").replaceAll("\\p{C}", ""); } @Override @@ -124,8 +124,9 @@ public interface OsType { class Unix implements OsType { @Override - public String makeFileSystemCompatible(String path) { - return path.replaceAll("/", "_").replaceAll("\0", ""); + public String makeFileSystemCompatible(String name) { + // Technically the backslash is supported, but it causes all kinds of troubles, so we also exclude it + return name.replaceAll("/\\\\", "_").replaceAll("\0", ""); } @Override @@ -211,8 +212,9 @@ public interface OsType { final class MacOs implements OsType, Local, Any { @Override - public String makeFileSystemCompatible(String path) { - return path.replaceAll("[/:]", "_").replaceAll("\0", ""); + public String makeFileSystemCompatible(String name) { + // Technically the backslash is supported, but it causes all kinds of troubles, so we also exclude it + return name.replaceAll("[\\\\/:]", "_").replaceAll("\0", ""); } @Override diff --git a/core/src/main/java/io/xpipe/core/store/FilePath.java b/core/src/main/java/io/xpipe/core/store/FilePath.java index 8e79be099..331c31d61 100644 --- a/core/src/main/java/io/xpipe/core/store/FilePath.java +++ b/core/src/main/java/io/xpipe/core/store/FilePath.java @@ -1,5 +1,6 @@ package io.xpipe.core.store; +import io.xpipe.core.process.OsType; import lombok.EqualsAndHashCode; import lombok.NonNull; @@ -7,10 +8,19 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.regex.Pattern; @EqualsAndHashCode public final class FilePath { + public static boolean isProbableFilePath(OsType osType, String s) { + if (osType.equals(OsType.WINDOWS) && s.length() >= 2 && s.charAt(1) == ':') { + return true; + } + + return s.startsWith("/"); + } + @NonNull private final String value; @@ -24,6 +34,36 @@ public final class FilePath { } } + public FilePath fileSystemCompatible(OsType osType) { + var split = split(); + var needsReplacement = split.stream().anyMatch(s -> !s.equals(osType.makeFileSystemCompatible(s))); + if (!needsReplacement) { + return this; + } + + var backslash = value.contains("\\"); + var p = Pattern.compile("[^/\\\\]+"); + var m = p.matcher(value); + var replaced = m.replaceAll(matchResult -> osType.makeFileSystemCompatible(matchResult.group())); + return new FilePath(replaced); + } + + public FilePath getRoot() { + if (value.startsWith("/")) { + return new FilePath("/"); + } else if (value.length() >= 2 && value.charAt(1) == ':') { + // Without the trailing slash, many programs struggle with this + return new FilePath(value.substring(0, 2) + "\\"); + } else if (value.startsWith("\\\\")) { + var split = split(); + if (split.size() > 0) { + return new FilePath("\\\\" + split.getFirst()); + } + } + + throw new IllegalArgumentException("Unable to determine root of " + value); + } + public Path toLocalPath() { return Path.of(value); } diff --git a/dist/licenses/vernacular-vnc.license b/dist/licenses/vernacular-vnc.license new file mode 100644 index 000000000..9b4ca945a --- /dev/null +++ b/dist/licenses/vernacular-vnc.license @@ -0,0 +1,19 @@ +Copyright (c) 2018 ShinyHut Solutions Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dist/licenses/vernacular-vnc.properties b/dist/licenses/vernacular-vnc.properties new file mode 100644 index 000000000..33c6bc829 --- /dev/null +++ b/dist/licenses/vernacular-vnc.properties @@ -0,0 +1,4 @@ +name=Vernacular VNC +version=1.17 +license=MIT License +link=https://github.com/shinyhut/vernacular-vnc \ No newline at end of file diff --git a/lang/app/strings/translations_de.properties b/lang/app/strings/translations_de.properties index 02563e7a3..09a6356e2 100644 --- a/lang/app/strings/translations_de.properties +++ b/lang/app/strings/translations_de.properties @@ -433,3 +433,4 @@ attributes=Attribute modified=Geändert isOnlySupported=wird nur mit einer professionellen Lizenz unterstützt areOnlySupported=werden nur mit einer professionellen Lizenz unterstützt +updateReadyTitle=Update auf $VERSION$ bereit diff --git a/lang/app/strings/translations_en.properties b/lang/app/strings/translations_en.properties index f3fc7cf4e..98b722860 100644 --- a/lang/app/strings/translations_en.properties +++ b/lang/app/strings/translations_en.properties @@ -438,3 +438,4 @@ attributes=Attributes modified=Modified isOnlySupported=is only supported with a professional license areOnlySupported=are only supported with a professional license +updateReadyTitle=Update to $VERSION$ ready diff --git a/lang/app/strings/translations_es.properties b/lang/app/strings/translations_es.properties index d840f1bc7..cc75dbbc7 100644 --- a/lang/app/strings/translations_es.properties +++ b/lang/app/strings/translations_es.properties @@ -423,3 +423,4 @@ attributes=Atributos modified=Modificado isOnlySupported=sólo es compatible con una licencia profesional areOnlySupported=sólo son compatibles con una licencia profesional +updateReadyTitle=Actualiza a $VERSION$ ready diff --git a/lang/app/strings/translations_fr.properties b/lang/app/strings/translations_fr.properties index 6f5dd8ae9..b1ee2eb1f 100644 --- a/lang/app/strings/translations_fr.properties +++ b/lang/app/strings/translations_fr.properties @@ -423,3 +423,4 @@ attributes=Attributs modified=Modifié isOnlySupported=n'est pris en charge qu'avec une licence professionnelle areOnlySupported=ne sont pris en charge qu'avec une licence professionnelle +updateReadyTitle=Mise à jour de $VERSION$ ready diff --git a/lang/app/strings/translations_it.properties b/lang/app/strings/translations_it.properties index 458800e5f..9a08d8a15 100644 --- a/lang/app/strings/translations_it.properties +++ b/lang/app/strings/translations_it.properties @@ -423,3 +423,4 @@ attributes=Attributi modified=Modificato isOnlySupported=è supportato solo con una licenza professionale areOnlySupported=sono supportati solo con una licenza professionale +updateReadyTitle=Aggiornamento a $VERSION$ ready diff --git a/lang/app/strings/translations_ja.properties b/lang/app/strings/translations_ja.properties index 294dc5c74..7e341d191 100644 --- a/lang/app/strings/translations_ja.properties +++ b/lang/app/strings/translations_ja.properties @@ -423,3 +423,4 @@ attributes=属性 modified=変更された isOnlySupported=プロフェッショナルライセンスでのみサポートされる areOnlySupported=プロフェッショナルライセンスでのみサポートされる +updateReadyTitle=$VERSION$ に更新 diff --git a/lang/app/strings/translations_nl.properties b/lang/app/strings/translations_nl.properties index c2fd15a26..5543c107b 100644 --- a/lang/app/strings/translations_nl.properties +++ b/lang/app/strings/translations_nl.properties @@ -423,3 +423,4 @@ attributes=Attributen modified=Gewijzigd isOnlySupported=wordt alleen ondersteund met een professionele licentie areOnlySupported=worden alleen ondersteund met een professionele licentie +updateReadyTitle=Bijwerken naar $VERSION$ klaar diff --git a/lang/app/strings/translations_pt.properties b/lang/app/strings/translations_pt.properties index 43f215125..3a3d9fffc 100644 --- a/lang/app/strings/translations_pt.properties +++ b/lang/app/strings/translations_pt.properties @@ -423,3 +423,4 @@ attributes=Atribui modified=Modificado isOnlySupported=só é suportado com uma licença profissional areOnlySupported=só são suportados com uma licença profissional +updateReadyTitle=Actualiza para $VERSION$ ready diff --git a/lang/app/strings/translations_ru.properties b/lang/app/strings/translations_ru.properties index cf0cea2a0..fb17a6169 100644 --- a/lang/app/strings/translations_ru.properties +++ b/lang/app/strings/translations_ru.properties @@ -423,3 +423,4 @@ attributes=Атрибуты modified=Изменено isOnlySupported=поддерживается только при наличии профессиональной лицензии areOnlySupported=поддерживаются только с профессиональной лицензией +updateReadyTitle=Обновление на $VERSION$ готово diff --git a/lang/app/strings/translations_zh.properties b/lang/app/strings/translations_zh.properties index 47c9ca8b8..23075f2cd 100644 --- a/lang/app/strings/translations_zh.properties +++ b/lang/app/strings/translations_zh.properties @@ -423,3 +423,4 @@ attributes=属性 modified=已修改 isOnlySupported=只有专业许可证才支持 areOnlySupported=只有专业许可证才支持 +updateReadyTitle=更新至$VERSION$ ready