This commit is contained in:
crschnick 2024-07-09 14:03:56 +00:00
parent 9f232aa7d1
commit 4c64eb5ae5
22 changed files with 166 additions and 183 deletions

View file

@ -7,6 +7,7 @@ import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.fxcomps.impl.PrettyImageHelper; import io.xpipe.app.fxcomps.impl.PrettyImageHelper;
import io.xpipe.app.fxcomps.util.BindingsHelper;
import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.fxcomps.util.PlatformThread;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
@ -58,9 +59,15 @@ public class BrowserSelectionListComp extends SimpleComp {
return Comp.of(() -> { return Comp.of(() -> {
var image = PrettyImageHelper.ofFixedSizeSquare(entry.getIcon(), 24) var image = PrettyImageHelper.ofFixedSizeSquare(entry.getIcon(), 24)
.createRegion(); .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.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; return l;
}); });
}, },

View file

@ -1,8 +1,6 @@
package io.xpipe.app.browser; package io.xpipe.app.browser;
import io.xpipe.app.browser.file.BrowserFileTransferMode;
import io.xpipe.app.browser.fs.OpenFileSystemModel; 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.AppFont;
import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppI18n;
import io.xpipe.app.fxcomps.Comp; 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.impl.*;
import io.xpipe.app.fxcomps.util.DerivedObservableList; import io.xpipe.app.fxcomps.util.DerivedObservableList;
import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.fxcomps.util.PlatformThread;
import io.xpipe.app.util.ThreadHelper;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.css.PseudoClass; import javafx.css.PseudoClass;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.Dragboard; import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode; import javafx.scene.input.TransferMode;
import javafx.scene.layout.Region; import javafx.scene.layout.Region;
@ -38,8 +39,6 @@ public class BrowserTransferComp extends SimpleComp {
@Override @Override
protected Region createSimple() { protected Region createSimple() {
var syncItems = PlatformThread.sync(model.getItems()); 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")) var background = new LabelComp(AppI18n.observable("transferDescription"))
.apply(struc -> struc.get().setGraphic(new FontIcon("mdi2d-download-outline"))) .apply(struc -> struc.get().setGraphic(new FontIcon("mdi2d-download-outline")))
@ -53,46 +52,42 @@ public class BrowserTransferComp extends SimpleComp {
.getList(); .getList();
var list = new BrowserSelectionListComp( var list = new BrowserSelectionListComp(
binding, binding,
entry -> Bindings.createStringBinding( entry -> {
() -> { var sourceItem = syncItems.stream()
var sourceItem = syncItems.stream() .filter(item -> item.getBrowserEntry() == entry)
.filter(item -> item.getBrowserEntry() == entry) .findAny();
.findAny(); if (sourceItem.isEmpty()) {
if (sourceItem.isEmpty()) { return new SimpleStringProperty("?");
return "?"; }
} return Bindings.createStringBinding(() -> {
var name = entry.getModel() == null var p = sourceItem.get().getProgress().getValue();
|| sourceItem var progressSuffix = sourceItem.get().downloadFinished().get() ? "" : " " + (p.getTransferred() * 100 / p.getTotal()) + "%";
.get() return entry.getFileName() + progressSuffix;
.downloadFinished() }, sourceItem.get().getProgress());
.get() })
? "Local"
: entry.getModel()
.getFileSystemModel()
.getName();
return entry.getFileName() + " (" + name + ")";
},
syncAllDownloaded))
.grow(false, true); .grow(false, true);
var dragNotice = new LabelComp(syncAllDownloaded.flatMap( var dragNotice = new LabelComp(AppI18n.observable("dragLocalFiles"))
aBoolean -> aBoolean ? AppI18n.observable("dragLocalFiles") : AppI18n.observable("dragFiles")))
.apply(struc -> struc.get().setGraphic(new FontIcon("mdi2h-hand-left"))) .apply(struc -> struc.get().setGraphic(new FontIcon("mdi2h-hand-left")))
.apply(struc -> AppFont.medium(struc.get())) .apply(struc -> AppFont.medium(struc.get()))
.apply(struc -> struc.get().setWrapText(true)) .apply(struc -> struc.get().setWrapText(true))
.hide(Bindings.isEmpty(syncItems)); .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", () -> { var clearButton = new IconButtonComp("mdi2c-close", () -> {
model.clear(true); ThreadHelper.runAsync(() -> {
model.clear(true);
});
}) })
.hide(Bindings.isEmpty(syncItems)) .hide(Bindings.isEmpty(syncItems))
.tooltipKey("clearTransferDescription"); .tooltipKey("clearTransferDescription");
var downloadButton = new IconButtonComp("mdi2f-folder-move-outline", () -> {
ThreadHelper.runFailableAsync(() -> {
model.transferToDownloads();
});
})
.hide(Bindings.isEmpty(syncItems))
.tooltipKey("downloadStageDescription");
var bottom = var bottom =
new HorizontalComp(List.of(Comp.hspacer(), dragNotice, Comp.hspacer(), downloadButton, Comp.hspacer(4), clearButton)); new HorizontalComp(List.of(Comp.hspacer(), dragNotice, Comp.hspacer(), downloadButton, Comp.hspacer(4), clearButton));
var listBox = new VerticalComp(List.of(list, bottom)) var listBox = new VerticalComp(List.of(list, bottom))
@ -100,8 +95,7 @@ public class BrowserTransferComp extends SimpleComp {
.padding(new Insets(10, 10, 5, 10)) .padding(new Insets(10, 10, 5, 10))
.apply(struc -> struc.get().setMinHeight(200)) .apply(struc -> struc.get().setMinHeight(200))
.apply(struc -> struc.get().setMaxHeight(200)); .apply(struc -> struc.get().setMaxHeight(200));
var stack = LoadingOverlayComp.noProgress( var stack = new StackComp(List.of(backgroundStack, listBox))
new StackComp(List.of(backgroundStack, listBox))
.apply(DragOverPseudoClassAugment.create()) .apply(DragOverPseudoClassAugment.create())
.apply(struc -> { .apply(struc -> {
struc.get().setOnDragOver(event -> { struc.get().setOnDragOver(event -> {
@ -110,13 +104,6 @@ public class BrowserTransferComp extends SimpleComp {
event.acceptTransferModes(TransferMode.ANY); event.acceptTransferModes(TransferMode.ANY);
event.consume(); 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 -> { struc.get().setOnDragDropped(event -> {
// Accept drops from inside the app window // Accept drops from inside the app window
@ -138,29 +125,14 @@ public class BrowserTransferComp extends SimpleComp {
event.setDropCompleted(true); event.setDropCompleted(true);
event.consume(); 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 -> { struc.get().setOnDragDetected(event -> {
if (syncDownloaded.getValue()) {
return;
}
var selected = syncItems.stream() var selected = syncItems.stream()
.map(item -> item.getBrowserEntry()) .map(item -> item.getBrowserEntry())
.toList(); .toList();
Dragboard db = struc.get().startDragAndDrop(TransferMode.COPY); Dragboard db = struc.get().startDragAndDrop(TransferMode.COPY);
var cc = BrowserClipboard.startDrag(null, selected, BrowserFileTransferMode.NORMAL); var cc = new ClipboardContent();
if (cc == null) {
return;
}
var files = syncItems.stream() var files = syncItems.stream()
.filter(item -> item.downloadFinished().get()) .filter(item -> item.downloadFinished().get())
.map(item -> { .map(item -> {
@ -197,8 +169,7 @@ public class BrowserTransferComp extends SimpleComp {
model.clear(false); model.clear(false);
event.consume(); event.consume();
}); });
}), });
syncDownloaded);
stack.apply(struc -> { stack.apply(struc -> {
model.getBrowserSessionModel().getDraggingFiles().addListener((observable, oldValue, newValue) -> { model.getBrowserSessionModel().getDraggingFiles().addListener((observable, oldValue, newValue) -> {

View file

@ -7,45 +7,49 @@ import io.xpipe.app.browser.file.LocalFileSystem;
import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.browser.fs.OpenFileSystemModel;
import io.xpipe.app.browser.session.BrowserSessionModel; import io.xpipe.app.browser.session.BrowserSessionModel;
import io.xpipe.app.issue.ErrorEvent; 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.ShellTemp;
import io.xpipe.app.util.ThreadHelper;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.Property; import javafx.beans.property.Property;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableBooleanValue; import javafx.beans.value.ObservableBooleanValue;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import lombok.Value; import lombok.Value;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.nio.file.StandardCopyOption;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutorService; import java.util.Optional;
import java.util.concurrent.Executors;
@Value @Value
public class BrowserTransferModel { public class BrowserTransferModel {
private static final Path TEMP = ShellTemp.getLocalTempDataDirectory("download"); 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; BrowserSessionModel browserSessionModel;
ObservableList<Item> items = FXCollections.observableArrayList(); 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() { private void cleanDirectory() {
if (!Files.isDirectory(TEMP)) { if (!Files.isDirectory(TEMP)) {
@ -63,95 +67,77 @@ public class BrowserTransferModel {
} }
public void clear(boolean delete) { public void clear(boolean delete) {
items.clear(); synchronized (items) {
items.clear();
}
if (delete) { if (delete) {
executor.submit(() -> { cleanDirectory();
cleanDirectory();
});
} }
} }
public void drop(OpenFileSystemModel model, List<BrowserEntry> entries) { public void drop(OpenFileSystemModel model, List<BrowserEntry> entries) {
entries.forEach(entry -> { synchronized (items) {
var name = entry.getFileName(); entries.forEach(entry -> {
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);
var name = entry.getFileName(); var name = entry.getFileName();
if (items.stream().anyMatch(item -> item.getName().equals(name))) { if (items.stream().anyMatch(item -> item.getName().equals(name))) {
return; return;
} }
var item = new Item(null, name, entry, path); Path file = TEMP.resolve(name);
item.progress.setValue(BrowserTransferProgress.finished( var item = new Item(model, name, entry, file);
entry.getFileName(), entry.getRawFileEntry().getSize()));
items.add(item); items.add(item);
} });
} catch (Exception ex) {
ErrorEvent.fromThrowable(ex).handle();
}
if (empty) {
allDownloaded.set(true);
} }
} }
public void download() { public void downloadSingle(Item item) {
executor.submit(() -> { try {
try { FileUtils.forceMkdir(TEMP.toFile());
FileUtils.forceMkdir(TEMP.toFile()); } catch (IOException e) {
} catch (IOException e) { ErrorEvent.fromThrowable(e).handle();
ErrorEvent.fromThrowable(e).handle(); return;
}
if (item.downloadFinished().get()) {
return; return;
} }
for (Item item : new ArrayList<>(items)) { if (item.getOpenFileSystemModel() != null
if (item.downloadFinished().get()) { && item.getOpenFileSystemModel().isClosed()) {
continue; return;
} }
if (item.getOpenFileSystemModel() != null try {
&& item.getOpenFileSystemModel().isClosed()) { var op = new BrowserFileTransferOperation(
continue; LocalFileSystem.getLocalFileEntry(TEMP),
} List.of(item.getBrowserEntry().getRawFileEntry()),
BrowserFileTransferMode.COPY,
try { false,
try (var ignored = new BooleanScope(downloading).start()) { progress -> {
var op = new BrowserFileTransferOperation( item.getProgress().setValue(progress);
LocalFileSystem.getLocalFileEntry(TEMP), item.getOpenFileSystemModel().getProgress().setValue(progress);
List.of(item.getBrowserEntry().getRawFileEntry()), });
BrowserFileTransferMode.COPY, op.execute();
false, } catch (Throwable t) {
progress -> { ErrorEvent.fromThrowable(t).handle();
item.getProgress().setValue(progress); synchronized (items) {
item.getOpenFileSystemModel().getProgress().setValue(progress);
});
op.execute();
}
} catch (Throwable t) {
ErrorEvent.fromThrowable(t).handle();
items.remove(item); 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 @Value

View file

@ -41,6 +41,7 @@ public class BrowserTransferProgress {
var share = (double) transferred / total; var share = (double) transferred / total;
var rest = (1.0 - share) / share; var rest = (1.0 - share) / share;
var restMillis = (long) (elapsed.toMillis() * rest); 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);
} }
} }

View file

@ -229,6 +229,9 @@ public class BrowserFileTransferOperation {
OutputStream outputStream = null; OutputStream outputStream = null;
try { try {
var fileSize = sourceFile.getFileSystem().getFileSize(sourceFile.getPath()); 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 = new BufferedInputStream(sourceFile.getFileSystem().openInput(sourceFile.getPath()), 1024);
inputStream.mark(1024); inputStream.mark(1024);
var streamStart = new byte[1024]; var streamStart = new byte[1024];

View file

@ -9,7 +9,6 @@ import io.xpipe.app.fxcomps.SimpleCompStructure;
import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.fxcomps.util.PlatformThread;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.property.Property; import javafx.beans.property.Property;
import javafx.geometry.Pos;
import javafx.scene.Cursor; import javafx.scene.Cursor;
import javafx.scene.input.MouseButton; import javafx.scene.input.MouseButton;
import org.kordamp.ikonli.javafx.FontIcon; import org.kordamp.ikonli.javafx.FontIcon;
@ -36,14 +35,12 @@ public class FilterComp extends Comp<CompStructure<CustomTextField>> {
} }
}); });
var filter = new 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.setMaxHeight(2000);
filter.getStyleClass().add("filter-comp"); filter.getStyleClass().add("filter-comp");
filter.promptTextProperty().bind(AppI18n.observable("searchFilter")); filter.promptTextProperty().bind(AppI18n.observable("searchFilter"));
filter.setLeft(fi); filter.rightProperty().bind(Bindings.createObjectBinding(() -> {
filter.setRight(clear); return filter.isFocused() ? clear : fi;
}, filter.focusedProperty()));
filter.setAccessibleText("Filter"); filter.setAccessibleText("Filter");
filterText.subscribe(val -> { filterText.subscribe(val -> {

View file

@ -28,6 +28,23 @@ public class DesktopHelper {
return Path.of(System.getProperty("user.home") + "/Desktop"); 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 { public static void browsePathRemote(ShellControl sc, String path, FileKind kind) throws Exception {
var d = sc.getShellDialect(); var d = sc.getShellDialect();
switch (sc.getOsType()) { switch (sc.getOsType()) {

View file

@ -15,7 +15,7 @@
-fx-padding: 0 6 8 8; -fx-padding: 0 6 8 8;
} }
.transfer > * { .transfer > .download-background {
-fx-border-radius: 4; -fx-border-radius: 4;
-fx-background-radius: 4; -fx-background-radius: 4;
-fx-border-color: -color-border-default; -fx-border-color: -color-border-default;
@ -23,7 +23,7 @@
-fx-background-color: -color-bg-subtle; -fx-background-color: -color-bg-subtle;
} }
.transfer:highlighted > * { .transfer:highlighted > .download-background {
-fx-border-color: -color-accent-emphasis; -fx-border-color: -color-accent-emphasis;
-fx-background-color: derive(-color-bg-subtle, 5%); -fx-background-color: derive(-color-bg-subtle, 5%);
} }
@ -228,8 +228,8 @@
.browser .browser-content { .browser .browser-content {
-fx-padding: 6 0 0 0; -fx-padding: 6 0 0 0;
-fx-border-radius: 10 10 4 4; -fx-border-radius: 4;
-fx-background-radius: 10 10 4 4; -fx-background-radius: 4;
-fx-background-color: -color-bg-subtle, -color-bg-default; -fx-background-color: -color-bg-subtle, -color-bg-default;
-fx-background-insets: 0, 7 0 0 0; -fx-background-insets: 0, 7 0 0 0;
-fx-border-width: 1; -fx-border-width: 1;

View file

@ -1,4 +1,4 @@
.filter-comp { .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; -fx-background-color: transparent;
} }

View file

@ -80,7 +80,7 @@ lockCreationAlertHeader=Indstil din nye master-adgangssætning
#custom #custom
finish=Afslut finish=Afslut
error=Der opstod en fejl 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 ok=Ok
search=Søg efter search=Søg efter
newFile=Ny fil newFile=Ny fil
@ -108,7 +108,7 @@ deleteAlertHeader=Vil du slette de ($COUNT$) valgte elementer?
selectedElements=Udvalgte elementer: selectedElements=Udvalgte elementer:
mustNotBeEmpty=$VALUE$ må ikke være tom mustNotBeEmpty=$VALUE$ må ikke være tom
valueMustNotBeEmpty=Værdien 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 dragFiles=Træk filer i browseren
dragLocalFiles=Træk lokale filer herfra dragLocalFiles=Træk lokale filer herfra
null=$VALUE$ må ikke være nul null=$VALUE$ må ikke være nul

View file

@ -82,7 +82,7 @@ lockCreationAlertHeader=Lege deine neue Master-Passphrase fest
#custom #custom
finish=Fertigstellen finish=Fertigstellen
error=Ein Fehler ist aufgetreten 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 ok=Ok
search=Suche search=Suche
newFile=Neue Datei newFile=Neue Datei
@ -107,7 +107,7 @@ deleteAlertHeader=Willst du die ($COUNT$) ausgewählten Elemente löschen?
selectedElements=Ausgewählte Elemente: selectedElements=Ausgewählte Elemente:
mustNotBeEmpty=$VALUE$ darf nicht leer sein mustNotBeEmpty=$VALUE$ darf nicht leer sein
valueMustNotBeEmpty=Der Wert 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 dragFiles=Dateien im Browser ziehen
dragLocalFiles=Lokale Dateien von hier ziehen dragLocalFiles=Lokale Dateien von hier ziehen
null=$VALUE$ muss nicht null sein null=$VALUE$ muss nicht null sein

View file

@ -80,7 +80,8 @@ lockCreationAlertHeader=Set your new master passphrase
#context: verb, exit #context: verb, exit
finish=Finish finish=Finish
error=An error occurred 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 ok=Ok
search=Search search=Search
newFile=New file newFile=New file
@ -105,7 +106,7 @@ deleteAlertHeader=Do you want to delete the ($COUNT$) selected elements?
selectedElements=Selected elements: selectedElements=Selected elements:
mustNotBeEmpty=$VALUE$ must not be empty mustNotBeEmpty=$VALUE$ must not be empty
valueMustNotBeEmpty=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 dragFiles=Drag files within browser
dragLocalFiles=Drag local files from here dragLocalFiles=Drag local files from here
null=$VALUE$ must be not null null=$VALUE$ must be not null

View file

@ -77,7 +77,7 @@ lockCreationAlertTitle=Establecer frase de contraseña
lockCreationAlertHeader=Establece tu nueva frase de contraseña maestra lockCreationAlertHeader=Establece tu nueva frase de contraseña maestra
finish=Terminar finish=Terminar
error=Se ha producido un error 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 ok=Ok
search=Busca en search=Busca en
newFile=Nuevo archivo newFile=Nuevo archivo
@ -102,7 +102,7 @@ deleteAlertHeader=¿Quieres borrar los ($COUNT$) elementos seleccionados?
selectedElements=Elementos seleccionados: selectedElements=Elementos seleccionados:
mustNotBeEmpty=$VALUE$ no debe estar vacío mustNotBeEmpty=$VALUE$ no debe estar vacío
valueMustNotBeEmpty=El valor 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 dragFiles=Arrastrar archivos dentro del navegador
dragLocalFiles=Arrastra archivos locales desde aquí dragLocalFiles=Arrastra archivos locales desde aquí
null=$VALUE$ debe ser no nulo null=$VALUE$ debe ser no nulo

View file

@ -77,7 +77,7 @@ lockCreationAlertTitle=Définir une phrase de passe
lockCreationAlertHeader=Définis ta nouvelle phrase de passe principale lockCreationAlertHeader=Définis ta nouvelle phrase de passe principale
finish=Finir finish=Finir
error=Une erreur s'est produite 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 ok=Ok
search=Rechercher search=Rechercher
newFile=Nouveau fichier newFile=Nouveau fichier
@ -102,7 +102,7 @@ deleteAlertHeader=Veux-tu supprimer les ($COUNT$) éléments sélectionnés ?
selectedElements=Éléments sélectionnés : selectedElements=Éléments sélectionnés :
mustNotBeEmpty=$VALUE$ ne doit pas être vide mustNotBeEmpty=$VALUE$ ne doit pas être vide
valueMustNotBeEmpty=La valeur 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 dragFiles=Faire glisser des fichiers dans le navigateur
dragLocalFiles=Fais glisser des fichiers locaux à partir d'ici dragLocalFiles=Fais glisser des fichiers locaux à partir d'ici
null=$VALUE$ doit être non nul null=$VALUE$ doit être non nul

View file

@ -77,7 +77,7 @@ lockCreationAlertTitle=Imposta una passphrase
lockCreationAlertHeader=Imposta la tua nuova passphrase principale lockCreationAlertHeader=Imposta la tua nuova passphrase principale
finish=Terminare finish=Terminare
error=Si è verificato un errore 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 ok=Ok
search=Ricerca search=Ricerca
newFile=Nuovo file newFile=Nuovo file
@ -102,7 +102,7 @@ deleteAlertHeader=Vuoi cancellare gli elementi ($COUNT$) selezionati?
selectedElements=Elementi selezionati: selectedElements=Elementi selezionati:
mustNotBeEmpty=$VALUE$ non deve essere vuoto mustNotBeEmpty=$VALUE$ non deve essere vuoto
valueMustNotBeEmpty=Il valore 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 dragFiles=Trascinare i file nel browser
dragLocalFiles=Trascina i file locali da qui dragLocalFiles=Trascina i file locali da qui
null=$VALUE$ deve essere non nullo null=$VALUE$ deve essere non nullo

View file

@ -77,7 +77,7 @@ lockCreationAlertTitle=パスフレーズを設定する
lockCreationAlertHeader=新しいマスターパスフレーズを設定する lockCreationAlertHeader=新しいマスターパスフレーズを設定する
finish=終了する finish=終了する
error=エラーが発生した error=エラーが発生した
downloadStageDescription=ファイルをローカルマシンにダウンロードし、ネイティブのデスクトップ環境にドラッグ&ドロップできるようにする downloadStageDescription=ダウンロードしたファイルをシステムのダウンロード・ディレクトリに移動し、開く
ok=OK ok=OK
search=検索 search=検索
newFile=新規ファイル newFile=新規ファイル
@ -102,7 +102,7 @@ deleteAlertHeader=選択した ($COUNT$) 要素を削除するか?
selectedElements=選択された要素: selectedElements=選択された要素:
mustNotBeEmpty=$VALUE$ は空であってはならない mustNotBeEmpty=$VALUE$ は空であってはならない
valueMustNotBeEmpty=値は空であってはならない valueMustNotBeEmpty=値は空であってはならない
transferDescription=ファイルをドロップして転送する transferDescription=ファイルをドロップしてダウンロードする
dragFiles=ブラウザ内でファイルをドラッグする dragFiles=ブラウザ内でファイルをドラッグする
dragLocalFiles=ここからローカルファイルをドラッグする dragLocalFiles=ここからローカルファイルをドラッグする
null=$VALUE$ はnullであってはならない。 null=$VALUE$ はnullであってはならない。

View file

@ -77,7 +77,7 @@ lockCreationAlertTitle=Passphrase instellen
lockCreationAlertHeader=Stel je nieuwe hoofdwachtzin in lockCreationAlertHeader=Stel je nieuwe hoofdwachtzin in
finish=Beëindigen finish=Beëindigen
error=Er is een fout opgetreden 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 ok=Ok
search=Zoeken search=Zoeken
newFile=Nieuw bestand newFile=Nieuw bestand
@ -102,7 +102,7 @@ deleteAlertHeader=Wil je de ($COUNT$) geselecteerde elementen verwijderen?
selectedElements=Geselecteerde elementen: selectedElements=Geselecteerde elementen:
mustNotBeEmpty=$VALUE$ mag niet leeg zijn mustNotBeEmpty=$VALUE$ mag niet leeg zijn
valueMustNotBeEmpty=Waarde 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 dragFiles=Bestanden slepen binnen browser
dragLocalFiles=Lokale bestanden van hier slepen dragLocalFiles=Lokale bestanden van hier slepen
null=$VALUE$ moet not null zijn null=$VALUE$ moet not null zijn

View file

@ -77,7 +77,7 @@ lockCreationAlertTitle=Define a frase-chave
lockCreationAlertHeader=Define a tua nova frase-chave principal lockCreationAlertHeader=Define a tua nova frase-chave principal
finish=Termina finish=Termina
error=Ocorreu um erro 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 ok=Ok
search=Procura search=Procura
newFile=Novo ficheiro newFile=Novo ficheiro

View file

@ -77,7 +77,7 @@ lockCreationAlertTitle=Установите парольную фразу
lockCreationAlertHeader=Установите новую главную кодовую фразу lockCreationAlertHeader=Установите новую главную кодовую фразу
finish=Закончи finish=Закончи
error=Произошла ошибка error=Произошла ошибка
downloadStageDescription=Загрузи файлы на локальную машину, чтобы ты мог перетащить их в родное окружение рабочего стола. downloadStageDescription=Перемести скачанные файлы в системный каталог загрузок и открой его.
ok=Ок ok=Ок
search=Поиск search=Поиск
newFile=Новый файл newFile=Новый файл
@ -102,7 +102,7 @@ deleteAlertHeader=Хочешь удалить ($COUNT$) выбранные эл
selectedElements=Выбранные элементы: selectedElements=Выбранные элементы:
mustNotBeEmpty=$VALUE$ не должен быть пустым mustNotBeEmpty=$VALUE$ не должен быть пустым
valueMustNotBeEmpty=Значение не должно быть пустым valueMustNotBeEmpty=Значение не должно быть пустым
transferDescription=Сбрасывать файлы для передачи transferDescription=Сбрасывать файлы для загрузки
dragFiles=Перетаскивание файлов в браузере dragFiles=Перетаскивание файлов в браузере
dragLocalFiles=Перетащите локальные файлы отсюда dragLocalFiles=Перетащите локальные файлы отсюда
null=$VALUE$ должен быть не нулевым null=$VALUE$ должен быть не нулевым

View file

@ -77,7 +77,7 @@ lockCreationAlertTitle=Parolayı ayarla
lockCreationAlertHeader=Yeni ana parolanızı ayarlayın lockCreationAlertHeader=Yeni ana parolanızı ayarlayın
finish=Bitirmek finish=Bitirmek
error=Bir hata oluştu 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 ok=Tamam
search=Arama search=Arama
newFile=Yeni dosya newFile=Yeni dosya
@ -102,7 +102,7 @@ deleteAlertHeader=($COUNT$) seçili öğeleri silmek istiyor musunuz?
selectedElements=Seçilen unsurlar: selectedElements=Seçilen unsurlar:
mustNotBeEmpty=$VALUE$ boş olmamalıdır mustNotBeEmpty=$VALUE$ boş olmamalıdır
valueMustNotBeEmpty=Değer 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 dragFiles=Dosyaları tarayıcı içinde sürükleyin
dragLocalFiles=Yerel dosyaları buradan sürükleyin dragLocalFiles=Yerel dosyaları buradan sürükleyin
null=$VALUE$ null olmamalıdır null=$VALUE$ null olmamalıdır

View file

@ -77,7 +77,7 @@ lockCreationAlertTitle=设置口令
lockCreationAlertHeader=设置新的主密码 lockCreationAlertHeader=设置新的主密码
finish=完成 finish=完成
error=发生错误 error=发生错误
downloadStageDescription=文件下载到本地计算机,以便拖放到本地桌面环境中 downloadStageDescription=下载的文件移动到系统下载目录并打开
ok=好的 ok=好的
search=搜索 search=搜索
newFile=新文件 newFile=新文件
@ -102,7 +102,7 @@ deleteAlertHeader=您想删除 ($COUNT$) 选定的元素吗?
selectedElements=选定要素: selectedElements=选定要素:
mustNotBeEmpty=$VALUE$ 不得为空 mustNotBeEmpty=$VALUE$ 不得为空
valueMustNotBeEmpty=值不得为空 valueMustNotBeEmpty=值不得为空
transferDescription=拉传输文件 transferDescription=文件
dragFiles=在浏览器中拖动文件 dragFiles=在浏览器中拖动文件
dragLocalFiles=从此处拖动本地文件 dragLocalFiles=从此处拖动本地文件
null=$VALUE$ 必须为非空 null=$VALUE$ 必须为非空

View file

@ -1 +1 @@
10.1-6 10.1-7