Merge branch 'release/1.5.12'

This commit is contained in:
Armin Schrenk
2021-02-04 10:49:08 +01:00
68 changed files with 923 additions and 264 deletions

View File

@@ -5,28 +5,12 @@ labels: type:bug
---
<!--
**************************************
* *
* ⚠️⚠️⚠️ READ CAREFULLY ⚠️⚠️⚠️ *
* *
**************************************
Do you want to ask a QUESTION? Are you looking for SUPPORT?
We're happy to help you via our support channels! Please read: https://github.com/cryptomator/cryptomator/blob/develop/SUPPORT.md
By filing an issue, you are expected to comply with our code of conduct: https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md
Of course, we also expect you to search for existing similar issues first! ;) https://github.com/cryptomator/cryptomator/issues?q=
Please make sure to:
- Comply with our code of conduct: https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md
- Search for existing similar issues first: https://github.com/cryptomator/cryptomator/issues?q=
⚠️ IMPORTANT: If you don't stick to this template, the issue will get closed.
*****************************************************************************
* *
* To proof that you read this, please remove the X from the line below: *
* *
*****************************************************************************
-->
<!-- oooXooo -->
### Description
@@ -34,7 +18,7 @@ Of course, we also expect you to search for existing similar issues first! ;) ht
### System Setup
* Operating system and version: [Windows/macOS/Linux + Version]
* Operating system and version: [Windows/macOS/Linux + Version ( + Desktop Environment, if Linux)]
* Cryptomator version: [Shown in the settings]
* Volume type: [Dokany/FUSE/WebDAV, shown in the settings]
@@ -61,7 +45,6 @@ Of course, we also expect you to search for existing similar issues first! ;) ht
[Any additional information, log files, screenshots, configuration, or data that might be necessary to reproduce the issue.]
<!--
If you want to add the log file or screenshots, please add them as attachments. If your log file seems empty and doesn't show any errors, you may enable the debug mode first. Here is how to do that: https://community.cryptomator.org/t/how-do-i-enable-debug-mode/36
Then reproduce the problem to ensure all important information is contained in there. You may use test data or redact sensitive information from the log file.
@@ -70,5 +53,4 @@ Log file location:
- Windows: %appdata%/Cryptomator
- macOS: ~/Library/Logs/Cryptomator
- Linux: ~/.local/share/Cryptomator/logs
-->

View File

@@ -1,8 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Cryptomator Community
- name: Help & Support
url: https://community.cryptomator.org/
about: Please ask and answer questions here
- name: Documentation
about: You will find answers in our community forum
- name: User Manual
url: https://docs.cryptomator.org/
about: Get instructions on how to use Cryptomator
about: Read the Cryptomator documentation here

View File

@@ -5,14 +5,9 @@ labels: type:feature-request
---
<!--
Do you want to ask a QUESTION? Are you looking for SUPPORT?
We're happy to help you via our support channels! Please read: https://github.com/cryptomator/cryptomator/blob/develop/SUPPORT.md
By filing a feature request, you are expected to comply with our code of conduct: https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md
Of course, we also expect you to search for existing similar feature requests first! ;)
Please make sure to:
- Comply with our code of conduct: https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md
- Search for existing similar issues first: https://github.com/cryptomator/cryptomator/issues?q=
-->
### Summary
@@ -29,4 +24,4 @@ Of course, we also expect you to search for existing similar feature requests fi
### Additional Context
[Add any other context or screenshots about the feature request here.]
[Add any other context or screenshots about the feature request here.]

View File

View File

View File

@@ -6,20 +6,32 @@ on:
jobs:
closeTemplateViolation:
name: Close bug reports that violate the issue template
name: Validate bug report against issue template
runs-on: ubuntu-latest
if: contains(github.event.issue.labels.*.name, 'type:bug')
steps:
- if: |
contains(github.event.issue.labels.*.name, 'type:bug')
&& (
!contains(github.event.issue.body, '<!-- oooooo -->')
|| !contains(github.event.issue.body, '### Description')
)
name: Close Issue
- name: Check "Description"
if: |
!contains(github.event.issue.body, env.MUST_CONTAIN)
|| contains(toJson(github.event.issue.body), env.MUST_NOT_CONTAIN)
run: exit 1
env:
MUST_CONTAIN: '### Description'
MUST_NOT_CONTAIN: '### Description\r\n\r\n[Summarize your problem.]\r\n\r\n### System Setup'
- name: Check "Steps to Reproduce"
if: |
!contains(github.event.issue.body, env.MUST_CONTAIN)
|| contains(toJson(github.event.issue.body), env.MUST_NOT_CONTAIN)
run: exit 1
env:
MUST_CONTAIN: '### Steps to Reproduce'
MUST_NOT_CONTAIN: '### Steps to Reproduce\r\n\r\n1. [First step]\r\n2. [Second step]\r\n3. [and so on…]\r\n\r\n#### Expected Behavior'
- name: Close issue if one of the checks failed
if: ${{ failure() }}
uses: peter-evans/close-issue@v1
with:
comment: |
This bug report did ignore our issue template. 😞
Auto-closing this issue, since it is most likely not useful.
_This decision was made by a bot. If you think the bot is wrong, let us know and we'll reopen this issue._
_This decision was made by a bot. If you think the bot is wrong, let us know and we'll reopen this issue._

View File

@@ -2,7 +2,7 @@
<configuration default="false" name="Cryptomator Linux" type="Application" factoryName="Application">
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
<module name="launcher" />
<option name="VM_PARAMETERS" value="-Djdk.gtk.version=2 -Duser.language=en -Dcryptomator.settingsPath=&quot;~/.config/Cryptomator/settings.json&quot; -Dcryptomator.ipcPortPath=&quot;~/.config/Cryptomator/ipcPort.bin&quot; -Dcryptomator.logDir=&quot;~/.local/share/Cryptomator/logs&quot; -Dcryptomator.mountPointsDir=&quot;~/.local/share/Cryptomator/mnt&quot; -Xss20m -Xmx512m" />
<option name="VM_PARAMETERS" value="-Djdk.gtk.version=2 -Duser.language=en -Dcryptomator.settingsPath=&quot;~/.config/Cryptomator/settings.json&quot; -Dcryptomator.ipcPortPath=&quot;~/.config/Cryptomator/ipcPort.bin&quot; -Dcryptomator.logDir=&quot;~/.local/share/Cryptomator/logs&quot; -Dcryptomator.mountPointsDir=&quot;~/.local/share/Cryptomator/mnt&quot; -Dcryptomator.showTrayIcon=true -Xss20m -Xmx512m" />
<method v="2">
<option name="Make" enabled="true" />
</method>

View File

@@ -2,7 +2,7 @@
<configuration default="false" name="Cryptomator Linux Dev" type="Application" factoryName="Application">
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
<module name="launcher" />
<option name="VM_PARAMETERS" value="-Djdk.gtk.version=2 -Duser.language=en -Dcryptomator.settingsPath=&quot;~/.config/Cryptomator-Dev/settings.json&quot; -Dcryptomator.ipcPortPath=&quot;~/.config/Cryptomator-Dev/ipcPort.bin&quot; -Dcryptomator.logDir=&quot;~/.local/share/Cryptomator-Dev/logs&quot; -Dcryptomator.mountPointsDir=&quot;~/.local/share/Cryptomator-Dev/mnt&quot; -Dfuse.experimental=&quot;true&quot; -Xss20m -Xmx512m" />
<option name="VM_PARAMETERS" value="-Djdk.gtk.version=2 -Duser.language=en -Dcryptomator.settingsPath=&quot;~/.config/Cryptomator-Dev/settings.json&quot; -Dcryptomator.ipcPortPath=&quot;~/.config/Cryptomator-Dev/ipcPort.bin&quot; -Dcryptomator.logDir=&quot;~/.local/share/Cryptomator-Dev/logs&quot; -Dcryptomator.mountPointsDir=&quot;~/.local/share/Cryptomator-Dev/mnt&quot; -Dcryptomator.showTrayIcon=true -Dfuse.experimental=&quot;true&quot; -Xss20m -Xmx512m" />
<method v="2">
<option name="Make" enabled="true" />
</method>

View File

@@ -2,7 +2,7 @@
<configuration default="false" name="Cryptomator Windows" type="Application" factoryName="Application">
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
<module name="launcher" />
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath=&quot;~/AppData/Roaming/Cryptomator/settings.json&quot; -Dcryptomator.ipcPortPath=&quot;~/AppData/Roaming/Cryptomator/ipcPort.bin&quot; -Dcryptomator.logDir=&quot;~/AppData/Roaming/Cryptomator&quot; -Dcryptomator.keychainPath=&quot;~/AppData/Roaming/Cryptomator/keychain.json&quot; -Dcryptomator.mountPointsDir=&quot;~/Cryptomator&quot; -Xss2m -Xmx512m" />
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath=&quot;~/AppData/Roaming/Cryptomator/settings.json&quot; -Dcryptomator.ipcPortPath=&quot;~/AppData/Roaming/Cryptomator/ipcPort.bin&quot; -Dcryptomator.logDir=&quot;~/AppData/Roaming/Cryptomator&quot; -Dcryptomator.keychainPath=&quot;~/AppData/Roaming/Cryptomator/keychain.json&quot; -Dcryptomator.mountPointsDir=&quot;~/Cryptomator&quot; -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m" />
<method v="2">
<option name="Make" enabled="true" />
</method>

View File

@@ -2,7 +2,7 @@
<configuration default="false" name="Cryptomator Windows Dev" type="Application" factoryName="Application">
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
<module name="launcher" />
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath=&quot;~/AppData/Roaming/Cryptomator-Dev/settings.json&quot; -Dcryptomator.ipcPortPath=&quot;~/AppData/Roaming/Cryptomator-Dev/ipcPort.bin&quot; -Dcryptomator.logDir=&quot;~/AppData/Roaming/Cryptomator-Dev&quot; -Dcryptomator.keychainPath=&quot;~/AppData/Roaming/Cryptomator-Dev/keychain.json&quot; -Dcryptomator.mountPointsDir=&quot;~/Cryptomator-Dev&quot; -Dfuse.experimental=&quot;true&quot; -Xss2m -Xmx512m" />
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath=&quot;~/AppData/Roaming/Cryptomator-Dev/settings.json&quot; -Dcryptomator.ipcPortPath=&quot;~/AppData/Roaming/Cryptomator-Dev/ipcPort.bin&quot; -Dcryptomator.logDir=&quot;~/AppData/Roaming/Cryptomator-Dev&quot; -Dcryptomator.keychainPath=&quot;~/AppData/Roaming/Cryptomator-Dev/keychain.json&quot; -Dcryptomator.mountPointsDir=&quot;~/Cryptomator-Dev&quot; -Dfuse.experimental=&quot;true&quot; -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m" />
<method v="2">
<option name="Make" enabled="true" />
</method>

View File

@@ -5,7 +5,7 @@
</envs>
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
<module name="launcher" />
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath=&quot;~/Library/Application Support/Cryptomator/settings.json&quot; -Dcryptomator.ipcPortPath=&quot;~/Library/Application Support/Cryptomator/ipcPort.bin&quot; -Dcryptomator.logDir=&quot;~/Library/Logs/Cryptomator&quot; -Xss2m -Xmx512m -ea" />
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath=&quot;~/Library/Application Support/Cryptomator/settings.json&quot; -Dcryptomator.ipcPortPath=&quot;~/Library/Application Support/Cryptomator/ipcPort.bin&quot; -Dcryptomator.logDir=&quot;~/Library/Logs/Cryptomator&quot; -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m -ea" />
<method v="2">
<option name="Make" enabled="true" />
</method>

View File

@@ -5,7 +5,7 @@
</envs>
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
<module name="launcher" />
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath=&quot;~/Library/Application Support/Cryptomator-Dev/settings.json&quot; -Dcryptomator.ipcPortPath=&quot;~/Library/Application Support/Cryptomator-Dev/ipcPort.bin&quot; -Dcryptomator.logDir=&quot;~/Library/Logs/Cryptomator-Dev&quot; -Xss2m -Xmx512m -ea" />
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath=&quot;~/Library/Application Support/Cryptomator-Dev/settings.json&quot; -Dcryptomator.ipcPortPath=&quot;~/Library/Application Support/Cryptomator-Dev/ipcPort.bin&quot; -Dcryptomator.logDir=&quot;~/Library/Logs/Cryptomator-Dev&quot; -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m -ea" />
<method v="2">
<option name="Make" enabled="true" />
</method>

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>org.cryptomator</groupId>
<artifactId>main</artifactId>
<version>1.5.11</version>
<version>1.6.0-SNAPSHOT</version>
</parent>
<artifactId>buildkit</artifactId>
<packaging>pom</packaging>

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>org.cryptomator</groupId>
<artifactId>main</artifactId>
<version>1.5.11</version>
<version>1.6.0-SNAPSHOT</version>
</parent>
<artifactId>commons</artifactId>
<name>Cryptomator Commons</name>

View File

@@ -21,14 +21,13 @@ import java.util.stream.StreamSupport;
public class Environment {
private static final Logger LOG = LoggerFactory.getLogger(Environment.class);
private static final String USER_HOME = System.getProperty("user.home");
private static final Path RELATIVE_HOME_DIR = Paths.get("~");
private static final Path ABSOLUTE_HOME_DIR = Paths.get(USER_HOME);
private static final char PATH_LIST_SEP = ':';
private static final int DEFAULT_MIN_PW_LENGTH = 8;
@Inject
public Environment() {
LOG.debug("user.home: {}", System.getProperty("user.home"));
LOG.debug("java.library.path: {}", System.getProperty("java.library.path"));
LOG.debug("user.language: {}", System.getProperty("user.language"));
LOG.debug("user.region: {}", System.getProperty("user.region"));
@@ -40,6 +39,7 @@ public class Environment {
LOG.debug("cryptomator.mountPointsDir: {}", System.getProperty("cryptomator.mountPointsDir"));
LOG.debug("cryptomator.minPwLength: {}", System.getProperty("cryptomator.minPwLength"));
LOG.debug("cryptomator.buildNumber: {}", System.getProperty("cryptomator.buildNumber"));
LOG.debug("cryptomator.showTrayIcon: {}", System.getProperty("cryptomator.showTrayIcon"));
LOG.debug("fuse.experimental: {}", Boolean.getBoolean("fuse.experimental"));
}
@@ -75,6 +75,11 @@ public class Environment {
return getInt("cryptomator.minPwLength", DEFAULT_MIN_PW_LENGTH);
}
public boolean showTrayIcon() {
return Boolean.getBoolean("cryptomator.showTrayIcon");
}
@Deprecated // TODO: remove as soon as custom mount path works properly on Win+Fuse
public boolean useExperimentalFuse() {
return Boolean.getBoolean("fuse.experimental");
}
@@ -92,8 +97,13 @@ public class Environment {
String value = System.getProperty(propertyName);
return Optional.ofNullable(value).map(Paths::get);
}
// visible for testing
// visible for testing
Path getHomeDir() {
return getPath("user.home").orElseThrow();
}
// visible for testing
Stream<Path> getPaths(String propertyName) {
Stream<String> rawSettingsPaths = getRawList(propertyName, PATH_LIST_SEP);
return rawSettingsPaths.filter(Predicate.not(Strings::isNullOrEmpty)).map(Paths::get).map(this::replaceHomeDir);
@@ -101,7 +111,7 @@ public class Environment {
private Path replaceHomeDir(Path path) {
if (path.startsWith(RELATIVE_HOME_DIR)) {
return ABSOLUTE_HOME_DIR.resolve(RELATIVE_HOME_DIR.relativize(path));
return getHomeDir().resolve(RELATIVE_HOME_DIR.relativize(path));
} else {
return path;
}

View File

@@ -9,6 +9,7 @@
package org.cryptomator.common.settings;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.common.Environment;
import javafx.beans.Observable;
import javafx.beans.property.BooleanProperty;
@@ -39,7 +40,8 @@ public class Settings {
public static final UiTheme DEFAULT_THEME = UiTheme.LIGHT;
public static final KeychainBackend DEFAULT_KEYCHAIN_BACKEND = SystemUtils.IS_OS_WINDOWS ? KeychainBackend.WIN_SYSTEM_KEYCHAIN : SystemUtils.IS_OS_MAC ? KeychainBackend.MAC_SYSTEM_KEYCHAIN : KeychainBackend.GNOME;
public static final NodeOrientation DEFAULT_USER_INTERFACE_ORIENTATION = NodeOrientation.LEFT_TO_RIGHT;
private static final String DEFAULT_LICENSE_KEY = "";
public static final String DEFAULT_LICENSE_KEY = "";
public static final boolean DEFAULT_SHOW_MINIMIZE_BUTTON = false;
private final ObservableList<VaultSettings> directories = FXCollections.observableArrayList(VaultSettings::observables);
private final BooleanProperty askedForUpdateCheck = new SimpleBooleanProperty(DEFAULT_ASKED_FOR_UPDATE_CHECK);
@@ -54,13 +56,17 @@ public class Settings {
private final ObjectProperty<KeychainBackend> keychainBackend = new SimpleObjectProperty<>(DEFAULT_KEYCHAIN_BACKEND);
private final ObjectProperty<NodeOrientation> userInterfaceOrientation = new SimpleObjectProperty<>(DEFAULT_USER_INTERFACE_ORIENTATION);
private final StringProperty licenseKey = new SimpleStringProperty(DEFAULT_LICENSE_KEY);
private final BooleanProperty showMinimizeButton = new SimpleBooleanProperty(DEFAULT_SHOW_MINIMIZE_BUTTON);
private final BooleanProperty showTrayIcon;
private Consumer<Settings> saveCmd;
/**
* Package-private constructor; use {@link SettingsProvider}.
*/
Settings() {
Settings(Environment env) {
this.showTrayIcon = new SimpleBooleanProperty(env.showTrayIcon());
directories.addListener(this::somethingChanged);
askedForUpdateCheck.addListener(this::somethingChanged);
checkForUpdates.addListener(this::somethingChanged);
@@ -74,6 +80,8 @@ public class Settings {
keychainBackend.addListener(this::somethingChanged);
userInterfaceOrientation.addListener(this::somethingChanged);
licenseKey.addListener(this::somethingChanged);
showMinimizeButton.addListener(this::somethingChanged);
showTrayIcon.addListener(this::somethingChanged);
}
void setSaveCmd(Consumer<Settings> saveCmd) {
@@ -141,4 +149,12 @@ public class Settings {
public StringProperty licenseKey() {
return licenseKey;
}
public BooleanProperty showMinimizeButton() {
return showMinimizeButton;
}
public BooleanProperty showTrayIcon() {
return showTrayIcon;
}
}

View File

@@ -9,19 +9,29 @@ import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import org.cryptomator.common.Environment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Singleton;
import javafx.geometry.NodeOrientation;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@Singleton
public class SettingsJsonAdapter extends TypeAdapter<Settings> {
private static final Logger LOG = LoggerFactory.getLogger(SettingsJsonAdapter.class);
private final VaultSettingsJsonAdapter vaultSettingsJsonAdapter = new VaultSettingsJsonAdapter();
private final Environment env;
@Inject
public SettingsJsonAdapter(Environment env) {
this.env = env;
}
@Override
public void write(JsonWriter out, Settings value) throws IOException {
@@ -40,6 +50,8 @@ public class SettingsJsonAdapter extends TypeAdapter<Settings> {
out.name("uiOrientation").value(value.userInterfaceOrientation().get().name());
out.name("keychainBackend").value(value.keychainBackend().get().name());
out.name("licenseKey").value(value.licenseKey().get());
out.name("showMinimizeButton").value(value.showMinimizeButton().get());
out.name("showTrayIcon").value(value.showTrayIcon().get());
out.endObject();
}
@@ -53,7 +65,7 @@ public class SettingsJsonAdapter extends TypeAdapter<Settings> {
@Override
public Settings read(JsonReader in) throws IOException {
Settings settings = new Settings();
Settings settings = new Settings(env);
in.beginObject();
while (in.hasNext()) {
@@ -72,6 +84,8 @@ public class SettingsJsonAdapter extends TypeAdapter<Settings> {
case "uiOrientation" -> settings.userInterfaceOrientation().set(parseUiOrientation(in.nextString()));
case "keychainBackend" -> settings.keychainBackend().set(parseKeychainBackend(in.nextString()));
case "licenseKey" -> settings.licenseKey().set(in.nextString());
case "showMinimizeButton" -> settings.showMinimizeButton().set(in.nextBoolean());
case "showTrayIcon" -> settings.showTrayIcon().set(in.nextBoolean());
default -> {
LOG.warn("Unsupported vault setting found in JSON: " + name);
in.skipValue();
@@ -137,5 +151,4 @@ public class SettingsJsonAdapter extends TypeAdapter<Settings> {
in.endArray();
return result;
}
}

View File

@@ -49,13 +49,14 @@ public class SettingsProvider implements Supplier<Settings> {
private final AtomicReference<ScheduledFuture<?>> scheduledSaveCmd = new AtomicReference<>();
private final Supplier<Settings> settings = Suppliers.memoize(this::load);
private final SettingsJsonAdapter settingsJsonAdapter = new SettingsJsonAdapter();
private final SettingsJsonAdapter settingsJsonAdapter;
private final Environment env;
private final ScheduledExecutorService scheduler;
private final Gson gson;
@Inject
public SettingsProvider(Environment env, ScheduledExecutorService scheduler) {
public SettingsProvider(SettingsJsonAdapter settingsJsonAdapter, Environment env, ScheduledExecutorService scheduler) {
this.settingsJsonAdapter = settingsJsonAdapter;
this.env = env;
this.scheduler = scheduler;
this.gson = new GsonBuilder() //
@@ -70,7 +71,7 @@ public class SettingsProvider implements Supplier<Settings> {
}
private Settings load() {
Settings settings = env.getSettingsPath().flatMap(this::tryLoad).findFirst().orElse(new Settings());
Settings settings = env.getSettingsPath().flatMap(this::tryLoad).findFirst().orElse(new Settings(env));
settings.setSaveCmd(this::scheduleSave);
return settings;
}
@@ -90,7 +91,7 @@ public class SettingsProvider implements Supplier<Settings> {
}
} catch (NoSuchFileException e) {
return Stream.empty();
} catch (IOException e) {
} catch (IOException | JsonParseException e) {
LOG.warn("Exception while loading settings from " + path, e);
return Stream.empty();
}

View File

@@ -52,10 +52,11 @@ public class DokanyVolume extends AbstractVolume {
}
@Override
public void reveal() throws VolumeException {
boolean success = mount.reveal();
if (!success) {
throw new VolumeException("Reveal failed.");
public void reveal(Revealer revealer) throws VolumeException {
try {
mount.reveal(revealer::reveal);
} catch (Exception e) {
throw new VolumeException(e);
}
}
@@ -79,6 +80,7 @@ public class DokanyVolume extends AbstractVolume {
public boolean supportsForcedUnmount() {
return true;
}
@Override
public boolean isSupported() {
return DokanyVolume.isSupportedStatic();

View File

@@ -20,7 +20,6 @@ import javax.inject.Named;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedSet;
import java.util.regex.Pattern;
public class FuseVolume extends AbstractVolume {
@@ -73,11 +72,10 @@ public class FuseVolume extends AbstractVolume {
}
@Override
public void reveal() throws VolumeException {
public void reveal(Revealer revealer) throws VolumeException {
try {
mount.revealInFileManager();
} catch (CommandFailedException e) {
LOG.debug("Revealing the vault in file manger failed: " + e.getMessage());
mount.reveal(revealer::reveal);
} catch (Exception e) {
throw new VolumeException(e);
}
}

View File

@@ -104,7 +104,7 @@ public class Vault {
if (vaultSettings.usesReadOnlyMode().get()) {
flags.add(FileSystemFlags.READONLY);
}
if (vaultSettings.filenameLengthLimit().get() == -1) {
if (!flags.contains(FileSystemFlags.READONLY) && vaultSettings.filenameLengthLimit().get() == -1) {
LOG.debug("Determining file name length limitations...");
int limit = new FileSystemCapabilityChecker().determineSupportedFileNameLength(getPath());
vaultSettings.filenameLengthLimit().set(limit);
@@ -121,12 +121,29 @@ public class Vault {
return CryptoFileSystemProvider.newFileSystem(getPath(), fsProps);
}
private void destroyCryptoFileSystem() {
LOG.trace("Trying to close associated CryptoFS...");
CryptoFileSystem fs = cryptoFileSystem.getAndSet(null);
if (fs != null) {
try {
fs.close();
} catch (IOException e) {
LOG.error("Error closing file system.", e);
}
}
}
public synchronized void unlock(CharSequence passphrase) throws CryptoException, IOException, VolumeException, InvalidMountPointException {
if (cryptoFileSystem.get() == null) {
CryptoFileSystem fs = createCryptoFileSystem(passphrase);
cryptoFileSystem.set(fs);
volume = volumeProvider.get();
volume.mount(fs, getEffectiveMountFlags());
try {
volume = volumeProvider.get();
volume.mount(fs, getEffectiveMountFlags());
} catch (Exception e) {
destroyCryptoFileSystem();
throw e;
}
} else {
throw new IllegalStateException("Already unlocked.");
}
@@ -138,18 +155,11 @@ public class Vault {
} else {
volume.unmount();
}
CryptoFileSystem fs = cryptoFileSystem.getAndSet(null);
if (fs != null) {
try {
fs.close();
} catch (IOException e) {
LOG.error("Error closing file system.", e);
}
}
destroyCryptoFileSystem();
}
public void reveal() throws VolumeException {
volume.reveal();
public void reveal(Volume.Revealer vaultRevealer) throws VolumeException {
volume.reveal(vaultRevealer);
}
// ******************************************************************************

View File

@@ -34,7 +34,15 @@ public interface Volume {
*/
void mount(CryptoFileSystem fs, String mountFlags) throws IOException, VolumeException, InvalidMountPointException;
void reveal() throws VolumeException;
/**
* Reveals the mounted volume.
* <p>
* The given {@code revealer} might be used to do it, but not necessarily.
*
* @param revealer An object capable of revealing the location of the mounted vault to view the content (e.g. in the default file browser).
* @throws VolumeException
*/
void reveal(Revealer revealer) throws VolumeException;
void unmount() throws VolumeException;
@@ -79,4 +87,14 @@ public interface Volume {
}
/**
* Hides and unifies the different Revealer implementations in the different nio-adapters.
*/
@FunctionalInterface
interface Revealer {
void reveal(Path p) throws VolumeException;
}
}

View File

@@ -17,6 +17,7 @@ import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.file.Path;
import java.util.Optional;
import java.util.function.Supplier;
public class WebDavVolume implements Volume {
@@ -25,21 +26,27 @@ public class WebDavVolume implements Volume {
private final Provider<WebDavServer> serverProvider;
private final VaultSettings vaultSettings;
private final Settings settings;
private final WindowsDriveLetters windowsDriveLetters;
private WebDavServer server;
private WebDavServletController servlet;
private Mounter.Mount mount;
private Path mountPoint;
@Inject
public WebDavVolume(Provider<WebDavServer> serverProvider, VaultSettings vaultSettings, Settings settings) {
public WebDavVolume(Provider<WebDavServer> serverProvider, VaultSettings vaultSettings, Settings settings, WindowsDriveLetters windowsDriveLetters) {
this.serverProvider = serverProvider;
this.vaultSettings = vaultSettings;
this.settings = settings;
this.windowsDriveLetters = windowsDriveLetters;
}
@Override
public void mount(CryptoFileSystem fs, String mountFlags) throws VolumeException {
startServlet(fs);
mountServlet();
}
private void startServlet(CryptoFileSystem fs){
if (server == null) {
server = serverProvider.get();
}
@@ -50,32 +57,38 @@ public class WebDavVolume implements Volume {
String urlConformMountName = acceptable.negate().collapseFrom(vaultSettings.mountName().get(), '_');
servlet = server.createWebDavServlet(fs.getPath("/"), vaultSettings.getId() + "/" + urlConformMountName);
servlet.start();
mount();
}
private void mount() throws VolumeException {
private void mountServlet() throws VolumeException {
if (servlet == null) {
throw new IllegalStateException("Mounting requires unlocked WebDAV servlet.");
}
//on windows, prevent an automatic drive letter selection in the upstream library. Either we choose already a specifc one or there is no free.
Supplier<String> driveLetterSupplier;
if(System.getProperty("os.name").toLowerCase().contains("windows") && vaultSettings.winDriveLetter().isEmpty().get()) {
driveLetterSupplier = () -> windowsDriveLetters.getAvailableDriveLetter().orElse(null);
} else {
driveLetterSupplier = () -> vaultSettings.winDriveLetter().get();
}
MountParams mountParams = MountParams.create() //
.withWindowsDriveLetter(vaultSettings.winDriveLetter().get()) //
.withWindowsDriveLetter(driveLetterSupplier.get()) //
.withPreferredGvfsScheme(settings.preferredGvfsScheme().get().getPrefix())//
.withWebdavHostname(getLocalhostAliasOrNull()) //
.build();
try {
this.mount = servlet.mount(mountParams); // might block this thread for a while
} catch (Mounter.CommandFailedException e) {
e.printStackTrace();
throw new VolumeException(e);
}
}
@Override
public void reveal() throws VolumeException {
public void reveal(Revealer revealer) throws VolumeException {
try {
mount.reveal();
} catch (Mounter.CommandFailedException e) {
e.printStackTrace();
mount.reveal(revealer::reveal);
} catch (Exception e) {
throw new VolumeException(e);
}
}
@@ -102,7 +115,7 @@ public class WebDavVolume implements Volume {
@Override
public Optional<Path> getMountPoint() {
return Optional.ofNullable(mountPoint); //TODO
return mount.getMountPoint();
}
@Override

View File

@@ -8,6 +8,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -20,14 +21,10 @@ class EnvironmentTest {
private Environment env;
@BeforeAll
static void init() {
System.setProperty("user.home", "/home/testuser");
}
@BeforeEach
void initEach() {
env = new Environment();
void init() {
env = Mockito.spy(new Environment());
Mockito.when(env.getHomeDir()).thenReturn(Path.of("/home/testuser"));
}
@Test

View File

@@ -5,16 +5,19 @@
*******************************************************************************/
package org.cryptomator.common.settings;
import org.cryptomator.common.Environment;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.Mockito;
import java.io.IOException;
public class SettingsJsonAdapterTest {
private final SettingsJsonAdapter adapter = new SettingsJsonAdapter();
private final Environment env = Mockito.mock(Environment.class);
private final SettingsJsonAdapter adapter = new SettingsJsonAdapter(env);
@Test
public void testDeserialize() throws IOException {

View File

@@ -5,6 +5,7 @@
*******************************************************************************/
package org.cryptomator.common.settings;
import org.cryptomator.common.Environment;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
@@ -14,8 +15,10 @@ public class SettingsTest {
@Test
public void testAutoSave() {
Environment env = Mockito.mock(Environment.class);
@SuppressWarnings("unchecked") Consumer<Settings> changeListener = Mockito.mock(Consumer.class);
Settings settings = new Settings();
Settings settings = new Settings(env);
settings.setSaveCmd(changeListener);
VaultSettings vaultSettings = VaultSettings.withRandomId();
Mockito.verify(changeListener, Mockito.times(0)).accept(settings);

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>org.cryptomator</groupId>
<artifactId>main</artifactId>
<version>1.5.11</version>
<version>1.6.0-SNAPSHOT</version>
</parent>
<artifactId>launcher</artifactId>
<name>Cryptomator Launcher</name>

View File

@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.cryptomator</groupId>
<artifactId>main</artifactId>
<version>1.5.11</version>
<version>1.5.12</version>
<packaging>pom</packaging>
<name>Cryptomator</name>
@@ -28,15 +28,15 @@
<cryptomator.integrations.version>0.1.6</cryptomator.integrations.version>
<cryptomator.integrations.win.version>0.2.1</cryptomator.integrations.win.version>
<cryptomator.integrations.mac.version>0.1.0-beta3</cryptomator.integrations.mac.version>
<cryptomator.integrations.linux.version>0.1.0-beta2</cryptomator.integrations.linux.version>
<cryptomator.fuse.version>1.2.6</cryptomator.fuse.version>
<cryptomator.dokany.version>1.2.1</cryptomator.dokany.version>
<cryptomator.webdav.version>1.0.14</cryptomator.webdav.version>
<cryptomator.integrations.linux.version>0.1.1</cryptomator.integrations.linux.version>
<cryptomator.fuse.version>1.2.8</cryptomator.fuse.version>
<cryptomator.dokany.version>1.2.3</cryptomator.dokany.version>
<cryptomator.webdav.version>1.1.1</cryptomator.webdav.version>
<!-- 3rd party dependencies -->
<javafx.version>15</javafx.version>
<commons-lang3.version>3.11</commons-lang3.version>
<jwt.version>3.11.0</jwt.version>
<jwt.version>3.12.0</jwt.version>
<easybind.version>2.1.0</easybind.version>
<guava.version>30.0-jre</guava.version>
<dagger.version>2.29.1</dagger.version>
@@ -175,13 +175,6 @@
<artifactId>java-jwt</artifactId>
<version>${jwt.version}</version>
</dependency>
<!-- fixes CVE-2020-25649, can be removed once https://github.com/auth0/java-jwt/pull/463 is closed and released -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.5.1</version>
</dependency>
<!-- EasyBind -->
<dependency>

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>org.cryptomator</groupId>
<artifactId>main</artifactId>
<version>1.5.11</version>
<version>1.6.0-SNAPSHOT</version>
</parent>
<artifactId>ui</artifactId>
<name>Cryptomator GUI</name>

View File

@@ -0,0 +1,25 @@
package org.cryptomator.ui.common;
import dagger.Lazy;
import org.cryptomator.common.vaults.Volume;
import org.cryptomator.ui.fxapp.FxApplicationScoped;
import javax.inject.Inject;
import javafx.application.Application;
import java.nio.file.Path;
@FxApplicationScoped
public class HostServiceRevealer implements Volume.Revealer {
private final Lazy<Application> application;
@Inject
public HostServiceRevealer(Lazy<Application> application) {
this.application = application;
}
@Override
public void reveal(Path p) throws Volume.VolumeException {
application.get().getHostServices().showDocument(p.toUri().toString());
}
}

View File

@@ -23,10 +23,12 @@ public class VaultService {
private static final Logger LOG = LoggerFactory.getLogger(VaultService.class);
private final ExecutorService executorService;
private final HostServiceRevealer vaultRevealer;
@Inject
public VaultService(ExecutorService executorService) {
public VaultService(ExecutorService executorService, HostServiceRevealer vaultRevealer) {
this.executorService = executorService;
this.vaultRevealer = vaultRevealer;
}
public void reveal(Vault vault) {
@@ -39,7 +41,7 @@ public class VaultService {
* @param vault The vault to reveal
*/
public Task<Vault> createRevealTask(Vault vault) {
Task<Vault> task = new RevealVaultTask(vault);
Task<Vault> task = new RevealVaultTask(vault, vaultRevealer);
task.setOnSucceeded(evt -> LOG.info("Revealed {}", vault.getDisplayName()));
task.setOnFailed(evt -> LOG.error("Failed to reveal " + vault.getDisplayName(), evt.getSource().getException()));
return task;
@@ -99,19 +101,22 @@ public class VaultService {
private static class RevealVaultTask extends Task<Vault> {
private final Vault vault;
private final Volume.Revealer revealer;
/**
* @param vault The vault to lock
* @param revealer The object to use to show the vault content to the user.
*/
public RevealVaultTask(Vault vault) {
public RevealVaultTask(Vault vault, Volume.Revealer revealer) {
this.vault = vault;
this.revealer = revealer;
setOnFailed(evt -> LOG.error("Failed to reveal " + vault.getDisplayName(), getException()));
}
@Override
protected Vault call() throws Volume.VolumeException {
vault.reveal();
vault.reveal(revealer);
return vault;
}
}

View File

@@ -32,6 +32,8 @@ import javafx.stage.Stage;
import javafx.stage.Window;
import java.awt.desktop.QuitResponse;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
@FxApplicationScoped
public class FxApplication extends Application {
@@ -99,11 +101,14 @@ public class FxApplication extends Application {
});
}
public void showMainWindow() {
public CompletionStage<Stage> showMainWindow() {
CompletableFuture<Stage> future = new CompletableFuture<>();
Platform.runLater(() -> {
mainWindow.get().showMainWindow();
var win = mainWindow.get().showMainWindow();
LOG.debug("Showing MainWindow");
future.complete(win);
});
return future;
}
public void startUnlockWorkflow(Vault vault, Optional<Stage> owner) {

View File

@@ -5,11 +5,8 @@
*******************************************************************************/
package org.cryptomator.ui.fxapp;
import dagger.BindsInstance;
import dagger.Subcomponent;
import javax.inject.Named;
@FxApplicationScoped
@Subcomponent(modules = FxApplicationModule.class)
public interface FxApplicationComponent {
@@ -19,9 +16,6 @@ public interface FxApplicationComponent {
@Subcomponent.Builder
interface Builder {
@BindsInstance
Builder trayMenuSupported(@Named("trayMenuSupported") boolean trayMenuSupported);
FxApplicationComponent build();
}

View File

@@ -34,15 +34,15 @@ class AppLaunchEventHandler {
this.vaultListManager = vaultListManager;
}
public void startHandlingLaunchEvents(boolean hasTrayIcon) {
executorService.submit(() -> handleLaunchEvents(hasTrayIcon));
public void startHandlingLaunchEvents() {
executorService.submit(this::handleLaunchEvents);
}
private void handleLaunchEvents(boolean hasTrayIcon) {
private void handleLaunchEvents() {
try {
while (!Thread.interrupted()) {
AppLaunchEvent event = launchEventQueue.take();
handleLaunchEvent(hasTrayIcon, event);
handleLaunchEvent(event);
}
} catch (InterruptedException e) {
LOG.warn("Interrupted launch event handler.");
@@ -50,10 +50,10 @@ class AppLaunchEventHandler {
}
}
private void handleLaunchEvent(boolean hasTrayIcon, AppLaunchEvent event) {
private void handleLaunchEvent(AppLaunchEvent event) {
switch (event.getType()) {
case REVEAL_APP -> fxApplicationStarter.get(hasTrayIcon).thenAccept(FxApplication::showMainWindow);
case OPEN_FILE -> fxApplicationStarter.get(hasTrayIcon).thenRun(() -> {
case REVEAL_APP -> fxApplicationStarter.get().thenAccept(FxApplication::showMainWindow);
case OPEN_FILE -> fxApplicationStarter.get().thenRun(() -> {
Platform.runLater(() -> {
event.getPathsToOpen().forEach(this::addVault);
});

View File

@@ -83,7 +83,7 @@ public class AppLifecycleListener {
if (allowQuitWithoutPrompt.get()) {
decoratedQuitResponse.performQuit();
} else {
fxApplicationStarter.get(true).thenAccept(app -> app.showQuitWindow(decoratedQuitResponse));
fxApplicationStarter.get().thenAccept(app -> app.showQuitWindow(decoratedQuitResponse));
}
}
@@ -113,11 +113,11 @@ public class AppLifecycleListener {
}
private void showPreferencesWindow(@SuppressWarnings("unused") EventObject actionEvent) {
fxApplicationStarter.get(true).thenAccept(app -> app.showPreferencesWindow(SelectedPreferencesTab.ANY));
fxApplicationStarter.get().thenAccept(app -> app.showPreferencesWindow(SelectedPreferencesTab.ANY));
}
private void showAboutWindow(@SuppressWarnings("unused") AboutEvent aboutEvent) {
fxApplicationStarter.get(true).thenAccept(app -> app.showPreferencesWindow(SelectedPreferencesTab.ABOUT));
fxApplicationStarter.get().thenAccept(app -> app.showPreferencesWindow(SelectedPreferencesTab.ABOUT));
}
private void forceUnmountRemainingVaults() {

View File

@@ -1,5 +1,6 @@
package org.cryptomator.ui.launcher;
import dagger.Lazy;
import org.cryptomator.ui.fxapp.FxApplication;
import org.cryptomator.ui.fxapp.FxApplicationComponent;
import org.slf4j.Logger;
@@ -18,37 +19,36 @@ public class FxApplicationStarter {
private static final Logger LOG = LoggerFactory.getLogger(FxApplicationStarter.class);
private final FxApplicationComponent.Builder fxAppComponent;
private final Lazy<FxApplicationComponent> fxAppComponent;
private final ExecutorService executor;
private final AtomicBoolean started;
private final CompletableFuture<FxApplication> future;
@Inject
public FxApplicationStarter(FxApplicationComponent.Builder fxAppComponent, ExecutorService executor) {
public FxApplicationStarter(Lazy<FxApplicationComponent> fxAppComponent, ExecutorService executor) {
this.fxAppComponent = fxAppComponent;
this.executor = executor;
this.started = new AtomicBoolean();
this.future = new CompletableFuture<>();
}
public CompletionStage<FxApplication> get(boolean hasTrayIcon) {
public CompletionStage<FxApplication> get() {
if (!started.getAndSet(true)) {
start(hasTrayIcon);
start();
}
return future;
}
private void start(boolean hasTrayIcon) {
private void start() {
executor.submit(() -> {
LOG.debug("Starting JavaFX runtime...");
Platform.startup(() -> {
assert Platform.isFxApplicationThread();
LOG.info("JavaFX Runtime started.");
FxApplication app = fxAppComponent.trayMenuSupported(hasTrayIcon).build().application();
FxApplication app = fxAppComponent.get().application();
app.start();
future.complete(app);
});
});
}
}

View File

@@ -1,5 +1,6 @@
package org.cryptomator.ui.launcher;
import dagger.Lazy;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.integrations.tray.TrayIntegrationProvider;
@@ -24,60 +25,66 @@ public class UiLauncher {
private final Settings settings;
private final ObservableList<Vault> vaults;
private final TrayMenuComponent.Builder trayComponent;
private final Lazy<TrayMenuComponent> trayMenu;
private final FxApplicationStarter fxApplicationStarter;
private final AppLaunchEventHandler launchEventHandler;
private final Optional<TrayIntegrationProvider> trayIntegration;
@Inject
public UiLauncher(Settings settings, ObservableList<Vault> vaults, TrayMenuComponent.Builder trayComponent, FxApplicationStarter fxApplicationStarter, AppLaunchEventHandler launchEventHandler, Optional<TrayIntegrationProvider> trayIntegration) {
public UiLauncher(Settings settings, ObservableList<Vault> vaults, Lazy<TrayMenuComponent> trayMenu, FxApplicationStarter fxApplicationStarter, AppLaunchEventHandler launchEventHandler, Optional<TrayIntegrationProvider> trayIntegration) {
this.settings = settings;
this.vaults = vaults;
this.trayComponent = trayComponent;
this.trayMenu = trayMenu;
this.fxApplicationStarter = fxApplicationStarter;
this.launchEventHandler = launchEventHandler;
this.trayIntegration = trayIntegration;
}
public void launch() {
final boolean hasTrayIcon;
if (SystemTray.isSupported()) {
trayComponent.build().addIconToSystemTray();
hasTrayIcon = true;
boolean hidden = settings.startHidden().get();
if (SystemTray.isSupported() && settings.showTrayIcon().get()) {
trayMenu.get().initializeTrayIcon();
launch(true, hidden);
} else {
hasTrayIcon = false;
launch(false, hidden);
}
}
// show window on start?
if (hasTrayIcon && settings.startHidden().get()) {
private void launch(boolean withTrayIcon, boolean hidden) {
// start hidden, minimized or normal?
if (withTrayIcon && hidden) {
LOG.debug("Hiding application...");
trayIntegration.ifPresent(TrayIntegrationProvider::minimizedToTray);
} else if (!withTrayIcon && hidden) {
LOG.debug("Minimizing application...");
showMainWindowAsync(true);
} else {
showMainWindowAsync(hasTrayIcon);
LOG.debug("Showing application...");
showMainWindowAsync(false);
}
// register app reopen listener
Desktop.getDesktop().addAppEventListener((AppReopenedListener) e -> showMainWindowAsync(hasTrayIcon));
Desktop.getDesktop().addAppEventListener((AppReopenedListener) e -> showMainWindowAsync(false));
// auto unlock
Collection<Vault> vaultsToAutoUnlock = vaults.filtered(this::shouldAttemptAutoUnlock);
if (!vaultsToAutoUnlock.isEmpty()) {
fxApplicationStarter.get(hasTrayIcon).thenAccept(app -> {
fxApplicationStarter.get().thenAccept(app -> {
for (Vault vault : vaultsToAutoUnlock) {
app.startUnlockWorkflow(vault, Optional.empty());
}
});
}
launchEventHandler.startHandlingLaunchEvents(hasTrayIcon);
launchEventHandler.startHandlingLaunchEvents();
}
private boolean shouldAttemptAutoUnlock(Vault vault) {
return vault.isLocked() && vault.getVaultSettings().unlockAfterStartup().get();
}
private void showMainWindowAsync(boolean hasTrayIcon) {
fxApplicationStarter.get(hasTrayIcon).thenAccept(FxApplication::showMainWindow);
private void showMainWindowAsync(boolean minimize) {
fxApplicationStarter.get().thenCompose(FxApplication::showMainWindow).thenAccept(win -> win.setIconified(minimize));
}
}

View File

@@ -19,6 +19,18 @@ import java.util.concurrent.BlockingQueue;
@Module(subcomponents = {TrayMenuComponent.class, FxApplicationComponent.class})
public abstract class UiLauncherModule {
@Provides
@Singleton
static TrayMenuComponent provideTrayMenuComponent(TrayMenuComponent.Builder builder) {
return builder.build();
}
@Provides
@Singleton
static FxApplicationComponent provideFxApplicationComponent(FxApplicationComponent.Builder builder) {
return builder.build();
}
@Provides
@Singleton
static Optional<UiAppearanceProvider> provideAppearanceProvider() {

View File

@@ -26,7 +26,6 @@ public interface MainWindowComponent {
default Stage showMainWindow() {
Stage stage = window();
stage.setScene(scene().get());
stage.setIconified(false);
stage.show();
stage.toFront();
stage.requestFocus();

View File

@@ -7,13 +7,14 @@ import org.cryptomator.ui.fxapp.FxApplication;
import org.cryptomator.ui.fxapp.UpdateChecker;
import org.cryptomator.ui.launcher.AppLifecycleListener;
import org.cryptomator.ui.preferences.SelectedPreferencesTab;
import org.cryptomator.ui.traymenu.TrayMenuComponent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Named;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.fxml.FXML;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
@@ -23,32 +24,31 @@ public class MainWindowTitleController implements FxController {
private static final Logger LOG = LoggerFactory.getLogger(MainWindowTitleController.class);
public HBox titleBar;
private final AppLifecycleListener appLifecycle;
private final Stage window;
private final FxApplication application;
private final boolean minimizeToSysTray;
private final boolean trayMenuInitialized;
private final UpdateChecker updateChecker;
private final BooleanBinding updateAvailable;
private final LicenseHolder licenseHolder;
private final Settings settings;
private final BooleanBinding debugModeEnabled;
private final BooleanBinding showMinimizeButton;
public HBox titleBar;
private double xOffset;
private double yOffset;
@Inject
MainWindowTitleController(AppLifecycleListener appLifecycle, @MainWindow Stage window, FxApplication application, @Named("trayMenuSupported") boolean minimizeToSysTray, UpdateChecker updateChecker, LicenseHolder licenseHolder, Settings settings) {
MainWindowTitleController(AppLifecycleListener appLifecycle, @MainWindow Stage window, FxApplication application, TrayMenuComponent trayMenu, UpdateChecker updateChecker, LicenseHolder licenseHolder, Settings settings) {
this.appLifecycle = appLifecycle;
this.window = window;
this.application = application;
this.minimizeToSysTray = minimizeToSysTray;
this.trayMenuInitialized = trayMenu.isInitialized();
this.updateChecker = updateChecker;
this.updateAvailable = updateChecker.latestVersionProperty().isNotNull();
this.licenseHolder = licenseHolder;
this.settings = settings;
this.debugModeEnabled = Bindings.createBooleanBinding(this::isDebugModeEnabled, settings.debugMode());
this.showMinimizeButton = Bindings.createBooleanBinding(this::isShowMinimizeButton, settings.showMinimizeButton(), settings.showTrayIcon());
}
@FXML
@@ -71,7 +71,7 @@ public class MainWindowTitleController implements FxController {
@FXML
public void close() {
if (minimizeToSysTray) {
if (trayMenuInitialized) {
window.close();
} else {
appLifecycle.quit();
@@ -112,15 +112,24 @@ public class MainWindowTitleController implements FxController {
return updateAvailable.get();
}
public boolean isMinimizeToSysTray() {
return minimizeToSysTray;
public boolean isTrayIconPresent() {
return trayMenuInitialized;
}
public BooleanBinding debugModeEnabledProperty() {
return debugModeEnabled;
public ReadOnlyBooleanProperty debugModeEnabledProperty() {
return settings.debugMode();
}
public boolean isDebugModeEnabled() {
return settings.debugMode().get();
return debugModeEnabledProperty().get();
}
public BooleanBinding showMinimizeButtonProperty() {
return showMinimizeButton;
}
public boolean isShowMinimizeButton() {
// always show the minimize button if no tray icon is present OR it is explicitily enabled
return !trayMenuInitialized || settings.showMinimizeButton().get();
}
}

View File

@@ -10,11 +10,11 @@ import org.cryptomator.integrations.autostart.ToggleAutoStartFailedException;
import org.cryptomator.integrations.keychain.KeychainAccessProvider;
import org.cryptomator.ui.common.ErrorComponent;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.traymenu.TrayMenuComponent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Named;
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.value.ObservableValue;
@@ -31,7 +31,6 @@ import java.util.Arrays;
import java.util.Optional;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
@PreferencesScoped
@@ -41,11 +40,11 @@ public class GeneralPreferencesController implements FxController {
private final Stage window;
private final Settings settings;
private final boolean trayMenuInitialized;
private final boolean trayMenuSupported;
private final Optional<AutoStartProvider> autoStartProvider;
private final ObjectProperty<SelectedPreferencesTab> selectedTabProperty;
private final LicenseHolder licenseHolder;
private final ExecutorService executor;
private final ResourceBundle resourceBundle;
private final Application application;
private final Environment environment;
@@ -53,6 +52,8 @@ public class GeneralPreferencesController implements FxController {
private final ErrorComponent.Builder errorComponent;
public ChoiceBox<UiTheme> themeChoiceBox;
public ChoiceBox<KeychainBackend> keychainBackendChoiceBox;
public CheckBox showMinimizeButtonCheckbox;
public CheckBox showTrayIconCheckbox;
public CheckBox startHiddenCheckbox;
public CheckBox debugModeCheckbox;
public CheckBox autoStartCheckbox;
@@ -60,16 +61,17 @@ public class GeneralPreferencesController implements FxController {
public RadioButton nodeOrientationLtr;
public RadioButton nodeOrientationRtl;
@Inject
GeneralPreferencesController(@PreferencesWindow Stage window, Settings settings, @Named("trayMenuSupported") boolean trayMenuSupported, Optional<AutoStartProvider> autoStartProvider, Set<KeychainAccessProvider> keychainAccessProviders, ObjectProperty<SelectedPreferencesTab> selectedTabProperty, LicenseHolder licenseHolder, ExecutorService executor, ResourceBundle resourceBundle, Application application, Environment environment, ErrorComponent.Builder errorComponent) {
GeneralPreferencesController(@PreferencesWindow Stage window, Settings settings, TrayMenuComponent trayMenu, Optional<AutoStartProvider> autoStartProvider, Set<KeychainAccessProvider> keychainAccessProviders, ObjectProperty<SelectedPreferencesTab> selectedTabProperty, LicenseHolder licenseHolder, ResourceBundle resourceBundle, Application application, Environment environment, ErrorComponent.Builder errorComponent) {
this.window = window;
this.settings = settings;
this.trayMenuSupported = trayMenuSupported;
this.trayMenuInitialized = trayMenu.isInitialized();
this.trayMenuSupported = trayMenu.isSupported();
this.autoStartProvider = autoStartProvider;
this.keychainAccessProviders = keychainAccessProviders;
this.selectedTabProperty = selectedTabProperty;
this.licenseHolder = licenseHolder;
this.executor = executor;
this.resourceBundle = resourceBundle;
this.application = application;
this.environment = environment;
@@ -85,6 +87,10 @@ public class GeneralPreferencesController implements FxController {
themeChoiceBox.valueProperty().bindBidirectional(settings.theme());
themeChoiceBox.setConverter(new UiThemeConverter(resourceBundle));
showMinimizeButtonCheckbox.selectedProperty().bindBidirectional(settings.showMinimizeButton());
showTrayIconCheckbox.selectedProperty().bindBidirectional(settings.showTrayIcon());
startHiddenCheckbox.selectedProperty().bindBidirectional(settings.startHidden());
debugModeCheckbox.selectedProperty().bindBidirectional(settings.debugMode());
@@ -105,8 +111,12 @@ public class GeneralPreferencesController implements FxController {
return Arrays.stream(KeychainBackend.values()).filter(value -> namesOfAvailableProviders.contains(value.getProviderClass())).toArray(KeychainBackend[]::new);
}
public boolean isTrayMenuInitialized() {
return trayMenuInitialized;
}
public boolean isTrayMenuSupported() {
return this.trayMenuSupported;
return trayMenuSupported;
}
public boolean isAutoStartSupported() {
@@ -175,6 +185,7 @@ public class GeneralPreferencesController implements FxController {
public UiTheme fromString(String string) {
throw new UnsupportedOperationException();
}
}
private static class KeychainBackendConverter extends StringConverter<KeychainBackend> {
@@ -194,6 +205,6 @@ public class GeneralPreferencesController implements FxController {
public KeychainBackend fromString(String string) {
throw new UnsupportedOperationException();
}
}
}
}

View File

@@ -1,5 +1,6 @@
package org.cryptomator.ui.traymenu;
import com.google.common.base.Preconditions;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.integrations.uiappearance.Theme;
import org.cryptomator.integrations.uiappearance.UiAppearanceException;
@@ -22,6 +23,7 @@ public class TrayIconController {
private final Optional<UiAppearanceProvider> appearanceProvider;
private final TrayMenuController trayMenuController;
private final TrayIcon trayIcon;
private volatile boolean initialized;
@Inject
TrayIconController(TrayImageFactory imageFactory, TrayMenuController trayMenuController, Optional<UiAppearanceProvider> appearanceProvider) {
@@ -31,7 +33,9 @@ public class TrayIconController {
this.trayIcon = new TrayIcon(imageFactory.loadImage(), "Cryptomator", trayMenuController.getMenu());
}
public void initializeTrayIcon() {
public synchronized void initializeTrayIcon() throws IllegalStateException {
Preconditions.checkState(!initialized);
appearanceProvider.ifPresent(appearanceProvider -> {
try {
appearanceProvider.addListener(this::systemInterfaceThemeChanged);
@@ -53,10 +57,15 @@ public class TrayIconController {
}
trayMenuController.initTrayMenu();
this.initialized = true;
}
private void systemInterfaceThemeChanged(Theme theme) {
trayIcon.setImage(imageFactory.loadImage()); // TODO refactor "theme" is re-queried in loadImage()
}
public boolean isInitialized() {
return initialized;
}
}

View File

@@ -5,19 +5,38 @@
*******************************************************************************/
package org.cryptomator.ui.traymenu;
import dagger.Lazy;
import dagger.Subcomponent;
import java.awt.SystemTray;
@TrayMenuScoped
@Subcomponent
public interface TrayMenuComponent {
TrayIconController trayIconController();
Lazy<TrayIconController> trayIconController();
default void addIconToSystemTray() {
assert SystemTray.isSupported();
trayIconController().initializeTrayIcon();
/**
* @return <code>true</code> if a tray icon can be installed
*/
default boolean isSupported() {
return SystemTray.isSupported();
}
/**
* @return <code>true</code> if a tray icon has been installed
*/
default boolean isInitialized() {
return isSupported() && trayIconController().get().isInitialized();
}
/**
* Installs a tray icon to the system tray.
*
* @throws IllegalStateException If already added
*/
default void initializeTrayIcon() throws IllegalStateException {
assert isSupported();
trayIconController().get().initializeTrayIcon();
}
@Subcomponent.Builder

View File

@@ -1,6 +1,7 @@
package org.cryptomator.ui.traymenu;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.fxapp.FxApplication;
import org.cryptomator.ui.launcher.AppLifecycleListener;
import org.cryptomator.ui.launcher.FxApplicationStarter;
import org.cryptomator.ui.preferences.SelectedPreferencesTab;
@@ -103,32 +104,36 @@ class TrayMenuController {
return actionEvent -> consumer.accept(vault);
}
private void unlockVault(Vault vault) {
fxApplicationStarter.get(true).thenAccept(app -> app.startUnlockWorkflow(vault, Optional.empty()));
}
private void lockVault(Vault vault) {
fxApplicationStarter.get(true).thenAccept(app -> app.startLockWorkflow(vault, Optional.empty()));
}
private void lockAllVaults(ActionEvent actionEvent) {
fxApplicationStarter.get(true).thenAccept(app -> app.getVaultService().lockAll(vaults.filtered(Vault::isUnlocked), false));
}
private void revealVault(Vault vault) {
fxApplicationStarter.get(true).thenAccept(app -> app.getVaultService().reveal(vault));
}
void showMainWindow(@SuppressWarnings("unused") ActionEvent actionEvent) {
fxApplicationStarter.get(true).thenAccept(app -> app.showMainWindow());
}
private void showPreferencesWindow(@SuppressWarnings("unused") EventObject actionEvent) {
fxApplicationStarter.get(true).thenAccept(app -> app.showPreferencesWindow(SelectedPreferencesTab.ANY));
}
private void quitApplication(EventObject actionEvent) {
appLifecycle.quit();
}
private void unlockVault(Vault vault) {
showMainAppAndThen(app -> app.startUnlockWorkflow(vault, Optional.empty()));
}
private void lockVault(Vault vault) {
showMainAppAndThen(app -> app.startLockWorkflow(vault, Optional.empty()));
}
private void lockAllVaults(ActionEvent actionEvent) {
showMainAppAndThen(app -> app.getVaultService().lockAll(vaults.filtered(Vault::isUnlocked), false));
}
private void revealVault(Vault vault) {
showMainAppAndThen(app -> app.getVaultService().reveal(vault));
}
void showMainWindow(@SuppressWarnings("unused") ActionEvent actionEvent) {
showMainAppAndThen(app -> app.showMainWindow());
}
private void showPreferencesWindow(@SuppressWarnings("unused") EventObject actionEvent) {
showMainAppAndThen(app -> app.showPreferencesWindow(SelectedPreferencesTab.ANY));
}
private void showMainAppAndThen(Consumer<FxApplication> action) {
fxApplicationStarter.get().thenAccept(action);
}
}

View File

@@ -165,15 +165,7 @@ public class UnlockWorkflow extends Task<Boolean> {
assert requirement != MountPointRequirement.PARENT_OPT_MOUNT_POINT; //Not implemented anywhere (yet)
Throwable cause = impExc.getCause();
//Cause is either null (cause the IMPE was thrown directly, e.g. because no MPC succeeded)
//or the cause was not an Exception (but some other kind of Throwable)
//Either way: Handle as generic error
if (!(cause instanceof Exception)) {
handleGenericError(impExc);
return;
}
//From here on handle the cause, not the caught exception
// TODO: apply https://openjdk.java.net/jeps/8213076 in future JDK versions
if (cause instanceof NotDirectoryException) {
if (requirement == MountPointRequirement.PARENT_NO_MOUNT_POINT) {
LOG.error("Unlock failed. Parent folder is missing: {}", cause.getMessage());
@@ -182,28 +174,23 @@ public class UnlockWorkflow extends Task<Boolean> {
}
showInvalidMountPointScene();
return;
}
if (cause instanceof FileAlreadyExistsException) {
} else if (cause instanceof FileAlreadyExistsException) {
LOG.error("Unlock failed. Mountpoint already exists: {}", cause.getMessage());
showInvalidMountPointScene();
return;
}
if (cause instanceof DirectoryNotEmptyException) {
} else if (cause instanceof DirectoryNotEmptyException) {
LOG.error("Unlock failed. Mountpoint not an empty directory: {}", cause.getMessage());
showInvalidMountPointScene();
return;
} else {
handleGenericError(impExc);
}
//Everything else (especially IOException) results in a generic error
//This must be done after the other exceptions because they extend IOException...
handleGenericError(cause);
}
private void showInvalidMountPointScene() {
Platform.runLater(() -> {
window.setScene(invalidMountPointScene.get());
window.show();
});
}

View File

@@ -54,7 +54,7 @@
<Tooltip text="%main.preferencesBtn.tooltip"/>
</tooltip>
</Button>
<Button contentDisplay="GRAPHIC_ONLY" mnemonicParsing="false" onAction="#minimize" focusTraversable="false" visible="${!controller.minimizeToSysTray}" managed="${!controller.minimizeToSysTray}">
<Button contentDisplay="GRAPHIC_ONLY" mnemonicParsing="false" onAction="#minimize" focusTraversable="false" visible="${controller.showMinimizeButton}" managed="${controller.showMinimizeButton}">
<graphic>
<FontAwesome5IconView glyph="WINDOW_MINIMIZE" glyphSize="12"/>
</graphic>

View File

@@ -22,7 +22,7 @@
</ImageView>
<VBox spacing="3" HBox.hgrow="ALWAYS" alignment="CENTER_LEFT">
<FormattedLabel styleClass="label-large" format="Cryptomator %s" arg1="${controller.applicationVersion}"/>
<Label text="© 2016 2020 Skymatic GmbH"/>
<Label text="© 2016 2021 Skymatic GmbH"/>
</VBox>
</HBox>

View File

@@ -32,7 +32,11 @@
<RadioButton fx:id="nodeOrientationRtl" text="%preferences.general.interfaceOrientation.rtl" alignment="CENTER_RIGHT" toggleGroup="${nodeOrientation}"/>
</HBox>
<CheckBox fx:id="startHiddenCheckbox" text="%preferences.general.startHidden" visible="${controller.trayMenuSupported}" managed="${controller.trayMenuSupported}"/>
<CheckBox fx:id="showMinimizeButtonCheckbox" text="%preferences.general.showMinimizeButton" visible="${controller.trayMenuInitialized}" managed="${controller.trayMenuInitialized}"/>
<CheckBox fx:id="showTrayIconCheckbox" text="%preferences.general.showTrayIcon" visible="${controller.trayMenuSupported}" managed="${controller.trayMenuSupported}"/>
<CheckBox fx:id="startHiddenCheckbox" text="%preferences.general.startHidden" />
<HBox spacing="6" alignment="CENTER_LEFT">
<CheckBox fx:id="debugModeCheckbox" text="%preferences.general.debugLogging"/>

View File

@@ -150,6 +150,8 @@ preferences.general.theme.automatic=Automatic
preferences.general.theme.light=Light
preferences.general.theme.dark=Dark
preferences.general.unlockThemes=Unlock dark mode
preferences.general.showMinimizeButton=Show minimize button
preferences.general.showTrayIcon=Show tray icon (requires restart)
preferences.general.startHidden=Hide window when starting Cryptomator
preferences.general.debugLogging=Enable debug logging
preferences.general.debugDirectory=Reveal log files

View File

@@ -102,13 +102,16 @@ unlock.success.message=تم فتح المخزن "%s" بنجاح! يمكنك ال
unlock.success.rememberChoice=تذكر اختياري ولا تظهر هذا مرة أخرى
unlock.success.revealBtn=افتح الحافظة
## Failure
unlock.error.heading=غير قادر على فتح الخزنة
### Invalid Mount Point
unlock.error.invalidMountPoint.notExisting=نقطة التحميل ليست مجلد فارغ أو غير موجودة: %s
unlock.error.invalidMountPoint.existing=نقطة/مجلد التحميل موجود بالفعل أو المجلد الأصل مفقود: %s
# Lock
## Force
lock.forced.confirmBtn=فرض القفل
## Failure
lock.fail.heading=فشلت عملية اقفال الخزنة.
# Migration
migration.title=ترقية الحافظة
@@ -175,8 +178,12 @@ preferences.donationKey.getDonationKey=الحصول على مفتاح تبرع
preferences.about=حول البرنامج
# Vault Statistics
stats.cacheHitRate=معدل استخدام الكاش
## Read
stats.read.throughput.idle=قراءة: خامل
stats.decr.total.data.none=تم فك تشفير البيانات:-
## Write
stats.encr.total.data.none=البيانات المشفرة: -
# Main Window
main.closeBtn.tooltip=إغلاق
@@ -206,9 +213,11 @@ main.vaultDetail.accessLocation=يمكن الوصول إلى محتويات مخ
main.vaultDetail.revealBtn=اظهار القرص
main.vaultDetail.lockBtn=قفل
main.vaultDetail.bytesPerSecondRead=قراءة:
main.vaultDetail.bytesPerSecondWritten=كتابة:
main.vaultDetail.throughput.idle=خمول
main.vaultDetail.throughput.kbps=%.1f كيلوبايت/ث
main.vaultDetail.throughput.mbps=%.1f ميجابايت/ث
main.vaultDetail.stats=إحصائيات الخزنة
### Missing
main.vaultDetail.missing.info=لم يتمكن Cryptomator من العثور على خزنة في هذا المسار.
main.vaultDetail.missing.recheck=إعادة الفحص

View File

@@ -109,6 +109,7 @@ unlock.error.invalidMountPoint.existing=El punt de muntatge o la carpeta ja exis
# Lock
## Force
lock.forced.heading=Ha fallat el blocatge
lock.forced.message=No s'ha blocat "%s" perquè hi ha operacions pendents o fitxers oberts. Podeu forçar-ne el blocatge però heu de saber que interrompre l'entrada/sortida pot produir la pèrdua de dades.
lock.forced.confirmBtn=Força el blocatge
## Failure
@@ -148,6 +149,8 @@ preferences.general.theme.automatic=Automàtic
preferences.general.theme.light=Clar
preferences.general.theme.dark=Fosc
preferences.general.unlockThemes=Desbloqueja el tema fosc
preferences.general.showMinimizeButton=Mostra el botó de minimitzar
preferences.general.showTrayIcon=Mostra la icona en la barra (cal reiniciar)
preferences.general.startHidden=Amaga la finestra quan s'inicia Cryptomator
preferences.general.debugLogging=Habilita el registre de depuració
preferences.general.debugDirectory=Mostra els fitxers de registres
@@ -156,6 +159,7 @@ preferences.general.keychainBackend=Desar contrasenyes amb
preferences.general.keychainBackend.org.cryptomator.linux.keychain.SecretServiceKeychainAccess=Anell de claus de Gnome
preferences.general.keychainBackend.org.cryptomator.linux.keychain.KDEWalletKeychainAccess=Cartera de KDE
preferences.general.keychainBackend.org.cryptomator.macos.keychain.MacSystemKeychainAccess=Accés a clauers macOS
preferences.general.keychainBackend.org.cryptomator.windows.keychain.WindowsProtectedKeychainAccess=Windows Data Protection
preferences.general.interfaceOrientation=Orientació de la interfície
preferences.general.interfaceOrientation.ltr=Esquerra a dreta
preferences.general.interfaceOrientation.rtl=Dreta a esquerra
@@ -180,6 +184,7 @@ preferences.about=Quant a
# Vault Statistics
stats.title=Estadístiques per a %s
stats.cacheHitRate=Relació d'encerts de la memòria cau
## Read
stats.read.throughput.idle=Llegit: inactiu
stats.read.throughput.kibs=Llegit: %.2f kiB/s

View File

@@ -144,6 +144,8 @@ preferences.general.theme.automatic=Automaticky
preferences.general.theme.light=Světlý
preferences.general.theme.dark=Tmavý
preferences.general.unlockThemes=Odemknout tmavý režim
preferences.general.showMinimizeButton=Zobrazit tlačítko minimalizovat
preferences.general.showTrayIcon=Zobrazit ikonu v liště (vyžaduje restart)
preferences.general.startHidden=Skrýt okno Cryptomatoru při spuštění
preferences.general.debugLogging=Ladicí režim
preferences.general.debugDirectory=Ukázat soubory se záznamy událostí (log)

View File

@@ -109,11 +109,11 @@ unlock.error.invalidMountPoint.existing=Einhängepunkt/Ordner bereits vorhanden
# Lock
## Force
lock.forced.heading=Tresor konnte nicht kontrolliert gesperrt werden
lock.forced.message=Das Sperren von „%s“ wurde durch noch ablaufende Vorgänge oder offene Dateien verhindert. Sie können das Sperren dieses Tresors erzwingen, allerdings kann dies zum Verlust ungespeicherter Daten führen.
lock.forced.heading=Sperren fehlgeschlagen
lock.forced.message=Aufgrund von Zugriffen laufender Prozesse oder geöffneter Dateien konnte „%s“ nicht gesperrt werden. Du kannst das Sperren dieses Tresors erzwingen, allerdings kann dies zum Verlust ungespeicherter Daten führen.
lock.forced.confirmBtn=Sperren erzwingen
## Failure
lock.fail.heading=Der Tresor konnte nicht gesperrt werden.
lock.fail.heading=Tresor konnte nicht gesperrt werden.
lock.fail.message=Der Tresor „%s“ konnte nicht gesperrt werden. Stellen Sie sicher, dass Sie Ihre ungespeicherten Arbeit an anderer Stelle speichern und wichtige Lese-/Schreibvorgänge abgeschlossen sind. Um den Tresor zu schließen, beenden Sie den Cryptomator-Prozess.
# Migration
@@ -149,6 +149,8 @@ preferences.general.theme.automatic=Automatisch
preferences.general.theme.light=Hell
preferences.general.theme.dark=Dunkel
preferences.general.unlockThemes=Dunklen Modus freischalten
preferences.general.showMinimizeButton=Minimieren-Schaltfläche anzeigen
preferences.general.showTrayIcon=Symbol im Infobereich anzeigen (Neustart erforderlich)
preferences.general.startHidden=Cryptomator im Hintergrund starten
preferences.general.debugLogging=Diagnoseprotokoll aktivieren
preferences.general.debugDirectory=Protokolldateien anzeigen
@@ -284,7 +286,7 @@ vaultOptions.mount.mountPoint.directoryPickerButton=Durchsuchen 
vaultOptions.mount.mountPoint.directoryPickerTitle=Wähle ein leeres Verzeichnis
## Master Key
vaultOptions.masterkey=Passwort
vaultOptions.masterkey.changePasswordBtn=Password ändern
vaultOptions.masterkey.changePasswordBtn=Passwort ändern
vaultOptions.masterkey.forgetSavedPasswordBtn=Gespeichertes Passwort vergessen
vaultOptions.masterkey.recoveryKeyExpanation=Bei Verlust deines Passworts ist ein Wiederherstellungsschlüssel deine einzige Möglichkeit, den Zugriff auf einen Tresor wiederherzustellen.
vaultOptions.masterkey.showRecoveryKeyBtn=Wiederherstellungsschlüssel anzeigen

View File

@@ -109,6 +109,7 @@ unlock.error.invalidMountPoint.existing=El punto de montaje/carpeta ya existe o
# Lock
## Force
lock.forced.heading=Bloqueo automático fallido
lock.forced.message=El bloqueo de "%s" fue bloqueado por operaciones pendientes o archivos abiertos. Puede forzar el bloqueo de esta bóveda, sin embargo, interrumpir la I/O puede provocar la pérdida de datos no guardados.
lock.forced.confirmBtn=Forzar bloqueo
## Failure
@@ -148,6 +149,8 @@ preferences.general.theme.automatic=Automático
preferences.general.theme.light=Claro
preferences.general.theme.dark=Oscuro
preferences.general.unlockThemes=Desbloquear el modo oscuro
preferences.general.showMinimizeButton=Mostrar botón minimizar
preferences.general.showTrayIcon=Mostrar icono de bandeja (requiere reiniciar)
preferences.general.startHidden=Ocultar ventana al iniciar Cryptomator
preferences.general.debugLogging=Habilitar registro de depuración
preferences.general.debugDirectory=Revelar archivos de registro

View File

@@ -113,7 +113,7 @@ lock.forced.heading=Le verrouillage normal a échoué
lock.forced.message=Le verrouillage de «%s» a été bloqué par des opérations en attente ou des fichiers ouverts. Vous pouvez forcer le verrouillage de ce coffre, mais l'interruption d'E/S peut entraîner la perte de données non enregistrées.
lock.forced.confirmBtn=Forcer le verrouillage
## Failure
lock.fail.heading=Le verrouillage du coffre-fort a échoué.
lock.fail.heading=Le verrouillage du coffre a échoué.
lock.fail.message=Le coffre-fort "%s" n'a pas pu être verrouillé. Assurez-vous que le travail non sauvegardé est sauvegardé ailleurs et que les opérations importantes de lecture/écriture sont bien terminées. Pour fermer le coffre-fort, tuez le processus Cryptomator.
# Migration
@@ -149,6 +149,8 @@ preferences.general.theme.automatic=Automatique
preferences.general.theme.light=Clair
preferences.general.theme.dark=Sombre
preferences.general.unlockThemes=Débloquer le mode nuit
preferences.general.showMinimizeButton=Afficher le bouton de réduction
preferences.general.showTrayIcon=Afficher l'icône de la barre des tâches (redémarrage requis)
preferences.general.startHidden=Démarrer Cryptomator en mode caché
preferences.general.debugLogging=Activer les logs debug
preferences.general.debugDirectory=Afficher le journal

View File

@@ -17,9 +17,11 @@ generic.error.title=कोई अनपेक्षित त्रुटि ह
generic.error.instruction=ऐसा नहीं होना चाहिए था। कृपया नीचे त्रुटि पाठ की रिपोर्ट करें और इस त्रुटि के लिए क्या कदम उठाए, इसका विवरण शामिल करें।
# Defaults
defaults.vault.vaultName=गुप्त तिजोरी
# Tray Menu
traymenu.showMainWindow=दिखाएँ
traymenu.showPreferencesWindow=प्राथमिकताएं
traymenu.lockAllVaults=सभी को लॉक करें
traymenu.quitApplication=बाहर निकलें
traymenu.vault.unlock=अनलॉक करें
@@ -42,9 +44,21 @@ addvaultwizard.new.locationPrompt=…
addvaultwizard.new.directoryPickerLabel=अपने पसंद की जगह डालें
addvaultwizard.new.directoryPickerButton=चुनें…
addvaultwizard.new.directoryPickerTitle=निर्देशिका चुनें
addvaultwizard.new.fileAlreadyExists=तिजोरी इस रास्ते पर नहीं बनाई जा सकती क्योंकि कुछ वस्तु पहले से मौजूद है।
addvaultwizard.new.locationDoesNotExist=तिजोरी इस रास्ते पर नहीं बनाई जा सकती क्योंकि कम से कम एक पथ घटक मौजूद नहीं है।
addvaultwizard.new.invalidName=अमान्य वॉल्ट नाम। कृपया एक नियमित निर्देशिका नाम पर विचार करें।
### Password
addvaultwizard.new.createVaultBtn=वॉल्ट बनाएं
addvaultwizard.new.generateRecoveryKeyChoice=आप अपने पासवर्ड के बिना अपने डेटा तक नहीं पहुंच पाएंगे। क्या आप उस वक़्त के लिए एक पुनर्प्राप्ति कुंजी चाहते हैं जब आप अपना पासवर्ड खो देते हैं?
addvaultwizard.new.generateRecoveryKeyChoice.yes=हाँ कृपया, पछतावा से बेहतर सुरक्षा
addvaultwizard.new.generateRecoveryKeyChoice.no=नहीं धन्यवाद, मैं अपना पासवर्ड नहीं खोऊंगा
### Information
addvault.new.readme.storageLocation.fileName=IMPORTANT.rtf
addvault.new.readme.storageLocation.1=⚠️ तिजोरी की फ़ाइलें ⚠️
addvault.new.readme.storageLocation.2=यह आपकी तिजोरी का भंडारण स्थान है।
addvault.new.readme.storageLocation.3=ऐसा न करें
addvault.new.readme.storageLocation.4=• इस निर्देशिका के भीतर किसी भी फाइल को बदल दें या
addvault.new.readme.storageLocation.5=• • इस डायरेक्टरी में एन्क्रिप्शन के लिए कोई भी फाइल पेस्ट करें।
## Existing
addvaultwizard.existing.chooseBtn=चुनें…
## Success
@@ -75,6 +89,7 @@ migration.title=वाउल्ट को अपग्रेड करें
## Impossible
# Preferences
preferences.title=प्राथमिकताएं
## General
preferences.general=सामान्य
## Volume
@@ -88,6 +103,7 @@ preferences.general=सामान्य
# Main Window
main.closeBtn.tooltip=बंद करें
main.preferencesBtn.tooltip=प्राथमिकताएं
## Drag 'n' Drop
## Vault List
main.vaultlist.addVaultBtn=वाउल्ट डालें

View File

@@ -0,0 +1,308 @@
# Locale Specific CSS files such as CJK, RTL,...
additionalStyleSheets=
# Generics
## Button
generic.button.apply=Alkalmaz
generic.button.back=Vissza
generic.button.cancel=Mégse
generic.button.change=Változtat
generic.button.close=Bezár
generic.button.copy=Másolás
generic.button.copied=Másolva!
generic.button.done=Kész
generic.button.next=Következő
generic.button.print=Nyomtatás
## Error
generic.error.title=Egy váratlan hiba történt
generic.error.instruction=Ennek nem lett volna szabad megtörténnie. Kérjük jelezze a hibát az alábbi szöveggel valamint a hiba reprodukálásához szükséges lépésekkel.
# Defaults
defaults.vault.vaultName=Széf
# Tray Menu
traymenu.showMainWindow=Megmutatás
traymenu.showPreferencesWindow=Beállítások
traymenu.lockAllVaults=Az összes zárolása
traymenu.quitApplication=Kilépés
traymenu.vault.unlock=Feloldás
traymenu.vault.lock=Zárolás
traymenu.vault.reveal=Megmutatás
# Add Vault Wizard
addvaultwizard.title=Széf hozzáadása
## Welcome
addvaultwizard.welcome.newButton=Új széf létrehozása
addvaultwizard.welcome.existingButton=Meglévő széf megnyitása
## New
### Name
addvaultwizard.new.nameInstruction=Válasszon egy nevet az új széf számára
addvaultwizard.new.namePrompt=A széf neve
### Location
addvaultwizard.new.locationInstruction=Hova mentse a Cryptomator a széf titkosított fájljait?
addvaultwizard.new.locationLabel=Tárolási hely
addvaultwizard.new.locationPrompt=
addvaultwizard.new.directoryPickerLabel=Egyedi hely
addvaultwizard.new.directoryPickerButton=Választás…
addvaultwizard.new.directoryPickerTitle=Könyvtár kiválasztása
addvaultwizard.new.fileAlreadyExists=Nem lehet a széfet létrehozni ezen a helyen, mert egy fájl már létezik itt.
addvaultwizard.new.locationDoesNotExist=Nem lehet a széfet létrehozni ezen a helyen, mert az útvonal legalább egy darabja nem létezik.
addvaultwizard.new.invalidName=Érvénytelen széf elnevezés. Kérjük vegye figyelembe a szabályos könyvtárelnevezésre vonatkozó szabályokat.
### Password
addvaultwizard.new.createVaultBtn=Széf létrehozása
addvaultwizard.new.generateRecoveryKeyChoice=Nem fog tudni hozzáférni az adataihoz a jelszó nélkül. Akar egy visszaállítási kulcsot arra az esetre, ha elveszíti a jelszavát?
addvaultwizard.new.generateRecoveryKeyChoice.yes=Igen kérem, jobb félni, mint megijedni.
addvaultwizard.new.generateRecoveryKeyChoice.no=Nem köszönöm, nem fogom elveszíteni a jelszavam.
### Information
addvault.new.readme.storageLocation.fileName=FONTOS.rtf
addvault.new.readme.storageLocation.1=⚠️ SZÉF FÁJLOK ⚠️
addvault.new.readme.storageLocation.2=Ez a széfjének a tárolási helye.
addvault.new.readme.storageLocation.3=NE
addvault.new.readme.storageLocation.4=• ne módosítson semmilyen fájlt ebbe a könyvtárba
addvault.new.readme.storageLocation.5=• ne tegyen titkosítani való fájlokat ebbe a könyvtárba
addvault.new.readme.storageLocation.6=Ha fájlokat akr titkosítani és a széf tartalmát akarja szerkeszteni akkor tegye a következőt:
addvault.new.readme.storageLocation.7=1. Adja hozzá a széfet a Cryptomator-hoz.
addvault.new.readme.storageLocation.8=2. Nyissa meg a széfet a Cryptomator-ban.
addvault.new.readme.storageLocation.9=3. Nyissa meg a hozzáférési helyet a "Megjelenítés" gombra való kattintással.
addvault.new.readme.storageLocation.10=Ha segítségre van szüksége, akkor látogasson el a dokumentáció oldalára: %s
addvault.new.readme.accessLocation.fileName=ÜDVÖZÖLJÜK.rtf
addvault.new.readme.accessLocation.1=🔐️ TITKOSÍTOTT KÖTET 🔐️
addvault.new.readme.accessLocation.2=Ez a széf hozzáférési helye.
addvault.new.readme.accessLocation.3=Bármilyen, a kötethez hozzáadott fájl titkosításra kerül a Cryptomator által. Úgy dolgozhat vele, mint minden más meghajtóval/mappával. Ez az egyetlen dekódolt tartalmi nézet. A fájlai folyamatosan titkosítva maradnak a merevlemezén.
addvault.new.readme.accessLocation.4=Bátran eltávolíthatja ezt a fájlt.
## Existing
addvaultwizard.existing.instruction=Válassza ki a már létező széfjéhez tartozó "masterkey.cryptomator" fájlt.
addvaultwizard.existing.chooseBtn=Kiválaszt…
addvaultwizard.existing.filePickerTitle=Mesterkulcs fájl kiválasztása
## Success
addvaultwizard.success.nextStepsInstructions=Széf létrehozva "%s".\nA tartalom eléréséhez, vagy hozzáadásához fel kell oldania a széfet. Alternatív megoldásként később bármikor feloldhatja.
addvaultwizard.success.unlockNow=Azonnali feloldás
# Remove Vault
removeVault.title=Széf eltávolitása
removeVault.information=Ez kizárolag a Cryptomator-ból távolitja el ezt a széfet. Később hozzáadhatja újra. A titkosított fájlokat nem törli a merevlemezről.
removeVault.confirmBtn=Széf eltávolitása
# Change Password
changepassword.title=Jelszó megváltoztatása
changepassword.enterOldPassword=Írja be a jelenlegi jelszavat a következő széfhez "%s"
changepassword.finalConfirmation=Megértettem, hogy nem fogok hozzáférni az adataimhoz amennyiben elfelejtem a jelszavam
# Forget Password
forgetPassword.title=Jelszó elfelejtése
forgetPassword.information=Eltávolítja a széf mentett jelszavát a rendszere kulcstartójából.
forgetPassword.confirmBtn=Jelszó elfelejtése
# Unlock
unlock.title=Széf feloldása
unlock.passwordPrompt=Írja be a jelszavát a következő széfhez "%s":
unlock.savePassword=Jelszó mentése
unlock.unlockBtn=Feloldás
## Success
unlock.success.message="%s" sikreresen feloldásra került! Mostmár hozzáférhet a széféhez.
unlock.success.rememberChoice=Jegyezze meg a választást és ne mutassa többet
unlock.success.revealBtn=Széf megjelenítése
## Failure
unlock.error.heading=Nem lehet feloldani a széfet
### Invalid Mount Point
unlock.error.invalidMountPoint.notExisting=A csatolási pont "%s" nem egy könyvtár, nem üres vagy nem létezik.
unlock.error.invalidMountPoint.existing=A csatolási pont "%s" már létezik vagy a already exists or szülőmappa hiányzik.
# Migration
migration.title=Széf frissítése
## Start
migration.start.prompt=A "%s" széf formátuma frissítésre szorul. A folytatás előtt győződjön meg arról, hogy nincs függőben lévő szinkronizálás, amely befolyásolja ezt a széfet.
migration.start.confirm=Igen, a széfem teljes mértékben szinkronizálva van
## Run
migration.run.enterPassword=Írja be a jelszót a következőhöz Enter the password for "%s"
migration.run.startMigrationBtn=Széf migrációja
migration.run.progressHint=Ez eltarthat egy darabig…
## Sucess
migration.success.nextStepsInstructions=A "%s" sikeresen migrálva. \nMost már feloldhatja a széfet.
migration.success.unlockNow=Azonnali feloldás
## Missing file system capabilities
migration.error.missingFileSystemCapabilities.title=Nem támogatott fájlrendszer
migration.error.missingFileSystemCapabilities.description=A migráció nem kezdődött el, mert a széf nem megfelelő fájlrendszeren található.
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=A fájlrendszer nem támogatja a hosszú fájlneveket.
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=A fájlrendszer nem támogatja a hosszú útvonalakat.
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=A fájlrendszer nem teszi lehetővé az olvasást.
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=A fájlrendszer nem teszi lehetővé az írást.
## Impossible
migration.impossible.heading=A széf frissítése sikertelen
migration.impossible.reason=A széfet nem lehet automatikusan frissíteni, mert a tárolási helye vagy a hozzáférési pontja nem kompatibilis.
migration.impossible.moreInfo=A széf továbbra is megnyitható marad egy régebbi verzióval. A széf kézi frissítésével kapcsolatos utasításokért keresse fel a következő címet:
# Preferences
preferences.title=Beállítások
## General
preferences.general=Általános
preferences.general.theme=Megjelenés
preferences.general.theme.automatic=Autómatikus
preferences.general.theme.light=Világos
preferences.general.theme.dark=Sötét
preferences.general.unlockThemes=Sötét mód feloldása
preferences.general.startHidden=Az ablak elrejtése a Cryptomator indítása után
preferences.general.debugLogging=Hibakeresési naplózás engedélyezése
preferences.general.debugDirectory=Naplófájlok megjelenítése
preferences.general.autoStart=Cryptomator indítása a rendszerrel együtt
preferences.general.keychainBackend=Itt tárolja a jelszavakat
preferences.general.keychainBackend.org.cryptomator.linux.keychain.SecretServiceKeychainAccess=Gnome Keyring
preferences.general.keychainBackend.org.cryptomator.linux.keychain.KDEWalletKeychainAccess=KDE Wallet
preferences.general.keychainBackend.org.cryptomator.macos.keychain.MacSystemKeychainAccess=macOS Keychain Access
preferences.general.keychainBackend.org.cryptomator.windows.keychain.WindowsProtectedKeychainAccess=Windows Data Protection
preferences.general.interfaceOrientation=Felhasználói felület orientációja
preferences.general.interfaceOrientation.ltr=Balról jobbra
preferences.general.interfaceOrientation.rtl=Jobbról balra
## Volume
preferences.volume=Virtuális meghajtó
preferences.volume.type=Kötet tipusa
preferences.volume.webdav.port=WebDAV Port
preferences.volume.webdav.scheme=WebDAV Scheme
## Updates
preferences.updates=Frissítések
preferences.updates.currentVersion=Jelenlegi verzió: %s
preferences.updates.autoUpdateCheck=Frissítések autómatikus keresése
preferences.updates.checkNowBtn=Ellenőrzés most
preferences.updates.updateAvailable=Frissítés a %s verzióra elérhető.
## Donation Key
preferences.donationKey=Adomány
preferences.donationKey.registeredFor=Regisztrálva %s számára
preferences.donationKey.noDonationKey=Nem található érvényes adománykulcs. Mint egy licenckulcs, csak olyan nagyszerű emberek számára, akik ingyenes szofvereket használnak. ;-)
preferences.donationKey.getDonationKey=Adománykulcs beszerzése
## About
preferences.about=Rólunk
# Vault Statistics
stats.title=Statisztika ehhez %s
stats.cacheHitRate=Gyorsítótár találati arány
## Read
stats.read.throughput.idle=Olvasás: tétlen
stats.read.throughput.kibs=Olvasás: %.2f kiB/s
stats.read.throughput.mibs=Olvasás: %.2f MiB/s
stats.read.total.data.none=Olvasott adat: -
stats.read.total.data.kib=Olvasott adat: %.1f kiB
stats.read.total.data.mib=Olvasott adat: %.1f MiB
stats.read.total.data.gib=Olvasott adat: %.1f GiB
stats.decr.total.data.none=Dekódolt adat: -
stats.decr.total.data.kib=Dekódolt adat: %.1f kiB
stats.decr.total.data.mib=Dekódolt adat: %.1f MiB
stats.decr.total.data.gib=Dekódolt adat: %.1f GiB
stats.read.accessCount=Összes olvasás: %d
## Write
stats.write.throughput.idle=Írás: tétlen
stats.write.throughput.kibs=Írás: %.2f kiB/s
stats.write.throughput.mibs=Írás: %.2f MiB/s
stats.write.total.data.none=Írott adat: -
stats.write.total.data.kib=Írott adat: %.1f kiB
stats.write.total.data.mib=Írott adat: %.1f MiB
stats.write.total.data.gib=Írott adat: %.1f GiB
stats.encr.total.data.none=Titkosított adat: -
stats.encr.total.data.kib=Titkosított adat: %.1f kiB
stats.encr.total.data.mib=Titkosított adat: %.1f MiB
stats.encr.total.data.gib=Titkosított adat: %.1f GiB
stats.write.accessCount=Összes írás: %d
# Main Window
main.closeBtn.tooltip=Bezárás
main.minimizeBtn.tooltip=Minimalizálás
main.preferencesBtn.tooltip=Beállítások
main.debugModeEnabled.tooltip=A hibakeresési mód aktiválva van
main.donationKeyMissing.tooltip=Kérjük, fontolja meg az adományozást
## Drag 'n' Drop
main.dropZone.dropVault=Adja hozzá ezt a széfet
main.dropZone.unknownDragboardContent=Ha egy széfet szeretne hozzáadni, akkor húzza át erre az ablakra.
## Vault List
main.vaultlist.emptyList.onboardingInstruction=Kattintson ide egy széf hozzáadásához
main.vaultlist.contextMenu.remove=Széf eltávolítása…
main.vaultlist.addVaultBtn=Széf hozzáadása
## Vault Detail
### Welcome
main.vaultDetail.welcomeOnboarding=Köszönjük, hogy a Cryptomator programot választotta a fájlai védelmére. Ha segítségre van szüksége, akkor olvassa el a kezdő útmutatónk lépéseit:
### Locked
main.vaultDetail.lockedStatus=ZÁROLVA
main.vaultDetail.unlockBtn=Feloldás…
main.vaultDetail.unlockNowBtn=Azonnali feloldás
main.vaultDetail.optionsBtn=Széf beállítások
main.vaultDetail.passwordSavedInKeychain=Jelszó mentve
### Unlocked
main.vaultDetail.unlockedStatus=FELOLDVA
main.vaultDetail.accessLocation=A széf tartalma itt érhető el:
main.vaultDetail.revealBtn=Széf megjelenítése
main.vaultDetail.lockBtn=Zárolás
main.vaultDetail.bytesPerSecondRead=Olvasás:
main.vaultDetail.bytesPerSecondWritten=Írás:
main.vaultDetail.throughput.idle=tétlen
main.vaultDetail.throughput.kbps=%.1f kiB/s
main.vaultDetail.throughput.mbps=%.1f MiB/s
main.vaultDetail.stats=Széf statisztika
### Missing
main.vaultDetail.missing.info=A Cryptomator nem talált széfet ezen az útvonalon.
main.vaultDetail.missing.recheck=Ellenőrizze újra
main.vaultDetail.missing.remove=A széf eltávolítása a listából…
main.vaultDetail.missing.changeLocation=A széf helyének megváltoztatása…
### Needs Migration
main.vaultDetail.migrateButton=Széf frissítése
main.vaultDetail.migratePrompt=A széfet új formátumra kell frissíteni, mielőtt hozzáférhet
# Wrong File Alert
wrongFileAlert.title=Hogyan lehet fájlokat titkosítani
wrongFileAlert.header.title=Próbálta ezeket a fájlokat titkosítani?
wrongFileAlert.header.lead=Erre a célra a Cryptomator egy kötetet biztosít a rendszer fájlkezelőjében.
wrongFileAlert.instruction.0=Hogy titkosítsa a fájlokat kövesse a következő lépéseket:
wrongFileAlert.instruction.1=1. Oldja fel a széfet.
wrongFileAlert.instruction.2=2. Kattintson a "Megjelenítés" gombra, hogy megnyissa a kötetet a fájlkezelőjében.
wrongFileAlert.instruction.3=3. Adjon hozzá fájlokat a kötethez.
wrongFileAlert.link=További segítségért látogasson el ide
# Vault Options
## General
vaultOptions.general=Általános
vaultOptions.general.vaultName=A széf neve
vaultOptions.general.unlockAfterStartup=A széf feloldása a Cryptomator indításakor
vaultOptions.general.actionAfterUnlock=Sikeres feloldás után
vaultOptions.general.actionAfterUnlock.ignore=Ne tegyen semmit
vaultOptions.general.actionAfterUnlock.reveal=Jelenítse meg a kötetet
vaultOptions.general.actionAfterUnlock.ask=Kérdezzen
## Mount
vaultOptions.mount=Csatolás
vaultOptions.mount.readonly=Csak olvasható
vaultOptions.mount.customMountFlags=Egyedi csatolási paraméterek
vaultOptions.mount.winDriveLetterOccupied=foglalt
vaultOptions.mount.mountPoint=Csatolási pont
vaultOptions.mount.mountPoint.auto=Válasszon egy megfelelő helyet autómatikusan
vaultOptions.mount.mountPoint.driveLetter=Használja a kiválasztott meghajtó betűjelét
vaultOptions.mount.mountPoint.custom=Egyedi útvonal
vaultOptions.mount.mountPoint.directoryPickerButton=Kiválasztás…
vaultOptions.mount.mountPoint.directoryPickerTitle=Válasszon egy üres könyvtárat
## Master Key
vaultOptions.masterkey=Jelszó
vaultOptions.masterkey.changePasswordBtn=Jelszó megváltoztatása
vaultOptions.masterkey.forgetSavedPasswordBtn=Elmentett jelszó elfelejtése
vaultOptions.masterkey.recoveryKeyExpanation=A helyreállítási kulcs az egyetlen módja annak, hogy visszaállítsa a széfhez való hozzáférést, ha elveíti a jelszavát.
vaultOptions.masterkey.showRecoveryKeyBtn=Visszaállítási kulcs megjelenítése
vaultOptions.masterkey.recoverPasswordBtn=Jelszó visszaállítása
# Recovery Key
recoveryKey.title=Visszaállítási kulcs
recoveryKey.enterPassword.prompt=Írja be a jelszavát a "%s" visszaállítási kulcsának megjelenítéséhez:
recoveryKey.display.message=A következő helyreállítási kulcs használható a "%s" hozzáférésének visszaállítására:
recoveryKey.display.StorageHints=Tartsa nagyon biztonságos helyen. pl.:\n •Tárolja egy jelszókezelővel\n •Mentse el egy USB meghajtóra\n •Nyomtassa egy papírra
recoveryKey.recover.prompt=Írja be a visszaállítási kulcsát a következőhöz "%s":
recoveryKey.recover.validKey=Ez egy érvényes visszaállítási kulcs
recoveryKey.printout.heading=Cryptomator visszaállítási kulcs\n"%s"\n
# New Password
newPassword.promptText=Írja be az új jelszavát
newPassword.reenterPassword=Erősítse meg az új jelszavát
newPassword.passwordsMatch=A jelszavak megegyeznek!
newPassword.passwordsDoNotMatch=A jelszavak nem egyeznek meg
passwordStrength.messageLabel.tooShort=Használjon legalább %d karaktert
passwordStrength.messageLabel.0=Nagyon gyenge
passwordStrength.messageLabel.1=Gyenge
passwordStrength.messageLabel.2=Átlagos
passwordStrength.messageLabel.3=Erős
passwordStrength.messageLabel.4=Nagyon erős
# Quit
quit.prompt=Kilép az alkalmazásból? Vannak még lezáratlan széfek.
quit.lockAndQuit=Zárolás és kilépés

View File

@@ -109,7 +109,12 @@ unlock.error.invalidMountPoint.existing=Il punto di Mount/cartella esiste già o
# Lock
## Force
lock.forced.heading=Blocco normale fallito
lock.forced.message=Il bloccaggio di "%s" è stato impedito da operazioni in sospeso o da file aperti. È possibile forzare il blocco di questa cassaforte, tuttavia interrompere I/O potrebbe causare la perdita di dati non salvati.
lock.forced.confirmBtn=Forza Blocco
## Failure
lock.fail.heading=Blocco cassaforte fallito.
lock.fail.message=Impossibile bloccare la cassaforte "%s". Assicurati che il lavoro non salvato sia salvato ovunque e che le operazioni di Lettura/Scrittura importanti siano concluse. Per chiudere la cassaforte, termina il processo di Cryptomator.
# Migration
migration.title=Aggiorna Cassaforte
@@ -144,6 +149,7 @@ preferences.general.theme.automatic=Automatico
preferences.general.theme.light=Chiaro
preferences.general.theme.dark=Scuro
preferences.general.unlockThemes=Sblocca modalità scura
preferences.general.showMinimizeButton=Mostra pulsante riduci a icona
preferences.general.startHidden=Nascondi la finestra all'avvio di Cryptomator
preferences.general.debugLogging=Abilita i registri di debug
preferences.general.debugDirectory=Mostra file log
@@ -178,9 +184,31 @@ preferences.about=Informazioni
# Vault Statistics
stats.title=Statistiche per %s
## Read
stats.read.throughput.idle=Lettura: inattivo
stats.read.throughput.kibs=Lettura: %.2f kiB/s
stats.read.throughput.mibs=Lettura: %.2f MiB/s
stats.read.total.data.none=Dati letti: -
stats.read.total.data.kib=Dati letti: %.1f kiB
stats.read.total.data.mib=Dati letti: %.1f MiB
stats.read.total.data.gib=Dati letti: %.1f GiB
stats.decr.total.data.none=Dati decriptati: -
stats.decr.total.data.kib=Dati decrittografati: %.1f kiB
stats.decr.total.data.mib=Dati decriptati: %.1f MiB
stats.decr.total.data.gib=Dati decrittografati: %.1f GiB
stats.read.accessCount=Totale lettura: %d
## Write
stats.write.throughput.idle=Scrivi: inattivo
stats.write.throughput.kibs=Scrittura: %.2f kiB/s
stats.write.throughput.mibs=Scrittura: %.2f MiB/s
stats.write.total.data.none=Dati letti: -
stats.write.total.data.kib=Dati scritti: %.1f kiB
stats.write.total.data.mib=Dati scritti: %.1f MiB
stats.write.total.data.gib=Dati scritti: %.1f GiB
stats.encr.total.data.none=Dati crittografati: -
stats.encr.total.data.kib=Dati crittografati: %.1f kiB
stats.encr.total.data.mib=Dati crittografati: %.1f MiB
stats.encr.total.data.gib=Dati crittografati: %.1f GiB
stats.write.accessCount=Totale scritture: %d
# Main Window
main.closeBtn.tooltip=Chiudi
@@ -210,9 +238,11 @@ main.vaultDetail.accessLocation=I contenuti della tua cassaforte sono accessibil
main.vaultDetail.revealBtn=Visualizza disco
main.vaultDetail.lockBtn=Blocca
main.vaultDetail.bytesPerSecondRead=Lettura:
main.vaultDetail.bytesPerSecondWritten=Scrittura:
main.vaultDetail.throughput.idle=inattivo
main.vaultDetail.throughput.kbps=%.1f kiB/s
main.vaultDetail.throughput.mbps=%.1f MiB/s
main.vaultDetail.stats=Statistiche Cassaforte
### Missing
main.vaultDetail.missing.info=Cryptomator non ha potuto trovare una cassaforte in questo percorso.
main.vaultDetail.missing.recheck=Ricontrollare

View File

@@ -105,6 +105,7 @@ unlock.success.revealBtn=金庫を表示
unlock.error.heading=金庫の解錠に失敗
### Invalid Mount Point
unlock.error.invalidMountPoint.notExisting=マウントポイントが空のディレクトリか存在していません: %s
unlock.error.invalidMountPoint.existing=マウント ポイント "%s" が既に存在するか、親フォルダーがありません。
# Lock
## Force
@@ -148,6 +149,8 @@ preferences.general.theme.automatic=自動
preferences.general.theme.light=ライト
preferences.general.theme.dark=ダーク
preferences.general.unlockThemes=ダークモードの解錠
preferences.general.showMinimizeButton=最小化ボタンを表示
preferences.general.showTrayIcon=トレイアイコンを表示 (再起動が必要)
preferences.general.startHidden=Cryptomator を開始したときウィンドウを隠す
preferences.general.debugLogging=ログを有効にする
preferences.general.debugDirectory=ログ ファイルを表示

View File

@@ -109,9 +109,12 @@ unlock.error.invalidMountPoint.existing=Monteringspunktet "%s" finnes enten alle
# Lock
## Force
lock.forced.heading=Låsingen mislyktes
lock.forced.message=Låsing "%s" ble blokkert av ventende operasjoner eller åpne filer. Du kan tvinge låsing av dette hvelvet, men avbrytelse av I/O kan føre til tap av ulagrede data.
lock.forced.confirmBtn=Tving låsing
## Failure
lock.fail.heading=Låsing av hvelvet mislyktes.
lock.fail.message=Hvelvet "%s" kunne ikke låses. Forsikre deg om at ulagrede arbeider lagres andre steder, og at viktige lese/skrive-operasjoner er fullført. For å lukke hvelvet må du avbryte Cryptomatorprosessen.
# Migration
migration.title=Oppgrader hvelv
@@ -146,11 +149,17 @@ preferences.general.theme.automatic=Automatisk
preferences.general.theme.light=Lys
preferences.general.theme.dark=Mørk
preferences.general.unlockThemes=Lås opp mørk modus
preferences.general.showMinimizeButton=Vis minimerknapp
preferences.general.showTrayIcon=Vis verktøykasseikon (krever omstart)
preferences.general.startHidden=Skjul vinduet når du starter Cryptomator
preferences.general.debugLogging=Aktiver loggføring av feilsøk
preferences.general.debugDirectory=Vis loggfiler
preferences.general.autoStart=Start Cryptomator ved systemstart
preferences.general.keychainBackend=Lagre passord med
preferences.general.keychainBackend.org.cryptomator.linux.keychain.SecretServiceKeychainAccess=Gnome Keyring
preferences.general.keychainBackend.org.cryptomator.linux.keychain.KDEWalletKeychainAccess=KDE Wallet
preferences.general.keychainBackend.org.cryptomator.macos.keychain.MacSystemKeychainAccess=macOS nøkkelringtilgang
preferences.general.keychainBackend.org.cryptomator.windows.keychain.WindowsProtectedKeychainAccess=Windows Data Protection
preferences.general.interfaceOrientation=Grensesnittorientering
preferences.general.interfaceOrientation.ltr=Fra venstre til høyre
preferences.general.interfaceOrientation.rtl=Fra høyre til venstre

View File

@@ -45,6 +45,7 @@ addvaultwizard.new.directoryPickerLabel=Andere locatie
addvaultwizard.new.directoryPickerButton=Kies…
addvaultwizard.new.directoryPickerTitle=Selecteer map
addvaultwizard.new.fileAlreadyExists=Er kan op deze locatie geen kluis aangemaakt worden, omdat er een bepaald object bestaat.
addvaultwizard.new.locationDoesNotExist=Er kan geen kluis op dit pad aangemaakt worden omdat ten minste één onderdeel van het pad niet bestaat.
addvaultwizard.new.invalidName=Ongeldige kluisnaam. Overweeg een standaard mapnaam.
### Password
addvaultwizard.new.createVaultBtn=Kluis aanmaken
@@ -98,13 +99,22 @@ unlock.savePassword=Wachtwoord Opslaan
unlock.unlockBtn=Ontgrendel
## Success
unlock.success.message="%s" is met succes ontgrendeld! Uw kluis is nu toegankelijk.
unlock.success.rememberChoice=Keuze onthouden en dit niet opnieuw tonen
unlock.success.revealBtn=Toon kluis
## Failure
unlock.error.heading=Kan kluis niet ontgrendelen
### Invalid Mount Point
unlock.error.invalidMountPoint.notExisting=Koppelpunt "%s" is geen map, is niet leeg of bestaat niet.
unlock.error.invalidMountPoint.existing=Koppelpunt "%s" bestaat reeds of de bovenliggende map ontbreekt.
# Lock
## Force
lock.forced.heading=De kluis kon niet op een gecontroleerde manier vergrendeld worden
lock.forced.message=Het vergrendelen van "%s" werd voorkomen door lopende processen of geopende bestanden. U kunt de vergrendeling op deze kluis forceren, maar dit kan leiden tot het verlies van niet-opgeslagen gegevens.
lock.forced.confirmBtn=Forceer vergrendeling
## Failure
lock.fail.heading=Kluis kan niet vergrendeld worden.
lock.fail.message=Kluis "%s" kan niet vergrendeld worden. Zorg ervoor dat u uw niet-opgeslagen werk ergens anders opslaat en belangrijke lees-/schrijfbewerkingen hebt voltooid. Om de kluis te sluiten, beëindigt u het Cryptomator-proces.
# Migration
migration.title=Kluis upgraden
@@ -114,6 +124,7 @@ migration.start.confirm=Ja, mijn kluis is volledig gesynchroniseerd
## Run
migration.run.enterPassword=Voer wachtwoord voor "%s" in
migration.run.startMigrationBtn=Kluis migreren
migration.run.progressHint=Dit kan enige tijd duren…
## Sucess
migration.success.nextStepsInstructions="%s" is succesvol gemigreerd.\nU kunt nu uw kluis ontgrendelen.
migration.success.unlockNow=Nu Ontgrendelen
@@ -122,17 +133,33 @@ migration.error.missingFileSystemCapabilities.title=Niet ondersteund bestandssys
migration.error.missingFileSystemCapabilities.description=Migratie is niet gestart, omdat uw kluis zich op een niet-adequaat bestandssysteem bevindt.
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=Het bestandssysteem ondersteunt geen lange bestandsnamen.
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=Het bestandssysteem ondersteunt geen lange paden.
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=Het bestandssysteem staat lezen niet toe.
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=Het bestandssysteem staat schrijven niet toe.
## Impossible
migration.impossible.heading=Kluis kan niet gemigreerd worden
migration.impossible.reason=De kluis kan niet automatisch gemigreerd worden omdat de opslaglocatie of het toegangspunt niet compatibel is.
migration.impossible.moreInfo=De kluis is nog te openen met een oudere versie. Instructies voor het handmatig migreren van een kluis zijn te vinden op
# Preferences
preferences.title=Voorkeuren
## General
preferences.general=Algemeen
preferences.general.theme=Uiterlijk
preferences.general.theme.automatic=Automatisch
preferences.general.theme.light=Licht
preferences.general.theme.dark=Donker
preferences.general.unlockThemes=Ontgrendel donkere modus
preferences.general.showMinimizeButton=Knop minimaliseren weergeven
preferences.general.showTrayIcon=Pictogram weergeven in systeemvak (herstart vereist)
preferences.general.startHidden=Verberg venster bij het opstarten van Cryptomator
preferences.general.debugLogging=Debug logging aanzetten
preferences.general.debugDirectory=Logboekbestanden bekijken
preferences.general.autoStart=Start Cryptomator als het systeem opstart
preferences.general.keychainBackend=Bewaar wachtwoorden met
preferences.general.keychainBackend.org.cryptomator.linux.keychain.SecretServiceKeychainAccess=Gnome sleutelhanger
preferences.general.keychainBackend.org.cryptomator.linux.keychain.KDEWalletKeychainAccess=KDE Wallet
preferences.general.keychainBackend.org.cryptomator.macos.keychain.MacSystemKeychainAccess=macOS-sleutelhangertoegang
preferences.general.keychainBackend.org.cryptomator.windows.keychain.WindowsProtectedKeychainAccess=Windows-gegevensbescherming
preferences.general.interfaceOrientation=Interface oriëntatie
preferences.general.interfaceOrientation.ltr=Links naar rechts
preferences.general.interfaceOrientation.rtl=Rechts naar links
@@ -156,13 +183,40 @@ preferences.donationKey.getDonationKey=Verkrijg een donatiesleutel
preferences.about=Over
# Vault Statistics
stats.title=Statistieken voor %s
stats.cacheHitRate=Succespercentage van cache
## Read
stats.read.throughput.idle=Lezen: inactief
stats.read.throughput.kibs=Lezen: %.2f kiB/s
stats.read.throughput.mibs=Lezen: %.2f MiB/s
stats.read.total.data.none=Gegevens gelezen: -
stats.read.total.data.kib=Gegevens gelezen: %.1f kiB
stats.read.total.data.mib=Gegevens gelezen: %.1f MiB
stats.read.total.data.gib=Gegevens gelezen: %.1f GiB
stats.decr.total.data.none=Gegevens ontsleuteld: -
stats.decr.total.data.kib=Gegevens ontsleuteld: %.1f kiB
stats.decr.total.data.mib=Gegevens ontsleuteld: %.1f MiB
stats.decr.total.data.gib=Gegevens ontsleuteld: %.1f GiB
stats.read.accessCount=Totaal gelezen: %d
## Write
stats.write.throughput.idle=Schrijven: inactief
stats.write.throughput.kibs=Schrijven: %.2f kiB/s
stats.write.throughput.mibs=Schrijven: %.2f MiB/s
stats.write.total.data.none=Gegevens gelezen: -
stats.write.total.data.kib=Gegevens geschreven: %.1f kiB
stats.write.total.data.mib=Gegevens geschreven: %.1f MiB
stats.write.total.data.gib=Gegevens geschreven: %.1f GiB
stats.encr.total.data.none=Gegevens versleuteld: -
stats.encr.total.data.kib=Gegevens versleuteld: %.1f kiB
stats.encr.total.data.mib=Gegevens versleuteld: %.1f MiB
stats.encr.total.data.gib=Gegevens versleuteld: %.1f GiB
stats.write.accessCount=Totaal geschreven: %d
# Main Window
main.closeBtn.tooltip=Sluiten
main.minimizeBtn.tooltip=Minimaliseer
main.preferencesBtn.tooltip=Voorkeuren
main.debugModeEnabled.tooltip=Foutopsporingsmodus is ingeschakeld
main.donationKeyMissing.tooltip=Overweeg alstublieft om een donatie te doen
## Drag 'n' Drop
main.dropZone.dropVault=Voeg deze kluis toe
@@ -176,20 +230,26 @@ main.vaultlist.addVaultBtn=Kluis toevoegen
main.vaultDetail.welcomeOnboarding=Bedankt dat u Cryptomator heeft gekozen om uw bestanden te beschermen. Voor assistentie verwijzen we u naar de starthandleidingen:
### Locked
main.vaultDetail.lockedStatus=VERGRENDELD
main.vaultDetail.unlockBtn=Ontgrendelen…
main.vaultDetail.unlockNowBtn=Nu Ontgrendelen
main.vaultDetail.optionsBtn=Kluis-instellingen
main.vaultDetail.passwordSavedInKeychain=Wachtwoord opgeslagen
### Unlocked
main.vaultDetail.unlockedStatus=ONTGRENDELD
main.vaultDetail.accessLocation=De inhoud van uw kluis is hier toegankelijk:
main.vaultDetail.revealBtn=Toon Schijf
main.vaultDetail.lockBtn=Vergrendel
main.vaultDetail.bytesPerSecondRead=Lezen:
main.vaultDetail.bytesPerSecondWritten=Schrijven:
main.vaultDetail.throughput.idle=inactief
main.vaultDetail.throughput.kbps=%.1f kiB/s
main.vaultDetail.throughput.mbps=%.1f MiB/s
main.vaultDetail.stats=Kluisstatistieken
### Missing
main.vaultDetail.missing.info=Cryptomator kon op dit pad geen kluis vinden.
main.vaultDetail.missing.recheck=Controleer nog eens
main.vaultDetail.missing.remove=Verwijderen van kluislijst…
main.vaultDetail.missing.changeLocation=Verander de locatie van de kluis…
### Needs Migration
main.vaultDetail.migrateButton=Kluis upgraden
main.vaultDetail.migratePrompt=Uw kluis moet worden bijgewerkt naar een nieuw formaat, voordat u deze kunt openen
@@ -209,7 +269,10 @@ wrongFileAlert.link=Voor verdere ondersteuning, bezoek
vaultOptions.general=Algemeen
vaultOptions.general.vaultName=Kluisnaam
vaultOptions.general.unlockAfterStartup=Ontgrendel kluis bij het starten van Cryptomator
vaultOptions.general.actionAfterUnlock=Na een succesvolle ontgrendeling
vaultOptions.general.actionAfterUnlock.ignore=Niets doen
vaultOptions.general.actionAfterUnlock.reveal=Toon Schijf
vaultOptions.general.actionAfterUnlock.ask=Vragen
## Mount
vaultOptions.mount=Aankoppelen
vaultOptions.mount.readonly=Alleen-Lezen
@@ -224,6 +287,7 @@ vaultOptions.mount.mountPoint.directoryPickerTitle=Kies een lege map
## Master Key
vaultOptions.masterkey=Wachtwoord
vaultOptions.masterkey.changePasswordBtn=Wijzig wachtwoord
vaultOptions.masterkey.forgetSavedPasswordBtn=Opgeslagen wachtwoord vergeten
vaultOptions.masterkey.recoveryKeyExpanation=Een herstelsleutel is je enige manier om de toegang tot een kluis te herstellen als je je wachtwoord kwijtraakt.
vaultOptions.masterkey.showRecoveryKeyBtn=Toon herstelsleutel
vaultOptions.masterkey.recoverPasswordBtn=Wachtwoord herstellen

View File

@@ -149,6 +149,8 @@ preferences.general.theme.automatic=Automatycznie
preferences.general.theme.light=Jasny
preferences.general.theme.dark=Ciemny
preferences.general.unlockThemes=Odblokuj tryb ciemny
preferences.general.showMinimizeButton=Pokaż przycisk minimalizacji
preferences.general.showTrayIcon=Pokaż ikonę zasobnika (wymaga ponownego uruchomienia)
preferences.general.startHidden=Ukryj okno podczas uruchamiania programu Cryptomator
preferences.general.debugLogging=Włącz logowanie w trybie debug
preferences.general.debugDirectory=Pokaż pliki logowania

View File

@@ -102,13 +102,19 @@ unlock.success.message="%s" foi desbloqueado com sucesso! Seu cofre agora está
unlock.success.rememberChoice=Lembrar opção escolhida, não mostrar isto novamente
unlock.success.revealBtn=Revelar Cofre
## Failure
unlock.error.heading=Não foi possível desbloquear o cofre
### Invalid Mount Point
unlock.error.invalidMountPoint.notExisting=O ponto de montagem não é um diretório vazio ou não existe: %s
unlock.error.invalidMountPoint.existing=Ponto de montagem/pasta já existe ou a pasta pai está faltando: %s
# Lock
## Force
lock.forced.heading=Bloqueio normal falhou
lock.forced.message=Trancar "%s" foi bloqueado por operações pendentes ou arquivos abertos. Você pode forçar o bloqueio deste cofre, no entanto, a interrupção pode resultar em perda de dados não salvos.
lock.forced.confirmBtn=Forçar Bloqueio
## Failure
lock.fail.heading=O bloqueio do cofre falhou.
lock.fail.message=Cofre "%s" não pôde ser bloqueado. Certifique-se de que o trabalho não salvo está salvo em outro lugar e que operações de Leitura/Escrita importantes sejam concluídas. Para fechar o cofre, encerre o processo do Cryptomator.
# Migration
migration.title=Atualizar Cofre
@@ -143,13 +149,17 @@ preferences.general.theme.automatic=Automático
preferences.general.theme.light=Claro
preferences.general.theme.dark=Escuro
preferences.general.unlockThemes=Desbloquear o modo escuro
preferences.general.showMinimizeButton=Mostrar botão minimizar
preferences.general.showTrayIcon=Mostrar ícone na barra do sistema (requer reinicialização)
preferences.general.startHidden=Ocultar janela ao iniciar o Cryptomator
preferences.general.debugLogging=Ativar log de debug
preferences.general.debugDirectory=Mostrar arquivos de log
preferences.general.autoStart=Iniciar o Cryptomator durante inicialização do sistema
preferences.general.keychainBackend=Armazenar senhas no
preferences.general.keychainBackend.org.cryptomator.linux.keychain.SecretServiceKeychainAccess=Keyring do Gnome
preferences.general.keychainBackend.org.cryptomator.linux.keychain.KDEWalletKeychainAccess=Carteira KDE
preferences.general.keychainBackend.org.cryptomator.macos.keychain.MacSystemKeychainAccess=Keychain Access do macOS
preferences.general.keychainBackend.org.cryptomator.windows.keychain.WindowsProtectedKeychainAccess=Proteção de Dados do Windows
preferences.general.interfaceOrientation=Orientação da interface
preferences.general.interfaceOrientation.ltr=Da esquerda para a direita
preferences.general.interfaceOrientation.rtl=Da direita para a esquerda
@@ -173,8 +183,34 @@ preferences.donationKey.getDonationKey=Obtenha uma chave de doação
preferences.about=Sobre
# Vault Statistics
stats.title=Estatísticas para %s
stats.cacheHitRate=Taxa de Utilização do Cache
## Read
stats.read.throughput.idle=Leitura: ociosa
stats.read.throughput.kibs=Leitura: %.2f kiB/s
stats.read.throughput.mibs=Leitura: %.2f MiB/s
stats.read.total.data.none=Dados lidos: -
stats.read.total.data.kib=Dados lidos: %.1f kiB
stats.read.total.data.mib=Dados lidos: %.1f MiB
stats.read.total.data.gib=Dados lidos: %.1f GiB
stats.decr.total.data.none=Dados descriptografados: -
stats.decr.total.data.kib=Dados descriptografados: %.1f kiB
stats.decr.total.data.mib=Dados descriptografados: %.1f MiB
stats.decr.total.data.gib=Dados descriptografados: %.1f GiB
stats.read.accessCount=Total de leituras: %d
## Write
stats.write.throughput.idle=Escrita: ociosa
stats.write.throughput.kibs=Escrita: %.2f kiB/s
stats.write.throughput.mibs=Escrita: %.2f MiB/s
stats.write.total.data.none=Dados lidos: -
stats.write.total.data.kib=Dados gravados: %.1f kiB
stats.write.total.data.mib=Dados gravados: %.1f MiB
stats.write.total.data.gib=Dados gravados: %.1f GiB
stats.encr.total.data.none=Dados criptografados: -
stats.encr.total.data.kib=Dados criptografados: %.1f kiB
stats.encr.total.data.mib=Dados criptografados: %.1f MiB
stats.encr.total.data.gib=Dados criptografados: %.1f GiB
stats.write.accessCount=Total gravado: %d
# Main Window
main.closeBtn.tooltip=Fechar
@@ -204,9 +240,11 @@ main.vaultDetail.accessLocation=O conteúdo do seu cofre está disponível aqui:
main.vaultDetail.revealBtn=Revelar Volume
main.vaultDetail.lockBtn=Bloquear
main.vaultDetail.bytesPerSecondRead=Leitura:
main.vaultDetail.bytesPerSecondWritten=Escrita:
main.vaultDetail.throughput.idle=ocioso
main.vaultDetail.throughput.kbps=%.1f kiB/s
main.vaultDetail.throughput.mbps=%.1f MiB/s
main.vaultDetail.stats=Estatísticas do Cofre
### Missing
main.vaultDetail.missing.info=O Cryptomator não conseguiu encontrar um cofre neste caminho.
main.vaultDetail.missing.recheck=Verificar novamente

View File

@@ -56,8 +56,8 @@ addvaultwizard.new.generateRecoveryKeyChoice.no=Нет, спасибо, я не
addvault.new.readme.storageLocation.fileName=ВАЖНО.rtf
addvault.new.readme.storageLocation.1=⚠️ ФАЙЛЫ ХРАНИЛИЩА ⚠️
addvault.new.readme.storageLocation.2=Это место, где находится ваше хранилище.
addvault.new.readme.storageLocation.3=НЕТ
addvault.new.readme.storageLocation.4=• изменяйте любые файлы в этой папке или
addvault.new.readme.storageLocation.3=НЕЛЬЗЯ
addvault.new.readme.storageLocation.4= изменять любые файлы в этой папке или
addvault.new.readme.storageLocation.5=• добавляйте в эту папку любые файлы для шифрования.
addvault.new.readme.storageLocation.6=Чтобы зашифровать файлы и просмотреть содержимое хранилища, сделайте следующее:
addvault.new.readme.storageLocation.7=1. Добавьте это хранилище в Cryptomator.
@@ -102,19 +102,19 @@ unlock.success.message=Разблокировка "%s" успешно выпол
unlock.success.rememberChoice=Запомнить выбор и больше не спрашивать
unlock.success.revealBtn=Показать хранилище
## Failure
unlock.error.heading=Невозможно разблокировать хранилище
unlock.error.heading=Не удалось разблокировать хранилище
### Invalid Mount Point
unlock.error.invalidMountPoint.notExisting=Точка монтирования %s - не папка, не пуста или не существует.
unlock.error.invalidMountPoint.notExisting=Точка монтирования "%s" не является пустой папкой или не существует.
unlock.error.invalidMountPoint.existing=Точка монтирования %s уже существует, либо отсутствует родительская папка.
# Lock
## Force
lock.forced.heading=Ошибка корректной блокировки
lock.forced.message=Блокировка "%s" была отменена из-за текущих операций или открытых файлов. Вы можете заблокировать это хранилище принудительно, однако прерывание ввода-вывода может привести к потере несохранённых данных.
lock.forced.heading=Не удалось выполнить мягкую блокировку
lock.forced.message=Блокировка "%s" невозможна из-за незавершённых операций или открытых файлов. Вы можете заблокировать это хранилище принудительно, однако прерывание ввода-вывода может привести к потере несохранённых данных.
lock.forced.confirmBtn=Принудительная блокировка
## Failure
lock.fail.heading=Ошибка блокировки хранилища.
lock.fail.message=Хранилище "%s" не удалось заблокировать. Убедитесь, что несохранённая работа сохранена в другом месте и завершены важные операции чтения/записи. Чтобы закрыть хранилище, удалите процесс Cryptomator.
lock.fail.heading=Не удалось заблокировать хранилище.
lock.fail.message=Хранилище "%s" не удалось заблокировать. Убедитесь, что несохранённые данные сохранены в другом месте и завершены важные операции чтения/записи. Чтобы закрыть хранилище, завершите процесс Cryptomator.
# Migration
migration.title=Обновить хранилище
@@ -144,18 +144,20 @@ migration.impossible.moreInfo=Хранилище по-прежнему можн
preferences.title=Настройки
## General
preferences.general=Общие
preferences.general.theme=Тема
preferences.general.theme=Оформление
preferences.general.theme.automatic=Автоматически
preferences.general.theme.light=Светлая
preferences.general.theme.dark=Тёмная
preferences.general.unlockThemes=Разблокировать тёмный режим
preferences.general.showMinimizeButton=Показать кнопку сворачивания
preferences.general.showTrayIcon=Показать значок в панели задач (требуется перезапуск)
preferences.general.startHidden=Скрывать окно при запуске Cryptomator
preferences.general.debugLogging=Вести журнал отладки
preferences.general.debugDirectory=Показать файлы журнала
preferences.general.autoStart=Запускать Cryptomator при старте системы
preferences.general.keychainBackend=Хранить пароли с
preferences.general.keychainBackend=Хранить пароли в
preferences.general.keychainBackend.org.cryptomator.linux.keychain.SecretServiceKeychainAccess=Связка ключей Gnome
preferences.general.keychainBackend.org.cryptomator.linux.keychain.KDEWalletKeychainAccess=Бумажник KDE
preferences.general.keychainBackend.org.cryptomator.linux.keychain.KDEWalletKeychainAccess=Хранилище ключей KDE
preferences.general.keychainBackend.org.cryptomator.macos.keychain.MacSystemKeychainAccess=Доступ к связке ключей macOS
preferences.general.keychainBackend.org.cryptomator.windows.keychain.WindowsProtectedKeychainAccess=Защита данных Windows
preferences.general.interfaceOrientation=Интерфейс
@@ -277,7 +279,7 @@ vaultOptions.mount.readonly=Только чтение
vaultOptions.mount.customMountFlags=Свои флаги монтирования
vaultOptions.mount.winDriveLetterOccupied=занято
vaultOptions.mount.mountPoint=Точка монтирования
vaultOptions.mount.mountPoint.auto=Автоматически выбирать подходящую
vaultOptions.mount.mountPoint.auto=Автоматически выбрать подходящее расположение
vaultOptions.mount.mountPoint.driveLetter=Использовать назначенную букву диска
vaultOptions.mount.mountPoint.custom=Свой путь
vaultOptions.mount.mountPoint.directoryPickerButton=Выбрать…
@@ -312,5 +314,5 @@ passwordStrength.messageLabel.3=Сильный
passwordStrength.messageLabel.4=Очень сильный
# Quit
quit.prompt=Выйти из приложения? Есть разблокированные хранилища.
quit.prompt=Выйти из приложения? Есть незаблокированные хранилища.
quit.lockAndQuit=Заблокировать и выйти

View File

@@ -149,6 +149,8 @@ preferences.general.theme.automatic=Otomatik
preferences.general.theme.light=ık
preferences.general.theme.dark=Koyu
preferences.general.unlockThemes=Koyu modun kilidini aç
preferences.general.showMinimizeButton=Küçültme düğmesini göster
preferences.general.showTrayIcon=Sistem tepsisi simgesini göster (Yeniden başlatma gerekir)
preferences.general.startHidden=Cryptomator'ı başlatırken pencereyi gizle
preferences.general.debugLogging=Hata ayıklama günlüğünü etkinleştir
preferences.general.debugDirectory=Kayıt dosyalarını göster

View File

@@ -95,7 +95,7 @@ forgetPassword.confirmBtn=忘记密码
# Unlock
unlock.title=解锁保险库
unlock.passwordPrompt=输入 "%s" 的密码
unlock.savePassword=保存密码
unlock.savePassword=记住密码
unlock.unlockBtn=解锁
## Success
unlock.success.message=已成功解锁 "%s"! 您现在可以访问该保险库
@@ -149,6 +149,8 @@ preferences.general.theme.automatic=自动
preferences.general.theme.light=亮色
preferences.general.theme.dark=暗色
preferences.general.unlockThemes=解锁暗黑模式
preferences.general.showMinimizeButton=显示最小化按钮
preferences.general.showTrayIcon=显示托盘图标 (需重启)
preferences.general.startHidden=最小化启动 Cryptomator 到系统托盘
preferences.general.debugLogging=启用调试日志
preferences.general.debugDirectory=显示日志文件

View File

@@ -149,6 +149,8 @@ preferences.general.theme.automatic=自動
preferences.general.theme.light=亮色
preferences.general.theme.dark=暗色
preferences.general.unlockThemes=解鎖暗色模式
preferences.general.showMinimizeButton=顯示最小化按鈕
preferences.general.showTrayIcon=顯示系統工作列圖示 (需要重新啟動)
preferences.general.startHidden=啟動 Cryptomator 時隱藏視窗
preferences.general.debugLogging=啟用除錯日誌
preferences.general.debugDirectory=顯示日誌檔

View File

@@ -11,7 +11,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/.
Cryptomator uses 47 third-party dependencies under the following licenses:
Cryptomator uses 46 third-party dependencies under the following licenses:
Apache License v2.0:
- jffi (com.github.jnr:jffi:1.2.23 - http://github.com/jnr/jffi)
- jnr-a64asm (com.github.jnr:jnr-a64asm:1.0.0 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-a64asm)
@@ -26,7 +26,6 @@ Cryptomator uses 47 third-party dependencies under the following licenses:
- Guava ListenableFuture only (com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava - https://github.com/google/guava/listenablefuture)
- J2ObjC Annotations (com.google.j2objc:j2objc-annotations:1.3 - https://github.com/google/j2objc/)
- Apache Commons CLI (commons-cli:commons-cli:1.4 - http://commons.apache.org/proper/commons-cli/)
- Apache Commons IO (commons-io:commons-io:2.6 - http://commons.apache.org/proper/commons-io/)
- javax.inject (javax.inject:javax.inject:1 - http://code.google.com/p/atinject/)
- Java Native Access (net.java.dev.jna:jna:5.6.0 - https://github.com/java-native-access/jna)
- Java Native Access Platform (net.java.dev.jna:jna-platform:5.5.0 - https://github.com/java-native-access/jna)
@@ -73,7 +72,7 @@ Cryptomator uses 47 third-party dependencies under the following licenses:
- Java Native Access (net.java.dev.jna:jna:5.6.0 - https://github.com/java-native-access/jna)
- Java Native Access Platform (net.java.dev.jna:jna-platform:5.5.0 - https://github.com/java-native-access/jna)
MIT License:
- java jwt (com.auth0:java-jwt:3.11.0 - https://github.com/auth0/java-jwt)
- java jwt (com.auth0:java-jwt:3.12.0 - https://github.com/auth0/java-jwt)
- jnr-x86asm (com.github.jnr:jnr-x86asm:1.0.2 - http://github.com/jnr/jnr-x86asm)
- jnr-fuse (com.github.serceman:jnr-fuse:0.5.4 - no url defined)
- zxcvbn4j (com.nulab-inc:zxcvbn:1.3.0 - https://github.com/nulab/zxcvbn4j)