mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-21 23:20:23 +00:00
Various fixes
This commit is contained in:
parent
a035f9498d
commit
3a9788fa76
18 changed files with 119 additions and 33 deletions
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Path> 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();
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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."));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ public interface OsType {
|
|||
}
|
||||
}
|
||||
|
||||
String makeFileSystemCompatible(String path);
|
||||
String makeFileSystemCompatible(String name);
|
||||
|
||||
List<String> 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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
19
dist/licenses/vernacular-vnc.license
vendored
Normal file
19
dist/licenses/vernacular-vnc.license
vendored
Normal file
|
@ -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.
|
4
dist/licenses/vernacular-vnc.properties
vendored
Normal file
4
dist/licenses/vernacular-vnc.properties
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
name=Vernacular VNC
|
||||
version=1.17
|
||||
license=MIT License
|
||||
link=https://github.com/shinyhut/vernacular-vnc
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -423,3 +423,4 @@ attributes=属性
|
|||
modified=変更された
|
||||
isOnlySupported=プロフェッショナルライセンスでのみサポートされる
|
||||
areOnlySupported=プロフェッショナルライセンスでのみサポートされる
|
||||
updateReadyTitle=$VERSION$ に更新
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -423,3 +423,4 @@ attributes=Атрибуты
|
|||
modified=Изменено
|
||||
isOnlySupported=поддерживается только при наличии профессиональной лицензии
|
||||
areOnlySupported=поддерживаются только с профессиональной лицензией
|
||||
updateReadyTitle=Обновление на $VERSION$ готово
|
||||
|
|
|
@ -423,3 +423,4 @@ attributes=属性
|
|||
modified=已修改
|
||||
isOnlySupported=只有专业许可证才支持
|
||||
areOnlySupported=只有专业许可证才支持
|
||||
updateReadyTitle=更新至$VERSION$ ready
|
||||
|
|
Loading…
Reference in a new issue