mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-21 15:10:23 +00:00
[stage]
This commit is contained in:
parent
9f232aa7d1
commit
4c64eb5ae5
22 changed files with 166 additions and 183 deletions
|
@ -7,6 +7,7 @@ import io.xpipe.app.core.window.AppWindowHelper;
|
|||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.SimpleComp;
|
||||
import io.xpipe.app.fxcomps.impl.PrettyImageHelper;
|
||||
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||
|
||||
import javafx.beans.binding.Bindings;
|
||||
|
@ -58,9 +59,15 @@ public class BrowserSelectionListComp extends SimpleComp {
|
|||
return Comp.of(() -> {
|
||||
var image = PrettyImageHelper.ofFixedSizeSquare(entry.getIcon(), 24)
|
||||
.createRegion();
|
||||
var l = new Label(null, image);
|
||||
var t = nameTransformation.apply(entry);
|
||||
var l = new Label(t.getValue(), image);
|
||||
l.setTextOverrun(OverrunStyle.CENTER_ELLIPSIS);
|
||||
l.textProperty().bind(PlatformThread.sync(nameTransformation.apply(entry)));
|
||||
t.addListener((observable, oldValue, newValue) -> {
|
||||
PlatformThread.runLaterIfNeeded(() -> {
|
||||
l.setText(newValue);
|
||||
});
|
||||
});
|
||||
BindingsHelper.preserve(l, t);
|
||||
return l;
|
||||
});
|
||||
},
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package io.xpipe.app.browser;
|
||||
|
||||
import io.xpipe.app.browser.file.BrowserFileTransferMode;
|
||||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.comp.base.LoadingOverlayComp;
|
||||
import io.xpipe.app.core.AppFont;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
|
@ -11,11 +9,14 @@ import io.xpipe.app.fxcomps.augment.DragOverPseudoClassAugment;
|
|||
import io.xpipe.app.fxcomps.impl.*;
|
||||
import io.xpipe.app.fxcomps.util.DerivedObservableList;
|
||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||
import io.xpipe.app.util.ThreadHelper;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.css.PseudoClass;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.input.ClipboardContent;
|
||||
import javafx.scene.input.Dragboard;
|
||||
import javafx.scene.input.TransferMode;
|
||||
import javafx.scene.layout.Region;
|
||||
|
@ -38,8 +39,6 @@ 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")))
|
||||
|
@ -53,46 +52,42 @@ public class BrowserTransferComp extends SimpleComp {
|
|||
.getList();
|
||||
var list = new BrowserSelectionListComp(
|
||||
binding,
|
||||
entry -> Bindings.createStringBinding(
|
||||
() -> {
|
||||
var sourceItem = syncItems.stream()
|
||||
.filter(item -> item.getBrowserEntry() == entry)
|
||||
.findAny();
|
||||
if (sourceItem.isEmpty()) {
|
||||
return "?";
|
||||
}
|
||||
var name = entry.getModel() == null
|
||||
|| sourceItem
|
||||
.get()
|
||||
.downloadFinished()
|
||||
.get()
|
||||
? "Local"
|
||||
: entry.getModel()
|
||||
.getFileSystemModel()
|
||||
.getName();
|
||||
return entry.getFileName() + " (" + name + ")";
|
||||
},
|
||||
syncAllDownloaded))
|
||||
entry -> {
|
||||
var sourceItem = syncItems.stream()
|
||||
.filter(item -> item.getBrowserEntry() == entry)
|
||||
.findAny();
|
||||
if (sourceItem.isEmpty()) {
|
||||
return new SimpleStringProperty("?");
|
||||
}
|
||||
return Bindings.createStringBinding(() -> {
|
||||
var p = sourceItem.get().getProgress().getValue();
|
||||
var progressSuffix = sourceItem.get().downloadFinished().get() ? "" : " " + (p.getTransferred() * 100 / p.getTotal()) + "%";
|
||||
return entry.getFileName() + progressSuffix;
|
||||
}, sourceItem.get().getProgress());
|
||||
})
|
||||
.grow(false, true);
|
||||
var dragNotice = new LabelComp(syncAllDownloaded.flatMap(
|
||||
aBoolean -> aBoolean ? AppI18n.observable("dragLocalFiles") : AppI18n.observable("dragFiles")))
|
||||
var dragNotice = new LabelComp(AppI18n.observable("dragLocalFiles"))
|
||||
.apply(struc -> struc.get().setGraphic(new FontIcon("mdi2h-hand-left")))
|
||||
.apply(struc -> AppFont.medium(struc.get()))
|
||||
.apply(struc -> struc.get().setWrapText(true))
|
||||
.hide(Bindings.isEmpty(syncItems));
|
||||
|
||||
var downloadButton = new IconButtonComp("mdi2d-download", () -> {
|
||||
model.download();
|
||||
})
|
||||
.hide(Bindings.isEmpty(syncItems))
|
||||
.disable(syncAllDownloaded)
|
||||
.tooltipKey("downloadStageDescription");
|
||||
var clearButton = new IconButtonComp("mdi2c-close", () -> {
|
||||
model.clear(true);
|
||||
ThreadHelper.runAsync(() -> {
|
||||
model.clear(true);
|
||||
});
|
||||
})
|
||||
.hide(Bindings.isEmpty(syncItems))
|
||||
.tooltipKey("clearTransferDescription");
|
||||
|
||||
var downloadButton = new IconButtonComp("mdi2f-folder-move-outline", () -> {
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
model.transferToDownloads();
|
||||
});
|
||||
})
|
||||
.hide(Bindings.isEmpty(syncItems))
|
||||
.tooltipKey("downloadStageDescription");
|
||||
|
||||
var bottom =
|
||||
new HorizontalComp(List.of(Comp.hspacer(), dragNotice, Comp.hspacer(), downloadButton, Comp.hspacer(4), clearButton));
|
||||
var listBox = new VerticalComp(List.of(list, bottom))
|
||||
|
@ -100,8 +95,7 @@ public class BrowserTransferComp extends SimpleComp {
|
|||
.padding(new Insets(10, 10, 5, 10))
|
||||
.apply(struc -> struc.get().setMinHeight(200))
|
||||
.apply(struc -> struc.get().setMaxHeight(200));
|
||||
var stack = LoadingOverlayComp.noProgress(
|
||||
new StackComp(List.of(backgroundStack, listBox))
|
||||
var stack = new StackComp(List.of(backgroundStack, listBox))
|
||||
.apply(DragOverPseudoClassAugment.create())
|
||||
.apply(struc -> {
|
||||
struc.get().setOnDragOver(event -> {
|
||||
|
@ -110,13 +104,6 @@ public class BrowserTransferComp extends SimpleComp {
|
|||
event.acceptTransferModes(TransferMode.ANY);
|
||||
event.consume();
|
||||
}
|
||||
|
||||
// Accept drops from outside the app window
|
||||
if (event.getGestureSource() == null
|
||||
&& !event.getDragboard().getFiles().isEmpty()) {
|
||||
event.acceptTransferModes(TransferMode.ANY);
|
||||
event.consume();
|
||||
}
|
||||
});
|
||||
struc.get().setOnDragDropped(event -> {
|
||||
// Accept drops from inside the app window
|
||||
|
@ -138,29 +125,14 @@ public class BrowserTransferComp extends SimpleComp {
|
|||
event.setDropCompleted(true);
|
||||
event.consume();
|
||||
}
|
||||
|
||||
// Accept drops from outside the app window
|
||||
if (event.getGestureSource() == null) {
|
||||
model.dropLocal(event.getDragboard().getFiles());
|
||||
event.setDropCompleted(true);
|
||||
event.consume();
|
||||
}
|
||||
});
|
||||
struc.get().setOnDragDetected(event -> {
|
||||
if (syncDownloaded.getValue()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var selected = syncItems.stream()
|
||||
.map(item -> item.getBrowserEntry())
|
||||
.toList();
|
||||
Dragboard db = struc.get().startDragAndDrop(TransferMode.COPY);
|
||||
|
||||
var cc = BrowserClipboard.startDrag(null, selected, BrowserFileTransferMode.NORMAL);
|
||||
if (cc == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var cc = new ClipboardContent();
|
||||
var files = syncItems.stream()
|
||||
.filter(item -> item.downloadFinished().get())
|
||||
.map(item -> {
|
||||
|
@ -197,8 +169,7 @@ public class BrowserTransferComp extends SimpleComp {
|
|||
model.clear(false);
|
||||
event.consume();
|
||||
});
|
||||
}),
|
||||
syncDownloaded);
|
||||
});
|
||||
|
||||
stack.apply(struc -> {
|
||||
model.getBrowserSessionModel().getDraggingFiles().addListener((observable, oldValue, newValue) -> {
|
||||
|
|
|
@ -7,45 +7,49 @@ import io.xpipe.app.browser.file.LocalFileSystem;
|
|||
import io.xpipe.app.browser.fs.OpenFileSystemModel;
|
||||
import io.xpipe.app.browser.session.BrowserSessionModel;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.util.BooleanScope;
|
||||
import io.xpipe.app.util.DesktopHelper;
|
||||
import io.xpipe.app.util.ShellTemp;
|
||||
|
||||
import io.xpipe.app.util.ThreadHelper;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.value.ObservableBooleanValue;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
import lombok.Value;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.Optional;
|
||||
|
||||
@Value
|
||||
public class BrowserTransferModel {
|
||||
|
||||
private static final Path TEMP = ShellTemp.getLocalTempDataDirectory("download");
|
||||
|
||||
ExecutorService executor = Executors.newSingleThreadExecutor(r -> {
|
||||
Thread t = Executors.defaultThreadFactory().newThread(r);
|
||||
t.setDaemon(true);
|
||||
t.setName("file downloader");
|
||||
return t;
|
||||
});
|
||||
BrowserSessionModel browserSessionModel;
|
||||
ObservableList<Item> items = FXCollections.observableArrayList();
|
||||
BooleanProperty downloading = new SimpleBooleanProperty();
|
||||
BooleanProperty allDownloaded = new SimpleBooleanProperty();
|
||||
|
||||
public BrowserTransferModel(BrowserSessionModel browserSessionModel) {
|
||||
this.browserSessionModel = browserSessionModel;
|
||||
var thread = ThreadHelper.createPlatformThread("file downloader", true,() -> {
|
||||
while (true) {
|
||||
Optional<Item> toDownload;
|
||||
synchronized (items) {
|
||||
toDownload = items.stream().filter(item -> !item.downloadFinished().get()).findFirst();
|
||||
}
|
||||
if (toDownload.isPresent()) {
|
||||
downloadSingle(toDownload.get());
|
||||
}
|
||||
ThreadHelper.sleep(20);
|
||||
}
|
||||
});
|
||||
thread.start();
|
||||
}
|
||||
|
||||
private void cleanDirectory() {
|
||||
if (!Files.isDirectory(TEMP)) {
|
||||
|
@ -63,95 +67,77 @@ public class BrowserTransferModel {
|
|||
}
|
||||
|
||||
public void clear(boolean delete) {
|
||||
items.clear();
|
||||
synchronized (items) {
|
||||
items.clear();
|
||||
}
|
||||
if (delete) {
|
||||
executor.submit(() -> {
|
||||
cleanDirectory();
|
||||
});
|
||||
cleanDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
public void drop(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
entries.forEach(entry -> {
|
||||
var name = entry.getFileName();
|
||||
if (items.stream().anyMatch(item -> item.getName().equals(name))) {
|
||||
return;
|
||||
}
|
||||
|
||||
Path file = TEMP.resolve(name);
|
||||
var item = new Item(model, name, entry, file);
|
||||
items.add(item);
|
||||
allDownloaded.set(false);
|
||||
});
|
||||
}
|
||||
|
||||
public void dropLocal(List<File> entries) {
|
||||
if (entries.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var empty = items.isEmpty();
|
||||
try {
|
||||
var paths = entries.stream().map(File::toPath).filter(Files::exists).toList();
|
||||
for (Path path : paths) {
|
||||
var entry = LocalFileSystem.getLocalBrowserEntry(path);
|
||||
synchronized (items) {
|
||||
entries.forEach(entry -> {
|
||||
var name = entry.getFileName();
|
||||
if (items.stream().anyMatch(item -> item.getName().equals(name))) {
|
||||
return;
|
||||
}
|
||||
|
||||
var item = new Item(null, name, entry, path);
|
||||
item.progress.setValue(BrowserTransferProgress.finished(
|
||||
entry.getFileName(), entry.getRawFileEntry().getSize()));
|
||||
Path file = TEMP.resolve(name);
|
||||
var item = new Item(model, name, entry, file);
|
||||
items.add(item);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ErrorEvent.fromThrowable(ex).handle();
|
||||
}
|
||||
if (empty) {
|
||||
allDownloaded.set(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void download() {
|
||||
executor.submit(() -> {
|
||||
try {
|
||||
FileUtils.forceMkdir(TEMP.toFile());
|
||||
} catch (IOException e) {
|
||||
ErrorEvent.fromThrowable(e).handle();
|
||||
public void downloadSingle(Item item) {
|
||||
try {
|
||||
FileUtils.forceMkdir(TEMP.toFile());
|
||||
} catch (IOException e) {
|
||||
ErrorEvent.fromThrowable(e).handle();
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.downloadFinished().get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Item item : new ArrayList<>(items)) {
|
||||
if (item.downloadFinished().get()) {
|
||||
continue;
|
||||
}
|
||||
if (item.getOpenFileSystemModel() != null
|
||||
&& item.getOpenFileSystemModel().isClosed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.getOpenFileSystemModel() != null
|
||||
&& item.getOpenFileSystemModel().isClosed()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
try (var ignored = new BooleanScope(downloading).start()) {
|
||||
var op = new BrowserFileTransferOperation(
|
||||
LocalFileSystem.getLocalFileEntry(TEMP),
|
||||
List.of(item.getBrowserEntry().getRawFileEntry()),
|
||||
BrowserFileTransferMode.COPY,
|
||||
false,
|
||||
progress -> {
|
||||
item.getProgress().setValue(progress);
|
||||
item.getOpenFileSystemModel().getProgress().setValue(progress);
|
||||
});
|
||||
op.execute();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
ErrorEvent.fromThrowable(t).handle();
|
||||
try {
|
||||
var op = new BrowserFileTransferOperation(
|
||||
LocalFileSystem.getLocalFileEntry(TEMP),
|
||||
List.of(item.getBrowserEntry().getRawFileEntry()),
|
||||
BrowserFileTransferMode.COPY,
|
||||
false,
|
||||
progress -> {
|
||||
item.getProgress().setValue(progress);
|
||||
item.getOpenFileSystemModel().getProgress().setValue(progress);
|
||||
});
|
||||
op.execute();
|
||||
} catch (Throwable t) {
|
||||
ErrorEvent.fromThrowable(t).handle();
|
||||
synchronized (items) {
|
||||
items.remove(item);
|
||||
}
|
||||
}
|
||||
allDownloaded.set(true);
|
||||
});
|
||||
}
|
||||
|
||||
public void transferToDownloads() throws Exception {
|
||||
if (items.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var files = items.stream().map(item -> item.getLocalFile()).toList();
|
||||
var downloads = DesktopHelper.getDownloadsDirectory();
|
||||
for (Path file : files) {
|
||||
Files.move(file, downloads.resolve(file.getFileName()), StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
clear(true);
|
||||
DesktopHelper.browseFileInDirectory(downloads.resolve(files.getFirst().getFileName()));
|
||||
}
|
||||
|
||||
@Value
|
||||
|
|
|
@ -41,6 +41,7 @@ public class BrowserTransferProgress {
|
|||
var share = (double) transferred / total;
|
||||
var rest = (1.0 - share) / share;
|
||||
var restMillis = (long) (elapsed.toMillis() * rest);
|
||||
return Duration.of(restMillis, ChronoUnit.MILLIS);
|
||||
var startupAdjustment = (long) (restMillis / (1.0 + Math.max(10000 - elapsed.toMillis(), 0) / 10000.0));
|
||||
return Duration.of(restMillis + startupAdjustment, ChronoUnit.MILLIS);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -229,6 +229,9 @@ public class BrowserFileTransferOperation {
|
|||
OutputStream outputStream = null;
|
||||
try {
|
||||
var fileSize = sourceFile.getFileSystem().getFileSize(sourceFile.getPath());
|
||||
|
||||
// Read the first few bytes to figure out possible command failure early
|
||||
// before creating the output stream
|
||||
inputStream = new BufferedInputStream(sourceFile.getFileSystem().openInput(sourceFile.getPath()), 1024);
|
||||
inputStream.mark(1024);
|
||||
var streamStart = new byte[1024];
|
||||
|
|
|
@ -9,7 +9,6 @@ import io.xpipe.app.fxcomps.SimpleCompStructure;
|
|||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Cursor;
|
||||
import javafx.scene.input.MouseButton;
|
||||
import org.kordamp.ikonli.javafx.FontIcon;
|
||||
|
@ -36,14 +35,12 @@ public class FilterComp extends Comp<CompStructure<CustomTextField>> {
|
|||
}
|
||||
});
|
||||
var filter = new CustomTextField();
|
||||
filter.alignmentProperty().bind(Bindings.createObjectBinding(() -> {
|
||||
return filter.isFocused() || (filter.getText() != null && !filter.getText().isEmpty()) ? Pos.CENTER_LEFT : Pos.CENTER;
|
||||
}, filter.textProperty(), filter.focusedProperty()));
|
||||
filter.setMaxHeight(2000);
|
||||
filter.getStyleClass().add("filter-comp");
|
||||
filter.promptTextProperty().bind(AppI18n.observable("searchFilter"));
|
||||
filter.setLeft(fi);
|
||||
filter.setRight(clear);
|
||||
filter.rightProperty().bind(Bindings.createObjectBinding(() -> {
|
||||
return filter.isFocused() ? clear : fi;
|
||||
}, filter.focusedProperty()));
|
||||
filter.setAccessibleText("Filter");
|
||||
|
||||
filterText.subscribe(val -> {
|
||||
|
|
|
@ -28,6 +28,23 @@ public class DesktopHelper {
|
|||
return Path.of(System.getProperty("user.home") + "/Desktop");
|
||||
}
|
||||
|
||||
public static Path getDownloadsDirectory() throws Exception {
|
||||
if (OsType.getLocal() == OsType.WINDOWS) {
|
||||
return Path.of(LocalShell.getLocalPowershell()
|
||||
.executeSimpleStringCommand("(New-Object -ComObject Shell.Application).NameSpace('shell:Downloads').Self.Path"));
|
||||
} else if (OsType.getLocal() == OsType.LINUX) {
|
||||
try (var cmd = LocalShell.getShell().command("xdg-user-dir DOWNLOAD").start()) {
|
||||
var read = cmd.readStdoutDiscardErr();
|
||||
var exit = cmd.getExitCode();
|
||||
if (exit == 0) {
|
||||
return Path.of(read);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Path.of(System.getProperty("user.home") + "/Downloads");
|
||||
}
|
||||
|
||||
public static void browsePathRemote(ShellControl sc, String path, FileKind kind) throws Exception {
|
||||
var d = sc.getShellDialect();
|
||||
switch (sc.getOsType()) {
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
-fx-padding: 0 6 8 8;
|
||||
}
|
||||
|
||||
.transfer > * {
|
||||
.transfer > .download-background {
|
||||
-fx-border-radius: 4;
|
||||
-fx-background-radius: 4;
|
||||
-fx-border-color: -color-border-default;
|
||||
|
@ -23,7 +23,7 @@
|
|||
-fx-background-color: -color-bg-subtle;
|
||||
}
|
||||
|
||||
.transfer:highlighted > * {
|
||||
.transfer:highlighted > .download-background {
|
||||
-fx-border-color: -color-accent-emphasis;
|
||||
-fx-background-color: derive(-color-bg-subtle, 5%);
|
||||
}
|
||||
|
@ -228,8 +228,8 @@
|
|||
|
||||
.browser .browser-content {
|
||||
-fx-padding: 6 0 0 0;
|
||||
-fx-border-radius: 10 10 4 4;
|
||||
-fx-background-radius: 10 10 4 4;
|
||||
-fx-border-radius: 4;
|
||||
-fx-background-radius: 4;
|
||||
-fx-background-color: -color-bg-subtle, -color-bg-default;
|
||||
-fx-background-insets: 0, 7 0 0 0;
|
||||
-fx-border-width: 1;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.filter-comp {
|
||||
-fx-padding: 0.15em 0.3em 0.15em 0.3em;
|
||||
-fx-padding: 0.15em 0.3em 0.15em 0.7em;
|
||||
-fx-background-color: transparent;
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ lockCreationAlertHeader=Indstil din nye master-adgangssætning
|
|||
#custom
|
||||
finish=Afslut
|
||||
error=Der opstod en fejl
|
||||
downloadStageDescription=Downloader filer til din lokale maskine, så du kan trække og slippe dem i dit oprindelige skrivebordsmiljø.
|
||||
downloadStageDescription=Flytter downloadede filer til dit systems download-bibliotek og åbner det.
|
||||
ok=Ok
|
||||
search=Søg efter
|
||||
newFile=Ny fil
|
||||
|
@ -108,7 +108,7 @@ deleteAlertHeader=Vil du slette de ($COUNT$) valgte elementer?
|
|||
selectedElements=Udvalgte elementer:
|
||||
mustNotBeEmpty=$VALUE$ må ikke være tom
|
||||
valueMustNotBeEmpty=Værdien må ikke være tom
|
||||
transferDescription=Drop filer til overførsel
|
||||
transferDescription=Drop filer til download
|
||||
dragFiles=Træk filer i browseren
|
||||
dragLocalFiles=Træk lokale filer herfra
|
||||
null=$VALUE$ må ikke være nul
|
||||
|
|
|
@ -82,7 +82,7 @@ lockCreationAlertHeader=Lege deine neue Master-Passphrase fest
|
|||
#custom
|
||||
finish=Fertigstellen
|
||||
error=Ein Fehler ist aufgetreten
|
||||
downloadStageDescription=Lädt Dateien auf deinen lokalen Rechner herunter, damit du sie per Drag & Drop in deine native Desktopumgebung ziehen kannst.
|
||||
downloadStageDescription=Verschiebt heruntergeladene Dateien in das Download-Verzeichnis deines Systems und öffnet sie.
|
||||
ok=Ok
|
||||
search=Suche
|
||||
newFile=Neue Datei
|
||||
|
@ -107,7 +107,7 @@ deleteAlertHeader=Willst du die ($COUNT$) ausgewählten Elemente löschen?
|
|||
selectedElements=Ausgewählte Elemente:
|
||||
mustNotBeEmpty=$VALUE$ darf nicht leer sein
|
||||
valueMustNotBeEmpty=Der Wert darf nicht leer sein
|
||||
transferDescription=Dateien zum Übertragen ablegen
|
||||
transferDescription=Dateien zum Herunterladen ablegen
|
||||
dragFiles=Dateien im Browser ziehen
|
||||
dragLocalFiles=Lokale Dateien von hier ziehen
|
||||
null=$VALUE$ muss nicht null sein
|
||||
|
|
|
@ -80,7 +80,8 @@ lockCreationAlertHeader=Set your new master passphrase
|
|||
#context: verb, exit
|
||||
finish=Finish
|
||||
error=An error occurred
|
||||
downloadStageDescription=Downloads files to your local machine, so you can drag and drop them into your native desktop environment.
|
||||
#force
|
||||
downloadStageDescription=Moves downloaded files into your system downloads directory and opens it.
|
||||
ok=Ok
|
||||
search=Search
|
||||
newFile=New file
|
||||
|
@ -105,7 +106,7 @@ deleteAlertHeader=Do you want to delete the ($COUNT$) selected elements?
|
|||
selectedElements=Selected elements:
|
||||
mustNotBeEmpty=$VALUE$ must not be empty
|
||||
valueMustNotBeEmpty=Value must not be empty
|
||||
transferDescription=Drop files to transfer
|
||||
transferDescription=Drop files to download
|
||||
dragFiles=Drag files within browser
|
||||
dragLocalFiles=Drag local files from here
|
||||
null=$VALUE$ must be not null
|
||||
|
|
|
@ -77,7 +77,7 @@ lockCreationAlertTitle=Establecer frase de contraseña
|
|||
lockCreationAlertHeader=Establece tu nueva frase de contraseña maestra
|
||||
finish=Terminar
|
||||
error=Se ha producido un error
|
||||
downloadStageDescription=Descarga archivos a tu máquina local, para que puedas arrastrarlos y soltarlos en tu entorno de escritorio nativo.
|
||||
downloadStageDescription=Mueve los archivos descargados al directorio de descargas de tu sistema y ábrelo.
|
||||
ok=Ok
|
||||
search=Busca en
|
||||
newFile=Nuevo archivo
|
||||
|
@ -102,7 +102,7 @@ deleteAlertHeader=¿Quieres borrar los ($COUNT$) elementos seleccionados?
|
|||
selectedElements=Elementos seleccionados:
|
||||
mustNotBeEmpty=$VALUE$ no debe estar vacío
|
||||
valueMustNotBeEmpty=El valor no debe estar vacío
|
||||
transferDescription=Soltar archivos para transferir
|
||||
transferDescription=Soltar archivos para descargar
|
||||
dragFiles=Arrastrar archivos dentro del navegador
|
||||
dragLocalFiles=Arrastra archivos locales desde aquí
|
||||
null=$VALUE$ debe ser no nulo
|
||||
|
|
|
@ -77,7 +77,7 @@ 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.
|
||||
downloadStageDescription=Déplace les fichiers téléchargés dans le répertoire des téléchargements de ton système et l'ouvre.
|
||||
ok=Ok
|
||||
search=Rechercher
|
||||
newFile=Nouveau fichier
|
||||
|
@ -102,7 +102,7 @@ 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
|
||||
transferDescription=Dépose des fichiers à télécharger
|
||||
dragFiles=Faire glisser des fichiers dans le navigateur
|
||||
dragLocalFiles=Fais glisser des fichiers locaux à partir d'ici
|
||||
null=$VALUE$ doit être non nul
|
||||
|
|
|
@ -77,7 +77,7 @@ lockCreationAlertTitle=Imposta una passphrase
|
|||
lockCreationAlertHeader=Imposta la tua nuova passphrase principale
|
||||
finish=Terminare
|
||||
error=Si è verificato un errore
|
||||
downloadStageDescription=Scarica i file sul tuo computer locale, in modo che tu possa trascinarli e rilasciarli nel tuo ambiente desktop nativo.
|
||||
downloadStageDescription=Sposta i file scaricati nella directory dei download del sistema e li apre.
|
||||
ok=Ok
|
||||
search=Ricerca
|
||||
newFile=Nuovo file
|
||||
|
@ -102,7 +102,7 @@ deleteAlertHeader=Vuoi cancellare gli elementi ($COUNT$) selezionati?
|
|||
selectedElements=Elementi selezionati:
|
||||
mustNotBeEmpty=$VALUE$ non deve essere vuoto
|
||||
valueMustNotBeEmpty=Il valore non deve essere vuoto
|
||||
transferDescription=Rilasciare i file da trasferire
|
||||
transferDescription=Scaricare i file
|
||||
dragFiles=Trascinare i file nel browser
|
||||
dragLocalFiles=Trascina i file locali da qui
|
||||
null=$VALUE$ deve essere non nullo
|
||||
|
|
|
@ -77,7 +77,7 @@ lockCreationAlertTitle=パスフレーズを設定する
|
|||
lockCreationAlertHeader=新しいマスターパスフレーズを設定する
|
||||
finish=終了する
|
||||
error=エラーが発生した
|
||||
downloadStageDescription=ファイルをローカルマシンにダウンロードし、ネイティブのデスクトップ環境にドラッグ&ドロップできるようにする。
|
||||
downloadStageDescription=ダウンロードしたファイルをシステムのダウンロード・ディレクトリに移動し、開く。
|
||||
ok=OK
|
||||
search=検索
|
||||
newFile=新規ファイル
|
||||
|
@ -102,7 +102,7 @@ deleteAlertHeader=選択した ($COUNT$) 要素を削除するか?
|
|||
selectedElements=選択された要素:
|
||||
mustNotBeEmpty=$VALUE$ は空であってはならない
|
||||
valueMustNotBeEmpty=値は空であってはならない
|
||||
transferDescription=ファイルをドロップして転送する
|
||||
transferDescription=ファイルをドロップしてダウンロードする
|
||||
dragFiles=ブラウザ内でファイルをドラッグする
|
||||
dragLocalFiles=ここからローカルファイルをドラッグする
|
||||
null=$VALUE$ はnullであってはならない。
|
||||
|
|
|
@ -77,7 +77,7 @@ lockCreationAlertTitle=Passphrase instellen
|
|||
lockCreationAlertHeader=Stel je nieuwe hoofdwachtzin in
|
||||
finish=Beëindigen
|
||||
error=Er is een fout opgetreden
|
||||
downloadStageDescription=Downloadt bestanden naar je lokale computer, zodat je ze naar je eigen desktopomgeving kunt slepen.
|
||||
downloadStageDescription=Verplaatst gedownloade bestanden naar de downloadmap van je systeem en opent deze.
|
||||
ok=Ok
|
||||
search=Zoeken
|
||||
newFile=Nieuw bestand
|
||||
|
@ -102,7 +102,7 @@ deleteAlertHeader=Wil je de ($COUNT$) geselecteerde elementen verwijderen?
|
|||
selectedElements=Geselecteerde elementen:
|
||||
mustNotBeEmpty=$VALUE$ mag niet leeg zijn
|
||||
valueMustNotBeEmpty=Waarde mag niet leeg zijn
|
||||
transferDescription=Bestanden laten vallen om over te dragen
|
||||
transferDescription=Bestanden laten vallen om te downloaden
|
||||
dragFiles=Bestanden slepen binnen browser
|
||||
dragLocalFiles=Lokale bestanden van hier slepen
|
||||
null=$VALUE$ moet not null zijn
|
||||
|
|
|
@ -77,7 +77,7 @@ lockCreationAlertTitle=Define a frase-chave
|
|||
lockCreationAlertHeader=Define a tua nova frase-chave principal
|
||||
finish=Termina
|
||||
error=Ocorreu um erro
|
||||
downloadStageDescription=Descarrega ficheiros para a sua máquina local, para que possa arrastá-los e largá-los no seu ambiente de trabalho nativo.
|
||||
downloadStageDescription=Move os ficheiros transferidos para o diretório de transferências do sistema e abre-o.
|
||||
ok=Ok
|
||||
search=Procura
|
||||
newFile=Novo ficheiro
|
||||
|
|
|
@ -77,7 +77,7 @@ lockCreationAlertTitle=Установите парольную фразу
|
|||
lockCreationAlertHeader=Установите новую главную кодовую фразу
|
||||
finish=Закончи
|
||||
error=Произошла ошибка
|
||||
downloadStageDescription=Загрузи файлы на локальную машину, чтобы ты мог перетащить их в родное окружение рабочего стола.
|
||||
downloadStageDescription=Перемести скачанные файлы в системный каталог загрузок и открой его.
|
||||
ok=Ок
|
||||
search=Поиск
|
||||
newFile=Новый файл
|
||||
|
@ -102,7 +102,7 @@ deleteAlertHeader=Хочешь удалить ($COUNT$) выбранные эл
|
|||
selectedElements=Выбранные элементы:
|
||||
mustNotBeEmpty=$VALUE$ не должен быть пустым
|
||||
valueMustNotBeEmpty=Значение не должно быть пустым
|
||||
transferDescription=Сбрасывать файлы для передачи
|
||||
transferDescription=Сбрасывать файлы для загрузки
|
||||
dragFiles=Перетаскивание файлов в браузере
|
||||
dragLocalFiles=Перетащите локальные файлы отсюда
|
||||
null=$VALUE$ должен быть не нулевым
|
||||
|
|
|
@ -77,7 +77,7 @@ lockCreationAlertTitle=Parolayı ayarla
|
|||
lockCreationAlertHeader=Yeni ana parolanızı ayarlayın
|
||||
finish=Bitirmek
|
||||
error=Bir hata oluştu
|
||||
downloadStageDescription=Dosyaları yerel makinenize indirir, böylece bunları yerel masaüstü ortamınıza sürükleyip bırakabilirsiniz.
|
||||
downloadStageDescription=İndirilen dosyaları sisteminizin indirilenler dizinine taşır ve açar.
|
||||
ok=Tamam
|
||||
search=Arama
|
||||
newFile=Yeni dosya
|
||||
|
@ -102,7 +102,7 @@ deleteAlertHeader=($COUNT$) seçili öğeleri silmek istiyor musunuz?
|
|||
selectedElements=Seçilen unsurlar:
|
||||
mustNotBeEmpty=$VALUE$ boş olmamalıdır
|
||||
valueMustNotBeEmpty=Değer boş olmamalıdır
|
||||
transferDescription=Aktarılacak dosyaları bırakın
|
||||
transferDescription=İndirilecek dosyaları bırakın
|
||||
dragFiles=Dosyaları tarayıcı içinde sürükleyin
|
||||
dragLocalFiles=Yerel dosyaları buradan sürükleyin
|
||||
null=$VALUE$ null olmamalıdır
|
||||
|
|
|
@ -77,7 +77,7 @@ lockCreationAlertTitle=设置口令
|
|||
lockCreationAlertHeader=设置新的主密码
|
||||
finish=完成
|
||||
error=发生错误
|
||||
downloadStageDescription=将文件下载到本地计算机,以便拖放到本地桌面环境中。
|
||||
downloadStageDescription=将下载的文件移动到系统下载目录并打开。
|
||||
ok=好的
|
||||
search=搜索
|
||||
newFile=新文件
|
||||
|
@ -102,7 +102,7 @@ deleteAlertHeader=您想删除 ($COUNT$) 选定的元素吗?
|
|||
selectedElements=选定要素:
|
||||
mustNotBeEmpty=$VALUE$ 不得为空
|
||||
valueMustNotBeEmpty=值不得为空
|
||||
transferDescription=下拉传输文件
|
||||
transferDescription=下载文件
|
||||
dragFiles=在浏览器中拖动文件
|
||||
dragLocalFiles=从此处拖动本地文件
|
||||
null=$VALUE$ 必须为非空
|
||||
|
|
2
version
2
version
|
@ -1 +1 @@
|
|||
10.1-6
|
||||
10.1-7
|
||||
|
|
Loading…
Reference in a new issue