~exprez135/cryptomator-libre

94af8bd15a20031ecd73283f5eb933cdea8102ff — Sebastian Stenzel 1 year, 4 months ago 8db889d + 4712c4f 1.5.2
Merge branch 'release/1.5.2'
53 files changed, 647 insertions(+), 203 deletions(-)

M .github/workflows/build.yml
M .idea/compiler.xml
M .idea/runConfigurations/Cryptomator_macOS.xml
M README.md
M main/buildkit/pom.xml
M main/commons/pom.xml
M main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java
M main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java
M main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java
M main/commons/src/main/java/org/cryptomator/common/vaults/VaultListManager.java
M main/commons/src/main/java/org/cryptomator/common/vaults/VaultStats.java
M main/commons/src/main/java/org/cryptomator/common/vaults/Volume.java
M main/commons/src/main/java/org/cryptomator/common/vaults/WindowsDriveLetters.java
M main/keychain/pom.xml
M main/launcher/pom.xml
M main/pom.xml
M main/ui/pom.xml
M main/ui/src/main/java/org/cryptomator/ui/common/FxmlFile.java
M main/ui/src/main/java/org/cryptomator/ui/controls/SecurePasswordField.java
M main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailController.java
M main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListCellController.java
M main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java
A main/ui/src/main/java/org/cryptomator/ui/migration/MigrationImpossibleController.java
M main/ui/src/main/java/org/cryptomator/ui/migration/MigrationModule.java
M main/ui/src/main/java/org/cryptomator/ui/migration/MigrationRunController.java
M main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesController.java
M main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayImageFactory.java
M main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java
M main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java
M main/ui/src/main/resources/css/dark_theme.css
M main/ui/src/main/resources/css/light_theme.css
A main/ui/src/main/resources/fxml/migration_impossible.fxml
M main/ui/src/main/resources/fxml/migration_run.fxml
M main/ui/src/main/resources/fxml/unlock.fxml
M main/ui/src/main/resources/i18n/strings.properties
M main/ui/src/main/resources/i18n/strings_ca.properties
M main/ui/src/main/resources/i18n/strings_cs.properties
M main/ui/src/main/resources/i18n/strings_de.properties
M main/ui/src/main/resources/i18n/strings_es.properties
M main/ui/src/main/resources/i18n/strings_fr.properties
M main/ui/src/main/resources/i18n/strings_it.properties
M main/ui/src/main/resources/i18n/strings_ja.properties
M main/ui/src/main/resources/i18n/strings_lv.properties
M main/ui/src/main/resources/i18n/strings_nb.properties
M main/ui/src/main/resources/i18n/strings_nn.properties
M main/ui/src/main/resources/i18n/strings_pt_BR.properties
M main/ui/src/main/resources/i18n/strings_ru.properties
A main/ui/src/main/resources/i18n/strings_sk.properties
M main/ui/src/main/resources/i18n/strings_sv.properties
M main/ui/src/main/resources/i18n/strings_tr.properties
M main/ui/src/main/resources/i18n/strings_zh.properties
M main/ui/src/main/resources/i18n/strings_zh_TW.properties
M main/ui/src/main/resources/license/THIRD-PARTY.txt
M .github/workflows/build.yml => .github/workflows/build.yml +12 -30
@@ 4,25 4,24 @@ on:
  [push]

jobs: 
  test:
    name: Run Tests
  build:
    name: Build and Test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK 14
        uses: actions/setup-java@v1
      - uses: actions/setup-java@v1
        with:
          java-version: 14
      - uses: actions/cache@v1
        with:
          path: ~/.m2/repository
          key: ${{ runner.os }}-maven-${{ github.run_id }}
          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
          restore-keys: |
            ${{ runner.os }}-maven-
      - name: Ensure to use tagged version
        run: mvn versions:set --file main/pom.xml -DnewVersion=${GITHUB_REF##*/} # use shell parameter expansion to strip of 'refs/tags'
        if: startsWith(github.ref, 'refs/tags/')
      - name: Build with Maven
      - name: Build and Test
        run: mvn -B install --file main/pom.xml -Pcoverage
      - name: Run Codacy Coverage Reporter
        run: |


@@ 34,25 33,7 @@ jobs:
          $JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter.jar final
        env:
          CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }}
          
  assemble-build-kit:
    name: Assemble Build Kit
    runs-on: ubuntu-latest
    needs: test
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK 14
        uses: actions/setup-java@v1
        with:
          java-version: 14
      - uses: actions/cache@v1
        with:
          path: ~/.m2/repository
          key: ${{ runner.os }}-maven-${{ github.run_id }}
      - name: Ensure to use tagged version
        run: mvn versions:set --file main/pom.xml -DnewVersion=${GITHUB_REF##*/} # use shell parameter expansion to strip of 'refs/tags'
        if: startsWith(github.ref, 'refs/tags/')
      - name: Build with Maven
      - name: Assemble Buildkit
        run: mvn -B package -DskipTests --file main/pom.xml --resume-from=buildkit -Prelease
      - name: Upload buildkit-linux.zip
        uses: actions/upload-artifact@v1


@@ 70,10 51,10 @@ jobs:
          name: buildkit-win.zip
          path: main/buildkit/target/buildkit-win.zip
          
  github-release:
  release:
    name: Draft a Release on GitHub Releases
    runs-on: ubuntu-latest
    needs: assemble-build-kit
    needs: build
    if: startsWith(github.ref, 'refs/tags/')
    steps:
      - name: Download buildkit-linux.zip


@@ 91,7 72,8 @@ jobs:
        with:
          name: buildkit-win.zip
          path: .
      - id: create_release
      - name: Create Release
        id: create_release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}


@@ 99,9 81,9 @@ jobs:
          tag_name: ${{ github.ref }}
          release_name: ${{ github.ref }}
          body: |
            TODO
            :construction: Work in Progress
          draft: true
          prerelease: true
          prerelease: false
      - name: Upload buildkit-linux.zip to GitHub Releases
        uses: actions/upload-release-asset@v1.0.1
        env:

M .idea/compiler.xml => .idea/compiler.xml +1 -1
@@ 32,9 32,9 @@
          <entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-metadata-jvm/0.1.0/kotlinx-metadata-jvm-0.1.0.jar" />
        </processorPath>
        <module name="keychain" />
        <module name="launcher" />
        <module name="commons" />
        <module name="ui" />
        <module name="launcher" />
      </profile>
    </annotationProcessing>
  </component>

M .idea/runConfigurations/Cryptomator_macOS.xml => .idea/runConfigurations/Cryptomator_macOS.xml +3 -0
@@ 1,5 1,8 @@
<component name="ProjectRunConfigurationManager">
  <configuration default="false" name="Cryptomator macOS" type="Application" factoryName="Application">
    <envs>
      <env name="LD_LIBRARY_PATH" value="/usr/local/lib" />
    </envs>
    <option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
    <module name="launcher" />
    <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />

M README.md => README.md +3 -3
@@ 1,6 1,6 @@
[![cryptomator](cryptomator.png)](https://cryptomator.org/)

[![Build Status](https://travis-ci.org/cryptomator/cryptomator.svg?branch=master)](https://travis-ci.org/cryptomator/cryptomator)
[![Build](https://github.com/cryptomator/cryptomator/workflows/Build/badge.svg)](https://github.com/cryptomator/cryptomator/actions?query=workflow%3ABuild)
[![Known Vulnerabilities](https://snyk.io/test/github/cryptomator/cryptomator/badge.svg?targetFile=main%2Fpom.xml)](https://snyk.io/test/github/cryptomator/cryptomator?targetFile=main%2Fpom.xml)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/2a0adf3cec6a4143b91035d3924178f1)](https://www.codacy.com/app/cryptomator/cryptomator?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=cryptomator/cryptomator&amp;utm_campaign=Badge_Grade)
[![Twitter](https://img.shields.io/badge/twitter-@Cryptomator-blue.svg?style=flat)](http://twitter.com/Cryptomator)


@@ 41,7 41,7 @@ Download native binaries of Cryptomator on [cryptomator.org](https://cryptomator
- File names get encrypted
- Folder structure gets obfuscated
- Use as many vaults in your Dropbox as you want, each having individual passwords
- One thousand commits for the security of your data!! :tada:
- Two thousand commits for the security of your data!! :tada:

### Privacy



@@ 65,7 65,7 @@ For more information on the security details visit [cryptomator.org](https://doc

### Dependencies

* JDK 11 (we recommend to use the latest version)
* JDK 14 (e.g. adoptopenjdk)
* Maven 3
* Optional: OS-dependent build tools for native packaging (see [Windows](https://github.com/cryptomator/cryptomator-win), [OS X](https://github.com/cryptomator/cryptomator-osx), [Linux](https://github.com/cryptomator/builder-containers))


M main/buildkit/pom.xml => main/buildkit/pom.xml +1 -1
@@ 4,7 4,7 @@
	<parent>
		<groupId>org.cryptomator</groupId>
		<artifactId>main</artifactId>
		<version>1.5.1</version>
		<version>1.5.2</version>
	</parent>
	<artifactId>buildkit</artifactId>
	<packaging>pom</packaging>

M main/commons/pom.xml => main/commons/pom.xml +1 -1
@@ 4,7 4,7 @@
	<parent>
		<groupId>org.cryptomator</groupId>
		<artifactId>main</artifactId>
		<version>1.5.1</version>
		<version>1.5.2</version>
	</parent>
	<artifactId>commons</artifactId>
	<name>Cryptomator Commons</name>

M main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java => main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java +9 -6
@@ 9,23 9,20 @@ import com.google.common.base.Strings;
import com.google.common.io.BaseEncoding;
import javafx.beans.Observable;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import org.apache.commons.lang3.StringUtils;
import org.fxmisc.easybind.EasyBind;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Base64;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Random;
import java.util.UUID;

/**
 * The settings specific to a single vault.


@@ 38,6 35,7 @@ public class VaultSettings {
	public static final boolean DEFAULT_USES_INDIVIDUAL_MOUNTPATH = false;
	public static final boolean DEFAULT_USES_READONLY_MODE = false;
	public static final String DEFAULT_MOUNT_FLAGS = "";
	public static final int DEFAULT_FILENAME_LENGTH_LIMIT = -1;
	
	private static final Random RNG = new Random(); 



@@ 51,6 49,7 @@ public class VaultSettings {
	private final StringProperty individualMountPath = new SimpleStringProperty();
	private final BooleanProperty usesReadOnlyMode = new SimpleBooleanProperty(DEFAULT_USES_READONLY_MODE);
	private final StringProperty mountFlags = new SimpleStringProperty(DEFAULT_MOUNT_FLAGS);
	private final IntegerProperty filenameLengthLimit = new SimpleIntegerProperty(DEFAULT_FILENAME_LENGTH_LIMIT);

	public VaultSettings(String id) {
		this.id = Objects.requireNonNull(id);


@@ 59,7 58,7 @@ public class VaultSettings {
	}

	Observable[] observables() {
		return new Observable[]{path, mountName, winDriveLetter, unlockAfterStartup, revealAfterMount, usesIndividualMountPath, individualMountPath, usesReadOnlyMode, mountFlags};
		return new Observable[]{path, mountName, winDriveLetter, unlockAfterStartup, revealAfterMount, usesIndividualMountPath, individualMountPath, usesReadOnlyMode, mountFlags, filenameLengthLimit};
	}

	private void deriveMountNameFromPath(Path path) {


@@ 146,6 145,10 @@ public class VaultSettings {
	public StringProperty mountFlags() {
		return mountFlags;
	}
	
	public IntegerProperty filenameLengthLimit() {
		return filenameLengthLimit;
	}

	/* Hashcode/Equals */


M main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java => main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java +6 -0
@@ 29,6 29,7 @@ class VaultSettingsJsonAdapter {
		out.name("individualMountPath").value(value.individualMountPath().get());
		out.name("usesReadOnlyMode").value(value.usesReadOnlyMode().get());
		out.name("mountFlags").value(value.mountFlags().get());
		out.name("filenameLengthLimit").value(value.filenameLengthLimit().get());
		out.endObject();
	}



@@ 43,6 44,7 @@ class VaultSettingsJsonAdapter {
		boolean usesIndividualMountPath = VaultSettings.DEFAULT_USES_INDIVIDUAL_MOUNTPATH;
		boolean usesReadOnlyMode = VaultSettings.DEFAULT_USES_READONLY_MODE;
		String mountFlags = VaultSettings.DEFAULT_MOUNT_FLAGS;
		int filenameLengthLimit = VaultSettings.DEFAULT_FILENAME_LENGTH_LIMIT;

		in.beginObject();
		while (in.hasNext()) {


@@ 78,6 80,9 @@ class VaultSettingsJsonAdapter {
				case "mountFlags":
					mountFlags = in.nextString();
					break;
				case "filenameLengthLimit":
					filenameLengthLimit = in.nextInt();
					break;
				default:
					LOG.warn("Unsupported vault setting found in JSON: " + name);
					in.skipValue();


@@ 96,6 101,7 @@ class VaultSettingsJsonAdapter {
		vaultSettings.individualMountPath().set(individualMountPath);
		vaultSettings.usesReadOnlyMode().set(usesReadOnlyMode);
		vaultSettings.mountFlags().set(mountFlags);
		vaultSettings.filenameLengthLimit().set(filenameLengthLimit);
		return vaultSettings;
	}


M main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java => main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java +11 -0
@@ 21,6 21,8 @@ import org.cryptomator.cryptofs.CryptoFileSystem;
import org.cryptomator.cryptofs.CryptoFileSystemProperties;
import org.cryptomator.cryptofs.CryptoFileSystemProperties.FileSystemFlags;
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
import org.cryptomator.cryptofs.common.Constants;
import org.cryptomator.cryptofs.common.FileSystemCapabilityChecker;
import org.cryptomator.cryptolib.api.CryptoException;
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
import org.slf4j.Logger;


@@ 101,10 103,19 @@ public class Vault {
		if (vaultSettings.usesReadOnlyMode().get()) {
			flags.add(FileSystemFlags.READONLY);
		}
		if (vaultSettings.filenameLengthLimit().get() == -1) {
			LOG.debug("Determining file name length limitations...");
			int limit = new FileSystemCapabilityChecker().determineSupportedFileNameLength(getPath());
			vaultSettings.filenameLengthLimit().set(limit);
			LOG.info("Storing file name length limit of {}", limit);
		}
		assert vaultSettings.filenameLengthLimit().get() > 0;
		CryptoFileSystemProperties fsProps = CryptoFileSystemProperties.cryptoFileSystemProperties() //
				.withPassphrase(passphrase) //
				.withFlags(flags) //
				.withMasterkeyFilename(MASTERKEY_FILENAME) //
				.withMaxPathLength(vaultSettings.filenameLengthLimit().get() + Constants.MAX_ADDITIONAL_PATH_LENGTH) //
				.withMaxNameLength(vaultSettings.filenameLengthLimit().get()) //
				.build();
		return CryptoFileSystemProvider.newFileSystem(getPath(), fsProps);
	}

M main/commons/src/main/java/org/cryptomator/common/vaults/VaultListManager.java => main/commons/src/main/java/org/cryptomator/common/vaults/VaultListManager.java +10 -11
@@ 51,15 51,16 @@ public class VaultListManager {
	}

	public Vault add(Path pathToVault) throws NoSuchFileException {
		if (!CryptoFileSystemProvider.containsVault(pathToVault, MASTERKEY_FILENAME)) {
			throw new NoSuchFileException(pathToVault.toString(), null, "Not a vault directory");
		Path normalizedPathToVault = pathToVault.normalize().toAbsolutePath();
		if (!CryptoFileSystemProvider.containsVault(normalizedPathToVault, MASTERKEY_FILENAME)) {
			throw new NoSuchFileException(normalizedPathToVault.toString(), null, "Not a vault directory");
		}
		Optional<Vault> alreadyExistingVault = get(pathToVault);
		Optional<Vault> alreadyExistingVault = get(normalizedPathToVault);
		if (alreadyExistingVault.isPresent()) {
			return alreadyExistingVault.get();
		} else {
			VaultSettings vaultSettings = VaultSettings.withRandomId();
			vaultSettings.path().set(pathToVault);
			vaultSettings.path().set(normalizedPathToVault);
			Vault newVault = create(vaultSettings);
			vaultList.add(newVault);
			return newVault;


@@ 72,13 73,11 @@ public class VaultListManager {
	}

	private Optional<Vault> get(Path vaultPath) {
		return vaultList.stream().filter(v -> {
			try {
				return Files.isSameFile(vaultPath, v.getPath());
			} catch (IOException e) {
				return false;
			}
		}).findAny();
		assert vaultPath.isAbsolute();
		assert vaultPath.normalize().equals(vaultPath);
		return vaultList.stream() //
				.filter(v -> vaultPath.equals(v.getPath())) //
				.findAny();
	}

	private Vault create(VaultSettings vaultSettings) {

M main/commons/src/main/java/org/cryptomator/common/vaults/VaultStats.java => main/commons/src/main/java/org/cryptomator/common/vaults/VaultStats.java +7 -10
@@ 41,16 41,13 @@ public class VaultStats {
	}

	private void vaultStateChanged(@SuppressWarnings("unused") Observable observable) {
		switch (state.get()) {
			case UNLOCKED:
				assert fs.get() != null;
				LOG.debug("start recording stats");
				updateService.restart();
				break;
			default:
				LOG.debug("stop recording stats");
				updateService.cancel();
				break;
		if (VaultState.UNLOCKED.equals(state.get())) {
			assert fs.get() != null;
			LOG.debug("start recording stats");
			updateService.restart();
		} else {
			LOG.debug("stop recording stats");
			updateService.cancel();
		}
	}


M main/commons/src/main/java/org/cryptomator/common/vaults/Volume.java => main/commons/src/main/java/org/cryptomator/common/vaults/Volume.java +4 -11
@@ 43,17 43,10 @@ public interface Volume {
	}

	static VolumeImpl[] getCurrentSupportedAdapters() {
		return Stream.of(VolumeImpl.values()).filter(impl -> {
			switch (impl) {
				case WEBDAV:
					return WebDavVolume.isSupportedStatic();
				case DOKANY:
					return DokanyVolume.isSupportedStatic();
				case FUSE:
					return FuseVolume.isSupportedStatic();
				default:
					return false;//throw new IllegalStateException("Adapter not implemented.");
			}
		return Stream.of(VolumeImpl.values()).filter(impl -> switch (impl) {
			case WEBDAV -> WebDavVolume.isSupportedStatic();
			case DOKANY -> DokanyVolume.isSupportedStatic();
			case FUSE -> FuseVolume.isSupportedStatic();
		}).toArray(VolumeImpl[]::new);
	}


M main/commons/src/main/java/org/cryptomator/common/vaults/WindowsDriveLetters.java => main/commons/src/main/java/org/cryptomator/common/vaults/WindowsDriveLetters.java +6 -9
@@ 7,8 7,6 @@ package org.cryptomator.common.vaults;

import com.google.common.collect.Sets;
import org.apache.commons.lang3.SystemUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import javax.inject.Singleton;


@@ 22,12 20,11 @@ import java.util.stream.StreamSupport;
@Singleton
public final class WindowsDriveLetters {

	private static final Logger LOG = LoggerFactory.getLogger(WindowsDriveLetters.class);
	private static final Set<String> A_TO_Z;
	private static final Set<String> C_TO_Z;

	static {
		try (IntStream stream = IntStream.rangeClosed('A', 'Z')) {
			A_TO_Z = stream.mapToObj(i -> String.valueOf((char) i)).collect(Collectors.toSet());
		try (IntStream stream = IntStream.rangeClosed('C', 'Z')) {
			C_TO_Z = stream.mapToObj(i -> String.valueOf((char) i)).collect(Collectors.toSet());
		}
	}



@@ 36,7 33,7 @@ public final class WindowsDriveLetters {
	}

	public Set<String> getAllDriveLetters() {
		return A_TO_Z;
		return C_TO_Z;
	}

	public Set<String> getOccupiedDriveLetters() {


@@ 44,12 41,12 @@ public final class WindowsDriveLetters {
			return Set.of();
		} else {
			Iterable<Path> rootDirs = FileSystems.getDefault().getRootDirectories();
			return StreamSupport.stream(rootDirs.spliterator(), false).map(p -> p.toString().substring(0,1)).collect(Collectors.toSet());
			return StreamSupport.stream(rootDirs.spliterator(), false).map(p -> p.toString().substring(0, 1)).collect(Collectors.toSet());
		}
	}

	public Set<String> getAvailableDriveLetters() {
		return Sets.difference(A_TO_Z, getOccupiedDriveLetters());
		return Sets.difference(C_TO_Z, getOccupiedDriveLetters());
	}

}

M main/keychain/pom.xml => main/keychain/pom.xml +1 -1
@@ 4,7 4,7 @@
	<parent>
		<groupId>org.cryptomator</groupId>
		<artifactId>main</artifactId>
		<version>1.5.1</version>
		<version>1.5.2</version>
	</parent>
	<artifactId>keychain</artifactId>
	<name>System Keychain Access</name>

M main/launcher/pom.xml => main/launcher/pom.xml +1 -1
@@ 4,7 4,7 @@
	<parent>
		<groupId>org.cryptomator</groupId>
		<artifactId>main</artifactId>
		<version>1.5.1</version>
		<version>1.5.2</version>
	</parent>
	<artifactId>launcher</artifactId>
	<name>Cryptomator Launcher</name>

M main/pom.xml => main/pom.xml +4 -4
@@ 3,7 3,7 @@
	<modelVersion>4.0.0</modelVersion>
	<groupId>org.cryptomator</groupId>
	<artifactId>main</artifactId>
	<version>1.5.1</version>
	<version>1.5.2</version>
	<packaging>pom</packaging>
	<name>Cryptomator</name>



@@ 24,11 24,11 @@
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

		<!-- cryptomator dependencies -->
		<cryptomator.cryptofs.version>1.9.7</cryptomator.cryptofs.version>
		<cryptomator.cryptofs.version>1.9.9</cryptomator.cryptofs.version>
		<cryptomator.jni.version>2.2.2</cryptomator.jni.version>
		<cryptomator.fuse.version>1.2.3</cryptomator.fuse.version>
		<cryptomator.dokany.version>1.1.13</cryptomator.dokany.version>
		<cryptomator.webdav.version>1.0.10</cryptomator.webdav.version>
		<cryptomator.dokany.version>1.1.14</cryptomator.dokany.version>
		<cryptomator.webdav.version>1.0.11</cryptomator.webdav.version>

		<!-- 3rd party dependencies -->
		<javafx.version>14</javafx.version>

M main/ui/pom.xml => main/ui/pom.xml +1 -1
@@ 4,7 4,7 @@
	<parent>
		<groupId>org.cryptomator</groupId>
		<artifactId>main</artifactId>
		<version>1.5.1</version>
		<version>1.5.2</version>
	</parent>
	<artifactId>ui</artifactId>
	<name>Cryptomator GUI</name>

M main/ui/src/main/java/org/cryptomator/ui/common/FxmlFile.java => main/ui/src/main/java/org/cryptomator/ui/common/FxmlFile.java +1 -0
@@ 13,6 13,7 @@ public enum FxmlFile {
	FORGET_PASSWORD("/fxml/forget_password.fxml"), //
	MAIN_WINDOW("/fxml/main_window.fxml"), //
	MIGRATION_CAPABILITY_ERROR("/fxml/migration_capability_error.fxml"), //
	MIGRATION_IMPOSSIBLE("/fxml/migration_impossible.fxml"),
	MIGRATION_RUN("/fxml/migration_run.fxml"), //
	MIGRATION_START("/fxml/migration_start.fxml"), //
	MIGRATION_SUCCESS("/fxml/migration_success.fxml"), //

M main/ui/src/main/java/org/cryptomator/ui/controls/SecurePasswordField.java => main/ui/src/main/java/org/cryptomator/ui/controls/SecurePasswordField.java +9 -6
@@ 22,6 22,8 @@ import javafx.scene.control.TextField;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.TransferMode;



@@ 43,6 45,7 @@ public class SecurePasswordField extends TextField {
	private static final int GROW_BUFFER_SIZE = 50;
	private static final String DEFAULT_PLACEHOLDER = "●";
	private static final String STYLE_CLASS = "secure-password-field";
	private static final KeyCodeCombination SHORTCUT_BACKSPACE = new KeyCodeCombination(KeyCode.BACK_SPACE, KeyCombination.SHORTCUT_DOWN);

	private final String placeholderChar;
	private final BooleanProperty capsLocked = new SimpleBooleanProperty();


@@ 74,12 77,10 @@ public class SecurePasswordField extends TextField {
	}

	public Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters) {
		switch(attribute) {
			case TEXT:
				return null;
			default:
				return super.queryAccessibleAttribute(attribute, parameters);
		}
		return switch (attribute) {
			case TEXT -> null;
			default -> super.queryAccessibleAttribute(attribute, parameters);
		};
	}

	private void handleDragOver(DragEvent event) {


@@ 101,6 102,8 @@ public class SecurePasswordField extends TextField {
	private void handleKeyEvent(KeyEvent e) {
		if (e.getCode() == KeyCode.CAPS) {
			updateCapsLocked();
		} else if (SHORTCUT_BACKSPACE.match(e)) {
			swipe();
		}
	}


M main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailController.java => main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailController.java +6 -10
@@ 31,16 31,12 @@ public class VaultDetailController implements FxController {
	}

	private FontAwesome5Icon getGlyphForVaultState(VaultState state) {
		switch (state) {
			case LOCKED:
				return FontAwesome5Icon.LOCK;
			case PROCESSING:
				return FontAwesome5Icon.SPINNER;
			case UNLOCKED:
				return FontAwesome5Icon.LOCK_OPEN;
			default:
				return FontAwesome5Icon.EXCLAMATION_TRIANGLE;
		}
		return switch (state) {
			case LOCKED -> FontAwesome5Icon.LOCK;
			case PROCESSING -> FontAwesome5Icon.SPINNER;
			case UNLOCKED -> FontAwesome5Icon.LOCK_OPEN;
			case NEEDS_MIGRATION, MISSING, ERROR -> FontAwesome5Icon.EXCLAMATION_TRIANGLE;
		};
	}

	@FXML

M main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListCellController.java => main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListCellController.java +7 -11
@@ 3,9 3,9 @@ package org.cryptomator.ui.mainwindow;
import javafx.beans.binding.Binding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.controls.FontAwesome5Icon;
import org.fxmisc.easybind.EasyBind;



@@ 23,16 23,12 @@ public class VaultListCellController implements FxController {
	}

	private FontAwesome5Icon getGlyphForVaultState(VaultState state) {
		switch (state) {
			case LOCKED:
				return FontAwesome5Icon.LOCK;
			case PROCESSING:
				return FontAwesome5Icon.SPINNER;
			case UNLOCKED:
				return FontAwesome5Icon.LOCK_OPEN;
			default:
				return FontAwesome5Icon.EXCLAMATION_TRIANGLE;
		}
		return switch (state) {
			case LOCKED -> FontAwesome5Icon.LOCK;
			case PROCESSING -> FontAwesome5Icon.SPINNER;
			case UNLOCKED -> FontAwesome5Icon.LOCK_OPEN;
			case NEEDS_MIGRATION, MISSING, ERROR -> FontAwesome5Icon.EXCLAMATION_TRIANGLE;
		};
	}

	/* Getter/Setter */

M main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java => main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java +3 -8
@@ 66,9 66,7 @@ public class VaultListController implements FxController {
		}
		VaultState reportedState = newValue.getState();
		switch (reportedState) {
			case LOCKED:
			case NEEDS_MIGRATION:
			case MISSING:
			case LOCKED, NEEDS_MIGRATION, MISSING:
				try {
					VaultState determinedState = VaultListManager.determineVaultState(newValue.getPath());
					newValue.setState(determinedState);


@@ 78,11 76,8 @@ public class VaultListController implements FxController {
					newValue.setLastKnownException(e);
				}
				break;
			case ERROR:
			case UNLOCKED:
			case PROCESSING:
			default:
				// no-op
			case ERROR, UNLOCKED, PROCESSING:
				break; // no-op
		}
	}


A main/ui/src/main/java/org/cryptomator/ui/migration/MigrationImpossibleController.java => main/ui/src/main/java/org/cryptomator/ui/migration/MigrationImpossibleController.java +46 -0
@@ 0,0 1,46 @@
package org.cryptomator.ui.migration;

import javafx.fxml.FXML;
import javafx.stage.Stage;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.fxapp.FxApplication;

import javax.inject.Inject;

public class MigrationImpossibleController implements FxController {

	private static final String HELP_URI = "https://docs.cryptomator.org/en/1.5/help/manual-migration/";

	private final FxApplication fxApplication;
	private final Stage window;
	private final Vault vault;

	@Inject
	MigrationImpossibleController(FxApplication fxApplication, @MigrationWindow Stage window, @MigrationWindow Vault vault) {
		this.fxApplication = fxApplication;
		this.window = window;
		this.vault = vault;
	}

	@FXML
	public void close() {
		window.close();
	}

	@FXML
	public void getMigrationHelp() {
		fxApplication.getHostServices().showDocument(HELP_URI);
	}

	/* Getter/Setters */

	public Vault getVault() {
		return vault;
	}

	public String getHelpUri() {
		return HELP_URI;
	}

}

M main/ui/src/main/java/org/cryptomator/ui/migration/MigrationModule.java => main/ui/src/main/java/org/cryptomator/ui/migration/MigrationModule.java +12 -1
@@ 83,6 83,13 @@ abstract class MigrationModule {
		return fxmlLoaders.createScene("/fxml/migration_capability_error.fxml");
	}

	@Provides
	@FxmlScene(FxmlFile.MIGRATION_IMPOSSIBLE)
	@MigrationScoped
	static Scene provideMigrationImpossibleScene(@MigrationWindow FXMLLoaderFactory fxmlLoaders) {
		return fxmlLoaders.createScene("/fxml/migration_impossible.fxml");
	}

	// ------------------

	@Binds


@@ 104,5 111,9 @@ abstract class MigrationModule {
	@IntoMap
	@FxControllerKey(MigrationCapabilityErrorController.class)
	abstract FxController bindMigrationCapabilityErrorController(MigrationCapabilityErrorController controller);
	

	@Binds
	@IntoMap
	@FxControllerKey(MigrationImpossibleController.class)
	abstract FxController bindMigrationImpossibleController(MigrationImpossibleController controller);
}

M main/ui/src/main/java/org/cryptomator/ui/migration/MigrationRunController.java => main/ui/src/main/java/org/cryptomator/ui/migration/MigrationRunController.java +29 -22
@@ 16,8 16,10 @@ import javafx.scene.control.ContentDisplay;
import javafx.stage.Stage;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.cryptofs.FileNameTooLongException;
import org.cryptomator.cryptofs.common.FileSystemCapabilityChecker;
import org.cryptomator.cryptofs.migration.Migrators;
import org.cryptomator.cryptofs.migration.api.MigrationContinuationListener;
import org.cryptomator.cryptofs.migration.api.MigrationProgressListener;
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
import org.cryptomator.keychain.KeychainAccess;


@@ 58,6 60,7 @@ public class MigrationRunController implements FxController {
	private final ErrorComponent.Builder errorComponent;
	private final Lazy<Scene> startScene;
	private final Lazy<Scene> successScene;
	private final Lazy<Scene> impossibleScene;
	private final ObjectBinding<ContentDisplay> migrateButtonContentDisplay;
	private final Lazy<Scene> capabilityErrorScene;
	private final BooleanProperty migrationButtonDisabled;


@@ 66,7 69,8 @@ public class MigrationRunController implements FxController {
	public NiceSecurePasswordField passwordField;

	@Inject
	public MigrationRunController(@MigrationWindow Stage window, @MigrationWindow Vault vault, ExecutorService executor, ScheduledExecutorService scheduler, Optional<KeychainAccess> keychainAccess, @Named("capabilityErrorCause") ObjectProperty<FileSystemCapabilityChecker.Capability> missingCapability, @FxmlScene(FxmlFile.MIGRATION_START) Lazy<Scene> startScene, @FxmlScene(FxmlFile.MIGRATION_SUCCESS) Lazy<Scene> successScene, @FxmlScene(FxmlFile.MIGRATION_CAPABILITY_ERROR) Lazy<Scene> capabilityErrorScene, ErrorComponent.Builder errorComponent) {
	public MigrationRunController(@MigrationWindow Stage window, @MigrationWindow Vault vault, ExecutorService executor, ScheduledExecutorService scheduler, Optional<KeychainAccess> keychainAccess, @Named("capabilityErrorCause") ObjectProperty<FileSystemCapabilityChecker.Capability> missingCapability, @FxmlScene(FxmlFile.MIGRATION_START) Lazy<Scene> startScene, @FxmlScene(FxmlFile.MIGRATION_SUCCESS) Lazy<Scene> successScene, @FxmlScene(FxmlFile.MIGRATION_CAPABILITY_ERROR) Lazy<Scene> capabilityErrorScene, @FxmlScene(FxmlFile.MIGRATION_IMPOSSIBLE) Lazy<Scene> impossibleScene, ErrorComponent.Builder errorComponent) {

		this.window = window;
		this.vault = vault;
		this.executor = executor;


@@ 80,6 84,7 @@ public class MigrationRunController implements FxController {
		this.capabilityErrorScene = capabilityErrorScene;
		this.migrationButtonDisabled = new SimpleBooleanProperty();
		this.migrationProgress = new SimpleDoubleProperty(volatileMigrationProgress);
		this.impossibleScene = impossibleScene;
	}

	public void initialize() {


@@ 107,7 112,7 @@ public class MigrationRunController implements FxController {
		}, 0, MIGRATION_PROGRESS_UPDATE_MILLIS, TimeUnit.MILLISECONDS);
		Tasks.create(() -> {
			Migrators migrators = Migrators.get();
			migrators.migrate(vault.getPath(), MASTERKEY_FILENAME, password, this::migrationProgressChanged);
			migrators.migrate(vault.getPath(), MASTERKEY_FILENAME, password, this::migrationProgressChanged, this::migrationRequiresInput);
			return migrators.needsMigration(vault.getPath(), MASTERKEY_FILENAME);
		}).onSuccess(needsAnotherMigration -> {
			if (needsAnotherMigration) {


@@ 127,9 132,14 @@ public class MigrationRunController implements FxController {
			vault.setState(VaultState.NEEDS_MIGRATION);
		}).onError(FileSystemCapabilityChecker.MissingCapabilityException.class, e -> {
			LOG.error("Underlying file system not supported.", e);
			vault.setState(VaultState.ERROR);
			vault.setState(VaultState.NEEDS_MIGRATION);
			missingCapability.set(e.getMissingCapability());
			window.setScene(capabilityErrorScene.get());
		}).onError(FileNameTooLongException.class, e -> {
			LOG.error("Migration failed because the underlying file system does not support long filenames.", e);
			vault.setState(VaultState.NEEDS_MIGRATION);
			errorComponent.cause(e).window(window).returnToScene(startScene.get()).build().showErrorScene();
			window.setScene(impossibleScene.get());
		}).onError(Exception.class, e -> { // including RuntimeExceptions
			LOG.error("Migration failed for technical reasons.", e);
			vault.setState(VaultState.NEEDS_MIGRATION);


@@ 142,19 152,18 @@ public class MigrationRunController implements FxController {

	// Called by a background task. We can not directly modify observable properties from here
	private void migrationProgressChanged(MigrationProgressListener.ProgressState state, double progress) {
		switch (state) {
			case INITIALIZING:
				volatileMigrationProgress = -1.0;
				break;
			case MIGRATING:
				volatileMigrationProgress = progress;
				break;
			case FINALIZING:
				volatileMigrationProgress = 1.0;
				break;
			default:
				throw new IllegalStateException("Unexpted state " + state);
		}
		volatileMigrationProgress = switch (state) {
			case INITIALIZING -> -1.0;
			case MIGRATING -> progress;
			case FINALIZING -> 1.0;
		};
	}

	private MigrationContinuationListener.ContinuationResult migrationRequiresInput(MigrationContinuationListener.ContinuationEvent event) {
		//TODO: creating a new scene seems a little over the top, maybe stick to this scene
		// my suggestion is to make this quick and dirty by setting some elements unmanaged and invisible and afterwards activate them again
		// otherwise: We need a more abstract runController which has two subviews (run and halted), see mainWindow for example
		return MigrationContinuationListener.ContinuationResult.PROCEED;
	}

	private void loadStoredPassword() {


@@ 194,12 203,10 @@ public class MigrationRunController implements FxController {
	}

	public ContentDisplay getMigrateButtonContentDisplay() {
		switch (vault.getState()) {
			case PROCESSING:
				return ContentDisplay.LEFT;
			default:
				return ContentDisplay.TEXT_ONLY;
		}
		return switch (vault.getState()) {
			case PROCESSING -> ContentDisplay.LEFT;
			default -> ContentDisplay.TEXT_ONLY;
		};
	}

	public ReadOnlyDoubleProperty migrationProgressProperty() {

M main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesController.java => main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesController.java +8 -15
@@ 49,21 49,14 @@ public class PreferencesController implements FxController {
	}

	private Tab getTabToSelect(SelectedPreferencesTab selectedTab) {
		switch (selectedTab) {
			case UPDATES:
				return updatesTab;
			case VOLUME:
				return volumeTab;
			case DONATION_KEY:
				return donationKeyTab;
			case GENERAL:
				return generalTab;
			case ABOUT:
				return aboutTab;
			case ANY:
			default:
				return updateAvailable.get() ? updatesTab : generalTab;
		}
		return switch (selectedTab) {
			case UPDATES -> updatesTab;
			case VOLUME -> volumeTab;
			case DONATION_KEY -> donationKeyTab;
			case GENERAL -> generalTab;
			case ABOUT -> aboutTab;
			case ANY -> updateAvailable.get() ? updatesTab : generalTab;
		};
	}

	private void selectedTabChanged() {

M main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayImageFactory.java => main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayImageFactory.java +4 -6
@@ 29,12 29,10 @@ class TrayImageFactory {
		MacApplicationUiInterfaceStyle interfaceStyle = macFunctions.map(MacFunctions::uiAppearance) //
				.map(MacApplicationUiAppearance::getCurrentInterfaceStyle) //
				.orElse(MacApplicationUiInterfaceStyle.LIGHT);
		switch (interfaceStyle) {
			case DARK:
				return "/tray_icon_mac_white.png";
			default:
				return "/tray_icon_mac_black.png";
		}
		return switch (interfaceStyle) {
			case DARK -> "/tray_icon_mac_white.png";
			case LIGHT -> "/tray_icon_mac_black.png";
		};
	}

	private String getWinOrLinuxResourceName() {

M main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java => main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java +9 -7
@@ 73,7 73,7 @@ public class UnlockController implements FxController {
		if (keychainAccess.isPresent()) {
			loadStoredPassword();
		} else {
			savePassword.setDisable(true);
			savePassword.setSelected(false);
		}
		unlockButtonDisabled.bind(vault.stateProperty().isNotEqualTo(VaultState.LOCKED).or(passwordField.textProperty().isEmpty()));
	}


@@ 174,12 174,10 @@ public class UnlockController implements FxController {
	}

	public ContentDisplay getUnlockButtonState() {
		switch (vault.getState()) {
			case PROCESSING:
				return ContentDisplay.LEFT;
			default:
				return ContentDisplay.TEXT_ONLY;
		}
		return switch (vault.getState()) {
			case PROCESSING -> ContentDisplay.LEFT;
			default -> ContentDisplay.TEXT_ONLY;
		};
	}

	public ReadOnlyBooleanProperty unlockButtonDisabledProperty() {


@@ 189,4 187,8 @@ public class UnlockController implements FxController {
	public boolean isUnlockButtonDisabled() {
		return unlockButtonDisabled.get();
	}

	public boolean isKeychainAccessAvailable() {
		return keychainAccess.isPresent();
	}
}

M main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java => main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java +3 -2
@@ 8,6 8,7 @@ import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Modality;
import javafx.stage.Stage;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.common.DefaultSceneFactory;
import org.cryptomator.ui.common.FXMLLoaderFactory;
import org.cryptomator.ui.common.FxController;


@@ 35,9 36,9 @@ abstract class UnlockModule {
	@Provides
	@UnlockWindow
	@UnlockScoped
	static Stage provideStage(ResourceBundle resourceBundle, @Named("windowIcons") List<Image> windowIcons) {
	static Stage provideStage(@UnlockWindow Vault vault, @Named("windowIcons") List<Image> windowIcons) {
		Stage stage = new Stage();
		stage.setTitle(resourceBundle.getString("unlock.title"));
		stage.setTitle(vault.getDisplayableName());
		stage.setResizable(false);
		stage.initModality(Modality.APPLICATION_MODAL);
		stage.getIcons().addAll(windowIcons);

M main/ui/src/main/resources/css/dark_theme.css => main/ui/src/main/resources/css/dark_theme.css +1 -1
@@ 854,7 854,7 @@
.progress-bar > .bar {
	-fx-background-color: CONTROL_PRIMARY_BG_NORMAL;
	-fx-background-radius: 4px;
	-fx-padding: 0.5em;
	-fx-padding: 1em 0.5em;
}

.progress-bar:indeterminate > .bar {

M main/ui/src/main/resources/css/light_theme.css => main/ui/src/main/resources/css/light_theme.css +1 -1
@@ 853,7 853,7 @@
.progress-bar > .bar {
	-fx-background-color: CONTROL_PRIMARY_BG_NORMAL;
	-fx-background-radius: 4px;
	-fx-padding: 0.5em;
	-fx-padding: 1em 0.5em;
}

.progress-bar:indeterminate > .bar {

A main/ui/src/main/resources/fxml/migration_impossible.fxml => main/ui/src/main/resources/fxml/migration_impossible.fxml +52 -0
@@ 0,0 1,52 @@
<?xml version="1.0" encoding="UTF-8"?>


<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ButtonBar?>
<?import javafx.scene.control.Hyperlink?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.Circle?>
<?import javafx.scene.text.Text?>
<?import javafx.scene.text.TextFlow?>
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
<VBox xmlns="http://javafx.com/javafx"
	  xmlns:fx="http://javafx.com/fxml"
	  fx:controller="org.cryptomator.ui.migration.MigrationImpossibleController"
	  minWidth="400"
	  maxWidth="400"
	  minHeight="145"
	  spacing="12">
	<padding>
		<Insets topRightBottomLeft="12"/>
	</padding>

	<HBox spacing="12" alignment="CENTER_LEFT" VBox.vgrow="ALWAYS">
		<StackPane alignment="CENTER" HBox.hgrow="NEVER">
			<Circle styleClass="glyph-icon-red" radius="24"/>
			<FontAwesome5IconView styleClass="glyph-icon-white" glyph="TIMES" glyphSize="24"/>
		</StackPane>
		<VBox spacing="6">
			<Label styleClass="label-large" text="%migration.impossible.heading"/>
			<Label text="%migration.impossible.reason" wrapText="true" HBox.hgrow="ALWAYS"/>
			<TextFlow>
				<Text text="%migration.impossible.moreInfo"/>
				<Text text=" "/>
				<Hyperlink styleClass="hyperlink-underline" text="docs.cryptomator.org" wrapText="true" onAction="#getMigrationHelp"/>
				<Text text="."/>
			</TextFlow>
		</VBox>
	</HBox>

	<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
		<ButtonBar buttonMinWidth="120" buttonOrder="+C">
			<buttons>
				<!-- Button text="Try again" ButtonBar.buttonData="to do" onAction="#retry" / also add button to button bar order-->
				<Button text="%generic.button.close" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#close"/>
			</buttons>
		</ButtonBar>
	</VBox>
</VBox>

M main/ui/src/main/resources/fxml/migration_run.fxml => main/ui/src/main/resources/fxml/migration_run.fxml +7 -3
@@ 3,6 3,7 @@
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ButtonBar?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ProgressBar?>
<?import javafx.scene.control.ProgressIndicator?>
<?import javafx.scene.layout.VBox?>


@@ 19,17 20,20 @@
		<Insets topRightBottomLeft="12"/>
	</padding>
	<children>
		<VBox spacing="6">
		<VBox spacing="6" visible="${!controller.vault.processing}" managed="${!controller.vault.processing}">
			<FormattedLabel format="%migration.run.enterPassword" arg1="${controller.vault.displayableName}" wrapText="true"/>
			<NiceSecurePasswordField fx:id="passwordField"/>
		</VBox>

		<ProgressBar progress="${controller.migrationProgress}" prefWidth="Infinity" visible="${controller.vault.processing}"/>
		<VBox spacing="6" visible="${controller.vault.processing}" managed="${controller.vault.processing}">
			<Label text="%migration.run.progressHint" wrapText="true"/>
			<ProgressBar progress="${controller.migrationProgress}" prefWidth="Infinity"/>
		</VBox>

		<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
			<ButtonBar buttonMinWidth="120" buttonOrder="B+X">
				<buttons>
					<Button text="%generic.button.back" ButtonBar.buttonData="BACK_PREVIOUS" cancelButton="true" onAction="#back"/>
					<Button text="%generic.button.back" ButtonBar.buttonData="BACK_PREVIOUS" cancelButton="true" onAction="#back" disable="${controller.vault.processing}"/>
					<Button text="%migration.run.startMigrationBtn" ButtonBar.buttonData="NEXT_FORWARD" defaultButton="true" onAction="#migrate" contentDisplay="${controller.migrateButtonContentDisplay}"
							disable="${controller.migrationButtonDisabled}">
						<graphic>

M main/ui/src/main/resources/fxml/unlock.fxml => main/ui/src/main/resources/fxml/unlock.fxml +2 -2
@@ 22,13 22,13 @@
		<VBox spacing="6">
			<FormattedLabel format="%unlock.passwordPrompt" arg1="${controller.vault.displayableName}" wrapText="true"/>
			<NiceSecurePasswordField fx:id="passwordField"/>
			<CheckBox fx:id="savePassword" text="%unlock.savePassword" onAction="#didClickSavePasswordCheckbox"/>
			<CheckBox fx:id="savePassword" text="%unlock.savePassword" onAction="#didClickSavePasswordCheckbox" disable="${controller.vault.processing}" visible="${controller.keychainAccessAvailable}"/>
		</VBox>

		<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
			<ButtonBar buttonMinWidth="120" buttonOrder="+CI">
				<buttons>
					<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#cancel"/>
					<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#cancel" disable="${controller.vault.processing}"/>
					<Button text="%unlock.unlockBtn" ButtonBar.buttonData="FINISH" defaultButton="true" onAction="#unlock" contentDisplay="${controller.unlockButtonState}" disable="${controller.unlockButtonDisabled}">
						<graphic>
							<ProgressIndicator progress="-1" prefWidth="12" prefHeight="12"/>

M main/ui/src/main/resources/i18n/strings.properties => main/ui/src/main/resources/i18n/strings.properties +7 -0
@@ 108,6 108,7 @@ migration.start.confirm=Yes, my vault is fully synced
## Run
migration.run.enterPassword=Enter the password for "%s"
migration.run.startMigrationBtn=Migrate Vault
migration.run.progressHint=This might take some time…
## Sucess
migration.success.nextStepsInstructions=Migrated "%s" successfully.\nYou can now unlock your vault.
migration.success.unlockNow=Unlock Now


@@ 116,6 117,12 @@ migration.error.missingFileSystemCapabilities.title=Unsupported File System
migration.error.missingFileSystemCapabilities.description=Migration was not started, because your vault is located on an inadequate file system.
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=The file system does not support long file names.
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=The file system does not support long paths.
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=The file system does not allow to be read.
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=The file system does not allow to be written to.
## Impossible
migration.impossible.heading=Unable to migrate vault
migration.impossible.reason=The vault cannot be automatically migrated because its storage location or access point is not compatible.
migration.impossible.moreInfo=The vault can still be opened with an older version. For instructions on how to manually migrate a vault, visit

# Preferences
preferences.title=Preferences

M main/ui/src/main/resources/i18n/strings_ca.properties => main/ui/src/main/resources/i18n/strings_ca.properties +2 -0
@@ 115,6 115,8 @@ migration.error.missingFileSystemCapabilities.title=El sistema de fitxers no és
migration.error.missingFileSystemCapabilities.description=La migració no s'ha iniciat perquè la vostra caixa forta es troba en un sistema de fitxers no compatible.
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=El sistema de fitxers no suporta noms de fitxers llargs.
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=El sistema de fitxers no suporta camins llargs.
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=El sistema de fitxers no permet la lectura.
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=El sistema de fitxers no permet l'escriptura.

# Preferences
preferences.title=Preferències

M main/ui/src/main/resources/i18n/strings_cs.properties => main/ui/src/main/resources/i18n/strings_cs.properties +2 -0
@@ 115,6 115,8 @@ migration.error.missingFileSystemCapabilities.title=Nepodporovaný souborový sy
migration.error.missingFileSystemCapabilities.description=Migrace nebyla zahájena, protože váš trezor je umístěn na nedostatečném souborovém systému.
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=Souborový systém nepodporuje dlouhá jména souborů.
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=Souborový systém nepodporuje dlouhé cesty.
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=Souborový systém neumožňuje čtení.
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=Souborový systém neumožňuje zápis.

# Preferences
preferences.title=Nastavení

M main/ui/src/main/resources/i18n/strings_de.properties => main/ui/src/main/resources/i18n/strings_de.properties +2 -0
@@ 115,6 115,8 @@ migration.error.missingFileSystemCapabilities.title=Nicht unterstütztes Dateisy
migration.error.missingFileSystemCapabilities.description=Die Migration wurde nicht gestartet, da sich dein Tresor auf einem ungeeigneten Dateisystem befindet.
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=Das Dateisystem unterstützt keine langen Dateinamen.
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=Das Dateisystem unterstützt keine langen Pfadnamen.
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=Das Dateisystem lässt keine Lesevorgänge zu.
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=Das Dateisystem lässt keine Schreibvorgänge zu.

# Preferences
preferences.title=Einstellungen

M main/ui/src/main/resources/i18n/strings_es.properties => main/ui/src/main/resources/i18n/strings_es.properties +2 -0
@@ 115,6 115,8 @@ migration.error.missingFileSystemCapabilities.title=Sistema de archivos no sopor
migration.error.missingFileSystemCapabilities.description=La migración no se inició porque la bóveda se encuentra en un sistema de archivos inadecuado.
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=El sistema de archivos no soporta nombres largos.
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=El sistema de archivos no soporta rutas largas.
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=El sistema de archivos no permite la lectura.
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=El sistema de archivos no permite la escritura.

# Preferences
preferences.title=Preferencias

M main/ui/src/main/resources/i18n/strings_fr.properties => main/ui/src/main/resources/i18n/strings_fr.properties +2 -0
@@ 115,6 115,8 @@ migration.error.missingFileSystemCapabilities.title=Système de fichiers non pri
migration.error.missingFileSystemCapabilities.description=La migration n'a pas débuté car votre coffre se trouve dans un système de fichiers inapproprié.
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=Ce système de fichiers ne prend pas en charge les noms de fichiers longs.
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=Ce système de fichiers ne prend pas en charge les chemins d'accès longs.
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=Le système de fichiers ne permet pas d'être lu.
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=Le système de fichiers ne permet pas l'écriture.

# Preferences
preferences.title=Préférences

M main/ui/src/main/resources/i18n/strings_it.properties => main/ui/src/main/resources/i18n/strings_it.properties +2 -0
@@ 115,6 115,8 @@ migration.error.missingFileSystemCapabilities.title=File System non supportato
migration.error.missingFileSystemCapabilities.description=La migrazione non è stata avviata perché la cassaforte è situata su un file system inadeguato.
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=Il file system non supporta nomi di file lunghi.
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=Il file system non supporta percorsi lunghi.
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=Il file system non consente di essere letto.
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=Il file system non consente di essere scritto.

# Preferences
preferences.title=Impostazioni

M main/ui/src/main/resources/i18n/strings_ja.properties => main/ui/src/main/resources/i18n/strings_ja.properties +2 -0
@@ 115,6 115,8 @@ migration.error.missingFileSystemCapabilities.title=サポートされないフ
migration.error.missingFileSystemCapabilities.description=金庫が不適切なファイルシステムにあるため、移行が開始されませんでした。
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=ファイルシステムが長いファイル名をサポートしていません。
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=ファイルシステムが長いパスをサポートしていません。
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=ファイルシステムによって読み込みが許可されていません。
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=ファイルシステムによって書き込みが許可されていません。

# Preferences
preferences.title=設定

M main/ui/src/main/resources/i18n/strings_lv.properties => main/ui/src/main/resources/i18n/strings_lv.properties +180 -0
@@ 2,62 2,242 @@

# Generics
## Button
generic.button.apply=Pielietot
generic.button.back=Atpakaļ
generic.button.cancel=Atcelt
generic.button.change=Mainīt
generic.button.close=Aizvērt
generic.button.copy=Kopēt
generic.button.copied=Nokopēts!
generic.button.done=Darīts
generic.button.next=Tālāk
generic.button.print=Drukāt
## Error
generic.error.title=Radās neparedzēta kļūda
generic.error.instruction=Šis vēl nav atgadījies. Lūdzu ziņo zemāk redzamo kļūdas tekstu un iekļauj aprakstu, kas noveda pie šīs kļūdas.

# Tray Menu
traymenu.showMainWindow=Rādīt
traymenu.showPreferencesWindow=Iestatījumi
traymenu.lockAllVaults=Aizslēgt visu
traymenu.quitApplication=Iziet
traymenu.vault.unlock=Atslēgt
traymenu.vault.lock=Aizslēgt
traymenu.vault.reveal=Atklāt

# Add Vault Wizard
addvaultwizard.title=Pievienot glabātuvi
## Welcome
addvaultwizard.welcome.newButton=Izveidot jaunu glabātuvi
addvaultwizard.welcome.existingButton=Atvērt esošu glabātuvi
## New
### Name
addvaultwizard.new.nameInstruction=Izvēlies glabātuves nosaukumu
addvaultwizard.new.namePrompt=Glabātuves nosaukums
### Location
addvaultwizard.new.locationInstruction=Kur Cryptomator vajadzētu glabāt jūsu glabātuves šifrētos failus?
addvaultwizard.new.locationLabel=Krātuves atrašanās vieta
addvaultwizard.new.locationPrompt=…
addvaultwizard.new.directoryPickerLabel=Pielāgota atrašanās vieta
addvaultwizard.new.directoryPickerButton=Izvēlies...
addvaultwizard.new.directoryPickerTitle=Izvēlēties mapi
addvaultwizard.new.fileAlreadyExists=Glabātuvi nevar izveidot šajā ceļā, jo kāds objekts jau pastāv.
addvaultwizard.new.invalidName=Nederīgs glabātuves nosaukums. Lūdzu izvēlieties vienkāršu mapes nosaukumu.
### Password
addvaultwizard.new.createVaultBtn=Izveidot glabātuvi
addvaultwizard.new.generateRecoveryKeyChoice=Jūs nevarēsiet piekļūt saviem datiem bez paroles. Vai vēlaties atkopšanas atslēgu gadījumam, kad esat pazaudējis paroli?
addvaultwizard.new.generateRecoveryKeyChoice.yes=Jā, lūdzu, labāk droši nekā nekā
addvaultwizard.new.generateRecoveryKeyChoice.no=Nē, paldies, es nezaudēšu savu paroli
### Information
addvault.new.readme.storageLocation.fileName=IMPORTANT.rtf
addvault.new.readme.storageLocation.1=⚠️  GLABĀTUVES DATNES  ⚠️
addvault.new.readme.storageLocation.2=Šī ir jūsu glabātuves atrašanās vieta.
addvault.new.readme.storageLocation.3=Nekādā gadījumā
addvault.new.readme.storageLocation.4=mainīt visas datnes šajā mapē vai
addvault.new.readme.storageLocation.5=ielīmējiet visas datnes šifrēšanai šajā mapē.
addvault.new.readme.storageLocation.6=Ja vēlaties šifrēt datnes un skatīt glabātuves saturu, rīkojieties šādi:
addvault.new.readme.storageLocation.7=Pievienot šo glabātuvi Cryptomator.
addvault.new.readme.storageLocation.8=Atslēgt glabātuvi ar Cryptomator.
addvault.new.readme.storageLocation.9=Atveriet piekļuves vietu, noklikšķinot uz pogas "Atklāt".
addvault.new.readme.storageLocation.10=Ja hums ir nepieciešama palīdzība, apmeklējiet dokumentāciju: %s
addvault.new.readme.accessLocation.fileName=WELCOME.rtf
addvault.new.readme.accessLocation.1=🔐️  ŠIFRĒTS SĒJUMS  🔐️
addvault.new.readme.accessLocation.2=Šī ir jūsu glabātuves piekļuves vieta.
addvault.new.readme.accessLocation.3=Visas šeit pievienotās datnes tiks šifrētas ar Cryptomator. Jūs variet ar to strādāt kā ar jebkuru citu disku/mapi. Šis it tikai atšifrēts satura skats, jūsu dati diskā visu laiku ir šifrēti.
addvault.new.readme.accessLocation.4=Jūs variet droši noņemt šo datni.
## Existing
addvaultwizard.existing.instruction=Izvēlieties "masterkey.cryptomator" datni no jūsu esošās glabātuves.
addvaultwizard.existing.chooseBtn=Izvēlies...
addvaultwizard.existing.filePickerTitle=Atlasīt galveno atslēgas datni
## Success
addvaultwizard.success.nextStepsInstructions=Pievienota "%s" glabātuve.\nlai piekļūtu vai pievienotu datus, jums šo glabātuvi ir jāatslēdz. Vai arī jūs to variet atslēgt vēlāk jebkurā laikā.
addvaultwizard.success.unlockNow=Atslēgt tagad

# Remove Vault
removeVault.title=Noņemt glabātuvi
removeVault.information=Šis tikai liks Cryptomator aizmirst šo glabātuvi. Jūs to variet pievienot vēlāk atkārtoti. Nekādi šifrētie dati no diska netiks dzēsti.
removeVault.confirmBtn=Noņemt glabātuvi

# Change Password
changepassword.title=Mainīt paroli
changepassword.enterOldPassword=Ievadiet "%s" pašreizējo paroli
changepassword.finalConfirmation=Es saprotu, ka paroles aizmiršanas gadījumā, es vairs  nevarēšu piekļūt saviem datiem

# Forget Password
forgetPassword.title=Aizmirst paroli
forgetPassword.information=Tas dzēsīs saglabāto glabātuves paroli no jūsu sistēmas atslēgu krātuves.
forgetPassword.confirmBtn=Aizmirst paroli

# Unlock
unlock.title=Atslēgt glabātuvi
unlock.passwordPrompt=Ievadiet "%s" paroli:
unlock.savePassword=Saglabāt paroli
unlock.unlockBtn=Atslēgt
## Success
unlock.success.message="%s" sekmīgi atslēgts! Jūsu glabātuve tagad ir pieejama.
unlock.success.revealBtn=Atklāt glabātuvi
## Invalid Mount Point
unlock.error.invalidMountPoint=Montēšanas vieta nav tukša mape: %s

# Migration
migration.title=Jaunināt glabātuvi
## Start
migration.start.prompt=Jūsu "%s" glabātuvi nepieciešams atjaunināt uz jaunu formātu. Pirms turpiniet, pārliecinieties, ka nav aktīva šīs glabātuves sinhronizācija.
migration.start.confirm=Jā, mana glabātuve ir pilnībā sinhronizēta
## Run
migration.run.enterPassword=Ievadiet "%s" paroli
migration.run.startMigrationBtn=Migrēt glabātuvi
## Sucess
migration.success.nextStepsInstructions="%s" sekmīgi migrēta.\nJūs tagad variet atslēgt jūsu glabātuvi.
migration.success.unlockNow=Atslēgt tagad
## Missing file system capabilities
migration.error.missingFileSystemCapabilities.title=Neatbalstīta datņu sistēma
migration.error.missingFileSystemCapabilities.description=Migrācija netika uzsāta, jo jūsu glabātuve atrodās neadekvātā datņu sistēmā.
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=Datņu sistēma neatbalsta garus datņu nosaukumus.
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=Datņu sistēma neatbalsta garus ceļu nosaukumus.
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=Nav atļaujas lasīt no datņu sistēmas.
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=Nav atļaujas rakstīt datņu sistēmā.

# Preferences
preferences.title=Iestatījumi
## General
preferences.general=Vispārēji
preferences.general.theme=Izskats
preferences.general.unlockThemes=Iespējot tumšo režīmu
preferences.general.startHidden=Paslēpt logu, kad startē Cryptomator
preferences.general.debugLogging=Iespējot atkļūdošanas žurnalēšanu
preferences.general.autoStart=Palaist Cryptomator pie sistēmas startēšanas
preferences.general.interfaceOrientation=Saskarnes orientācija
preferences.general.interfaceOrientation.ltr=Kreisā uz labo
preferences.general.interfaceOrientation.rtl=Labā uz kreiso
## Volume
preferences.volume=Virtuāls disks
preferences.volume.type=Sējuma tips
preferences.volume.webdav.port=WebDAV ports
preferences.volume.webdav.scheme=WebDAV shēma
## Updates
preferences.updates=Atjauninājumi
preferences.updates.currentVersion=Pašreizējā versija: %s
preferences.updates.autoUpdateCheck=Automātiski pārbaudīt atjauninājumus
preferences.updates.checkNowBtn=Pārbaudīt tagad
preferences.updates.updateAvailable=Pieejams atjauninājums uz versiju %s.
## Donation Key
preferences.donationKey=Ziedojums
preferences.donationKey.registeredFor=Reģistrēts uz %s
preferences.donationKey.noDonationKey=Nav atrasta derīga ziedojuma atslēga. Tā ir kā licences atslēga , bet priekš satriecošiem cilvēkiem, kas izmanto bezmaksas programmatūru. ;-)
preferences.donationKey.getDonationKey=Iegūt ziedojuma atslēgu
## About
preferences.about=Par lietotni

# Main Window
main.closeBtn.tooltip=Aizvērt
main.minimizeBtn.tooltip=Minimizēt
main.preferencesBtn.tooltip=Iestatījumi
main.donationKeyMissing.tooltip=Lūdzu apsveriet iespēju ziedot
## Drag 'n' Drop
main.dropZone.dropVault=Pievienot šo glabātuvi
main.dropZone.unknownDragboardContent=Ja jūs vēlaties pievienot glabātuvi, velciet to uz šo logu
## Vault List
main.vaultlist.emptyList.onboardingInstruction=Spied šeit, lai pievienotu glabātuvi
main.vaultlist.contextMenu.remove=Noņemt glabātuvi
main.vaultlist.addVaultBtn=Pievienot glabātuvi
## Vault Detail
### Welcome
main.vaultDetail.welcomeOnboarding=Paldies, ka izvēlējāties Cryptomator lai aizsargātu jūsu datus. Ja jums nepieciešama palīdzība, iepazīstieties ar mūsu darba sākšanas ceļvežiem:
### Locked
main.vaultDetail.lockedStatus=AIZSLĒGTS
main.vaultDetail.unlockBtn=Atslēgt
main.vaultDetail.optionsBtn=Glabātuves opcijas
### Unlocked
main.vaultDetail.unlockedStatus=ATSLĒGTS
main.vaultDetail.accessLocation=Jūsu glabātuves saturs ir pieejams šeit:
main.vaultDetail.revealBtn=Atklāt disku
main.vaultDetail.lockBtn=Aizslēgt
main.vaultDetail.bytesPerSecondRead=nolasīts:
main.vaultDetail.bytesPerSecondWritten=ierakstīts:
main.vaultDetail.throughput.idle=dīkstāvē
main.vaultDetail.throughput.kbps=%.1f kiB/s
main.vaultDetail.throughput.mbps=%.1f MiB/s
### Missing
main.vaultDetail.missing.info=Cryptomator šajā ceļā nevarēja atrast glabātuvi.
### Needs Migration
main.vaultDetail.migrateButton=Jaunināt glabātuvi
main.vaultDetail.migratePrompt=Lai jūsu varētu piekļūt glabātuvei to ir nepieciešms jaunināt uz jaunu formātu

# Wrong File Alert
wrongFileAlert.title=Kā šifrēt datnes
wrongFileAlert.header.title=Vai jūs mēģinājāt šifrēt šīs datnes?
wrongFileAlert.header.lead=Šim nolūkam Cryptomator jūsu sistēmas datņu pārvaldniekā nodrošina sējumus.
wrongFileAlert.instruction.0=Lai šifrētu datnes, sekojiet šiem soļiem:
wrongFileAlert.instruction.1=1. Atslēdziet jūsu glabātuvi.
wrongFileAlert.instruction.2=2. Spiediet uz "Atklāt", lai atvērtu sējumu jūsu datņu pārvaldniekā.
wrongFileAlert.instruction.3=Šim sējumam pievienojiet jūsu datnes.
wrongFileAlert.link=Lai iegūtu turpmāku palīdzību, apmeklējiet

# Vault Options
## General
vaultOptions.general=Vispārēji
vaultOptions.general.unlockAfterStartup=Atslēgt glabātuvi startējot Cryptomator
## Mount
vaultOptions.mount=Montē
vaultOptions.mount.readonly=Tikai lasīt
vaultOptions.mount.driveName=Diska nosaukums
vaultOptions.mount.customMountFlags=Pielāgoti montēšanas parametri
vaultOptions.mount.winDriveLetterOccupied=aizņemts
vaultOptions.mount.mountPoint=Montēšanas vieta
vaultOptions.mount.mountPoint.auto=Automātiski izvēlieties piemērotu vietu
vaultOptions.mount.mountPoint.driveLetter=Izmantot piešķirtu diska burtu
vaultOptions.mount.mountPoint.custom=Pielāgots ceļš
vaultOptions.mount.mountPoint.directoryPickerButton=Izvēlies...
vaultOptions.mount.mountPoint.directoryPickerTitle=Izvēlies tukšu mapi
## Master Key
vaultOptions.masterkey=Parole
vaultOptions.masterkey.changePasswordBtn=Mainīt paroli
vaultOptions.masterkey.recoveryKeyExpanation=Atkopšanas atslēga ir jūsu vienīgais līdzeklis, lai atjaunotu piekļuvi glabātuvei, ja pazaudējat paroli.
vaultOptions.masterkey.showRecoveryKeyBtn=Rādīt atkopšanas atslēgu
vaultOptions.masterkey.recoverPasswordBtn=Atjaunot paroli

# Recovery Key
recoveryKey.title=Atjaunošanas atslēga
recoveryKey.enterPassword.prompt=Lai parādītu "%s" atjaunošanas atslēgu, ievadiet paroli:
recoveryKey.display.message=Šī atjaunošanas atslēga var tikt izmantota, lai atjaunotu "%s":
recoveryKey.display.StorageHints=Glabājiet to drošā vietā, piemēram:\n  • Uzglabājiet to, izmantojot paroļu pārvaldnieku\n  • Saglabājiet to USB zibatmiņā\n  • Izdrukājiet to uz papīra
recoveryKey.recover.prompt=Ievadiet "%s" atjaunošanas atslēgu:
recoveryKey.recover.validKey=Šī ir derīga atjaunošanas atslēga
recoveryKey.printout.heading=Cryptomator atjaunošanas atslēga\n"%s" \n

# New Password
newPassword.promptText=Ievadiet jauno paroli
newPassword.reenterPassword=Apstipriniet jauno paroli
newPassword.passwordsMatch=Parole sakrīt!
newPassword.passwordsDoNotMatch=Paroles nesakrīt
passwordStrength.messageLabel.tooShort=Izmantojiet vismaz %d burtus
passwordStrength.messageLabel.0=Ļoti vāja
passwordStrength.messageLabel.1=Vāja
passwordStrength.messageLabel.2=Vidēja
passwordStrength.messageLabel.3=Stipra
passwordStrength.messageLabel.4=Ļoti stipra

# Quit
quit.prompt=Aizvērt lietotni? Ir atslēgtas glabātuves.
quit.lockAndQuit=Aizslēgt un aizvērt

M main/ui/src/main/resources/i18n/strings_nb.properties => main/ui/src/main/resources/i18n/strings_nb.properties +2 -0
@@ 115,6 115,8 @@ migration.error.missingFileSystemCapabilities.title=Filsystemet er ikke støttet
migration.error.missingFileSystemCapabilities.description=Overføringen ble ikke startet fordi hvelvet ditt ligger i et mangelfullt filsystem.
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=Filsystemet støtter ikke lange filnavn.
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=Filsystemet støtter ikke lange søkestier.
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=Filsystemet tillater ikke lesing.
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=Filsystemet tillater ikke å bli skrevet på.

# Preferences
preferences.title=Innstillinger

M main/ui/src/main/resources/i18n/strings_nn.properties => main/ui/src/main/resources/i18n/strings_nn.properties +2 -0
@@ 115,6 115,8 @@ migration.error.missingFileSystemCapabilities.title=Filsystemet er ikkje støtta
migration.error.missingFileSystemCapabilities.description=Migreringen vart ikkje starta fordi kvelven din ligg i eit mangelfullt filsystem.
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=Filsystemet støttar ikkje lange filnamn.
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=Filsystemet støttar ikkje lange søkastiar.
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=Filsystemet tillèt ikkje å bli lese.
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=Filsystemet tillèt ikkje å bli skrive på.

# Preferences
preferences.title=Innstillingar

M main/ui/src/main/resources/i18n/strings_pt_BR.properties => main/ui/src/main/resources/i18n/strings_pt_BR.properties +2 -0
@@ 115,6 115,8 @@ migration.error.missingFileSystemCapabilities.title=Sistema de arquivos não sup
migration.error.missingFileSystemCapabilities.description=A migração não foi iniciada porque o seu cofre está localizado em um sistema de arquivos inadequado.
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=O sistema de arquivos não suporta arquivos com nome longo.
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=O sistema de arquivos não suporta caminhos longos.
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=O sistema de arquivos não permite leitura.
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=O sistema de arquivos não permite ser gravado.

# Preferences
preferences.title=Preferências

M main/ui/src/main/resources/i18n/strings_ru.properties => main/ui/src/main/resources/i18n/strings_ru.properties +2 -0
@@ 115,6 115,8 @@ migration.error.missingFileSystemCapabilities.title=Неподдерживаем
migration.error.missingFileSystemCapabilities.description=Миграция не была запущена, так как хранилище находится в ненадлежащей файловой системе.
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=Файловая система не поддерживает длинные имена файлов.
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=Файловая система не поддерживает длинные пути.
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=Файловая система не разрешает чтение.
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=Файловая система не разрешает запись.

# Preferences
preferences.title=Настройки

A main/ui/src/main/resources/i18n/strings_sk.properties => main/ui/src/main/resources/i18n/strings_sk.properties +130 -0
@@ 0,0 1,130 @@
# Locale Specific CSS files such as CJK, RTL,...

# Generics
## Button
generic.button.apply=Použiť
generic.button.back=Späť
generic.button.cancel=Zrušiť
generic.button.change=Zmeniť
generic.button.close=Zavrieť
generic.button.copy=Kopírovať
generic.button.copied=Skopírované!
generic.button.done=Hotovo
generic.button.next=Ďalej
generic.button.print=Tlač
## Error
generic.error.title=Vyskytla sa neočakávaná chyba
generic.error.instruction=Toto sa nemalo stať. Nahláste text chyby uvedený nižšie a uveďte popis krokov, ktoré viedli k tejto chybe.

# Tray Menu
traymenu.showMainWindow=Zobraziť
traymenu.showPreferencesWindow=Predvoľby
traymenu.lockAllVaults=Zamknúť všetky
traymenu.quitApplication=Ukončiť
traymenu.vault.unlock=Odomknúť
traymenu.vault.lock=Uzamknúť
traymenu.vault.reveal=Odkryť

# Add Vault Wizard
addvaultwizard.title=Pridať trezor
## Welcome
addvaultwizard.welcome.newButton=Vytvoriť nový trezor
addvaultwizard.welcome.existingButton=Otvoriť existujúci trezor
## New
### Name
addvaultwizard.new.nameInstruction=Zvoľte názov pre trezor
addvaultwizard.new.namePrompt=Názov trezoru
### Location
addvaultwizard.new.locationInstruction=Kde by mal Cryptomator uchovávať šifrované súbory vášho trezoru?
addvaultwizard.new.locationLabel=Umiestnenie úložiska
addvaultwizard.new.directoryPickerLabel=Vlastné umiestnenie
addvaultwizard.new.directoryPickerButton=Vybrať…
addvaultwizard.new.directoryPickerTitle=Vybrať adresár
addvaultwizard.new.fileAlreadyExists=Na tejto ceste nie je možné vytvoriť trezor, pretože niektorý objekt už existuje.
addvaultwizard.new.invalidName=Neplatný názov trezoru. Zvážte bežný názov adresára.
### Password
addvaultwizard.new.createVaultBtn=Vytvoriť trezor
addvaultwizard.new.generateRecoveryKeyChoice=Bez hesla nebudete mať prístup k svojim údajom. Chcete obnovovací kľúč pre prípad straty hesla?
addvaultwizard.new.generateRecoveryKeyChoice.yes=Áno, prosím, istota je istota
addvaultwizard.new.generateRecoveryKeyChoice.no=Nie, ďakujem, nestratím svoje heslo
### Information
addvault.new.readme.storageLocation.fileName=Dôležité.rtf
addvault.new.readme.storageLocation.1=⚠️  SÚBORY TREZORU  ⚠️
addvault.new.readme.storageLocation.2=Toto je umiestnenie úložiska vášho trezoru.
addvault.new.readme.storageLocation.3=NEVYKONÁVAJTE
addvault.new.readme.storageLocation.4=zmeniť akékoľvek súbory v tomto adresári alebo
addvault.new.readme.storageLocation.5=vložiť do tohto adresára akékoľvek súbory na šifrovanie.
addvault.new.readme.storageLocation.6=Ak chcete šifrovať súbory a zobraziť obsah trezoru, postupujte takto:
addvault.new.readme.storageLocation.7=1. Pridajte tento trezor do Cryptomatoru.
addvault.new.readme.storageLocation.8=2. Odomknite trezor v Cryptomatore.
addvault.new.readme.storageLocation.9=3. Otvorte prístupové miesto kliknutím na tlačidlo „Odkryť“.
addvault.new.readme.storageLocation.10=Ak potrebujete pomoc, navštívte dokumentáciu: %s
addvault.new.readme.accessLocation.fileName=VITAJTE.rtf
addvault.new.readme.accessLocation.1=🔐️ ZAŠIFROVANÝ ZVÄZOK 🔐️
addvault.new.readme.accessLocation.2=Toto je prístupové miesto vášho trezoru.
addvault.new.readme.accessLocation.3=Všetky súbory pridané do tohto zväzku budú šifrované programom Cryptomator. Môžete na tom pracovať ako na akomkoľvek inom disku / priečinku. Toto je iba dešifrované zobrazenie jeho obsahu, vaše súbory zostávajú stále šifrované na pevnom disku.
addvault.new.readme.accessLocation.4=Tento súbor môžete kedykoľvek odstrániť.
## Existing
addvaultwizard.existing.instruction=Vyberte súbor „masterkey.cryptomator“ existujúceho trezoru.
addvaultwizard.existing.chooseBtn=Vybrať…
## Success
addvaultwizard.success.nextStepsInstructions=Pridaný trezor "%s".\nAk chcete získať prístup alebo pridať obsah, musíte tento trezor odomknúť. Prípadne ju môžete odomknúť kedykoľvek neskôr.
addvaultwizard.success.unlockNow=Odomknúť teraz

# Remove Vault
removeVault.title=Odstrániť trezor
removeVault.information=To spôsobí, že Cryptomator iba zabudne na tento trezor. Môžete ho pridať znova neskôr. Z pevného disku sa neodstránia žiadne šifrované súbory.
removeVault.confirmBtn=Odstrániť trezor

# Change Password

# Forget Password

# Unlock
unlock.unlockBtn=Odomknúť
## Success
## Invalid Mount Point

# Migration
## Start
## Run
## Sucess
migration.success.unlockNow=Odomknúť teraz
## Missing file system capabilities

# Preferences
preferences.title=Predvoľby
## General
## Volume
## Updates
## Donation Key
## About

# Main Window
main.preferencesBtn.tooltip=Predvoľby
## Drag 'n' Drop
## Vault List
main.vaultlist.contextMenu.remove=Odstrániť trezor
main.vaultlist.addVaultBtn=Pridať trezor
## Vault Detail
### Welcome
### Locked
main.vaultDetail.unlockBtn=Odomknúť
### Unlocked
main.vaultDetail.lockBtn=Uzamknúť
### Missing
### Needs Migration

# Wrong File Alert

# Vault Options
## General
## Mount
vaultOptions.mount.mountPoint.directoryPickerButton=Vybrať…
## Master Key

# Recovery Key

# New Password

# Quit

M main/ui/src/main/resources/i18n/strings_sv.properties => main/ui/src/main/resources/i18n/strings_sv.properties +2 -0
@@ 115,6 115,8 @@ migration.error.missingFileSystemCapabilities.title=Filsystemet stöds ej
migration.error.missingFileSystemCapabilities.description=Migreringen startades inte, eftersom ditt valv ligger på ett ogiltigt filsystem.
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=Filsystemet har inte stöd för långa filnamn.
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=Filsystemet har inte stöd för långa filnamn.
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=Filsystemet tillåter inte att läsas.
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=Filsystemet tillåter inte att skrivas till.

# Preferences
preferences.title=Inställningar

M main/ui/src/main/resources/i18n/strings_tr.properties => main/ui/src/main/resources/i18n/strings_tr.properties +2 -0
@@ 115,6 115,8 @@ migration.error.missingFileSystemCapabilities.title=Desteklenmeyen Dosya Sistemi
migration.error.missingFileSystemCapabilities.description=Kasanız desteklenmeyen bir dosya sisteminde bulunduğundan taşıma başlatılmadı.
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=Dosya sistemi, uzun belge adlarını desteklemiyor.
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=Dosya sistemi, uzun yolları desteklemiyor.
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=Dosya sistemi okunmaya izin vermiyor.
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=Dosya sistemi yazılmaya izin vermiyor.

# Preferences
preferences.title=Seçenekler

M main/ui/src/main/resources/i18n/strings_zh.properties => main/ui/src/main/resources/i18n/strings_zh.properties +2 -0
@@ 115,6 115,8 @@ migration.error.missingFileSystemCapabilities.title=不支持的文件系统
migration.error.missingFileSystemCapabilities.description=迁移未开始,因为您的保险库在一个不适当的文件系统中
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=此文件系统不支持长文件名
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=此文件系统不支持长路径
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=文件系统不允许读取访问
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=文件系统不允许写入

# Preferences
preferences.title=首选项

M main/ui/src/main/resources/i18n/strings_zh_TW.properties => main/ui/src/main/resources/i18n/strings_zh_TW.properties +2 -0
@@ 115,6 115,8 @@ migration.error.missingFileSystemCapabilities.title=不支援的檔案系統
migration.error.missingFileSystemCapabilities.description=因您的加密檔案庫位於不支援的檔案系統中,升級並未開始。
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=檔案系統不支援長檔名
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=檔案系統不支援長路徑名
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=此檔案系統不允許讀取。
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=此檔案系統不允許寫入。

# Preferences
preferences.title=偏好

M main/ui/src/main/resources/license/THIRD-PARTY.txt => main/ui/src/main/resources/license/THIRD-PARTY.txt +19 -18
@@ 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 49 third-party dependencies under the following licenses:
Cryptomator uses 50 third-party dependencies under the following licenses:
	Apache License v2.0:
		- HKDF-RFC5869 (at.favre.lib:hkdf:1.0.2 - https://github.com/patrickfav/hkdf)
		- jffi (com.github.jnr:jffi:1.2.23 - http://github.com/jnr/jffi)


@@ 32,15 32,16 @@ Cryptomator uses 49 third-party dependencies under the following licenses:
		- Java Native Access (net.java.dev.jna:jna:5.1.0 - https://github.com/java-native-access/jna)
		- Java Native Access Platform (net.java.dev.jna:jna-platform:5.1.0 - https://github.com/java-native-access/jna)
		- Apache Commons Lang (org.apache.commons:commons-lang3:3.9 - http://commons.apache.org/proper/commons-lang/)
		- Jackrabbit WebDAV Library (org.apache.jackrabbit:jackrabbit-webdav:2.19.0 - http://jackrabbit.apache.org/jackrabbit-webdav/)
		- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.17.v20190418 - http://www.eclipse.org/jetty)
		- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.17.v20190418 - http://www.eclipse.org/jetty)
		- Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.17.v20190418 - http://www.eclipse.org/jetty)
		- Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.17.v20190418 - http://www.eclipse.org/jetty)
		- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.17.v20190418 - http://www.eclipse.org/jetty)
		- Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.17.v20190418 - http://www.eclipse.org/jetty)
		- Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.17.v20190418 - http://www.eclipse.org/jetty)
		- Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.17.v20190418 - http://www.eclipse.org/jetty)
		- Apache HttpCore (org.apache.httpcomponents:httpcore:4.4.13 - http://hc.apache.org/httpcomponents-core-ga)
		- Jackrabbit WebDAV Library (org.apache.jackrabbit:jackrabbit-webdav:2.21.0 - http://jackrabbit.apache.org/jackrabbit-webdav/)
		- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.28.v20200408 - http://www.eclipse.org/jetty)
		- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.28.v20200408 - http://www.eclipse.org/jetty)
		- Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.28.v20200408 - http://www.eclipse.org/jetty)
		- Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.28.v20200408 - http://www.eclipse.org/jetty)
		- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.28.v20200408 - http://www.eclipse.org/jetty)
		- Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.28.v20200408 - http://www.eclipse.org/jetty)
		- Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.28.v20200408 - http://www.eclipse.org/jetty)
		- Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.28.v20200408 - http://www.eclipse.org/jetty)
	BSD:
		- asm (org.ow2.asm:asm:7.1 - http://asm.ow2.org/)
		- asm-analysis (org.ow2.asm:asm-analysis:7.1 - http://asm.ow2.org/)


@@ 48,14 49,14 @@ Cryptomator uses 49 third-party dependencies under the following licenses:
		- asm-tree (org.ow2.asm:asm-tree:7.1 - http://asm.ow2.org/)
		- asm-util (org.ow2.asm:asm-util:7.1 - http://asm.ow2.org/)
	Eclipse Public License - Version 1.0:
		- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.17.v20190418 - http://www.eclipse.org/jetty)
		- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.17.v20190418 - http://www.eclipse.org/jetty)
		- Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.17.v20190418 - http://www.eclipse.org/jetty)
		- Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.17.v20190418 - http://www.eclipse.org/jetty)
		- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.17.v20190418 - http://www.eclipse.org/jetty)
		- Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.17.v20190418 - http://www.eclipse.org/jetty)
		- Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.17.v20190418 - http://www.eclipse.org/jetty)
		- Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.17.v20190418 - http://www.eclipse.org/jetty)
		- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.28.v20200408 - http://www.eclipse.org/jetty)
		- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.28.v20200408 - http://www.eclipse.org/jetty)
		- Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.28.v20200408 - http://www.eclipse.org/jetty)
		- Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.28.v20200408 - http://www.eclipse.org/jetty)
		- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.28.v20200408 - http://www.eclipse.org/jetty)
		- Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.28.v20200408 - http://www.eclipse.org/jetty)
		- Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.28.v20200408 - http://www.eclipse.org/jetty)
		- Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.28.v20200408 - http://www.eclipse.org/jetty)
	Eclipse Public License - v 2.0:
		- jnr-posix (com.github.jnr:jnr-posix:3.0.54 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix)
	GPLv2: