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.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;
});
},

View file

@ -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(
() -> {
entry -> {
var sourceItem = syncItems.stream()
.filter(item -> item.getBrowserEntry() == entry)
.findAny();
if (sourceItem.isEmpty()) {
return "?";
return new SimpleStringProperty("?");
}
var name = entry.getModel() == null
|| sourceItem
.get()
.downloadFinished()
.get()
? "Local"
: entry.getModel()
.getFileSystemModel()
.getName();
return entry.getFileName() + " (" + name + ")";
},
syncAllDownloaded))
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", () -> {
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) -> {

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.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,15 +67,16 @@ public class BrowserTransferModel {
}
public void clear(boolean delete) {
synchronized (items) {
items.clear();
}
if (delete) {
executor.submit(() -> {
cleanDirectory();
});
}
}
public void drop(OpenFileSystemModel model, List<BrowserEntry> entries) {
synchronized (items) {
entries.forEach(entry -> {
var name = entry.getFileName();
if (items.stream().anyMatch(item -> item.getName().equals(name))) {
@ -81,40 +86,11 @@ public class BrowserTransferModel {
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();
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()));
items.add(item);
}
} catch (Exception ex) {
ErrorEvent.fromThrowable(ex).handle();
}
if (empty) {
allDownloaded.set(true);
}
}
public void download() {
executor.submit(() -> {
public void downloadSingle(Item item) {
try {
FileUtils.forceMkdir(TEMP.toFile());
} catch (IOException e) {
@ -122,18 +98,16 @@ public class BrowserTransferModel {
return;
}
for (Item item : new ArrayList<>(items)) {
if (item.downloadFinished().get()) {
continue;
return;
}
if (item.getOpenFileSystemModel() != null
&& item.getOpenFileSystemModel().isClosed()) {
continue;
return;
}
try {
try (var ignored = new BooleanScope(downloading).start()) {
var op = new BrowserFileTransferOperation(
LocalFileSystem.getLocalFileEntry(TEMP),
List.of(item.getBrowserEntry().getRawFileEntry()),
@ -144,14 +118,26 @@ public class BrowserTransferModel {
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

View file

@ -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);
}
}

View file

@ -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];

View file

@ -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 -> {

View file

@ -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()) {

View file

@ -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;

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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であってはならない。

View file

@ -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

View file

@ -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

View file

@ -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$ должен быть не нулевым

View file

@ -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

View file

@ -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$ 必须为非空

View file

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