diff --git a/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md
similarity index 100%
rename from CODE_OF_CONDUCT.md
rename to .github/CODE_OF_CONDUCT.md
diff --git a/CONTRIBUTING.md b/.github/CONTRIBUTING.md
similarity index 93%
rename from CONTRIBUTING.md
rename to .github/CONTRIBUTING.md
index 4889efd2a..bb48037de 100644
--- a/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -4,7 +4,7 @@
- Ensure you're running the latest version of Cryptomator.
- Ensure the bug is related to the desktop version of Cryptomator. Bugs concerning the Cryptomator iOS and Android app can be reported on the [Cryptomator for iOS issues list](https://github.com/cryptomator/cryptomator-ios/issues) and [Cryptomator for Android issues list](https://github.com/cryptomator/cryptomator-android/issues) respectively.
-- Ensure the bug was not [already reported](https://github.com/cryptomator/cryptomator/issues). You can also check out our [FAQ](https://community.cryptomator.org/c/faq).
+- Ensure the bug was not [already reported](https://github.com/cryptomator/cryptomator/issues). You can also check out our [FAQ](https://community.cryptomator.org/c/kb/faq).
- If you're unable to find an open issue addressing the problem, [submit a new one](https://github.com/cryptomator/cryptomator/issues/new).
## Did you write a patch that fixes a bug?
@@ -18,7 +18,7 @@
## Code of Conduct
-Help us keep Cryptomator open and inclusive. Please read and follow our [Code of Conduct](https://github.com/cryptomator/cryptomator/blob/develop/CODE_OF_CONDUCT.md).
+Help us keep Cryptomator open and inclusive. Please read and follow our [Code of Conduct](https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md).
## Above all, thank you for your contributions
diff --git a/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
similarity index 92%
rename from ISSUE_TEMPLATE.md
rename to .github/ISSUE_TEMPLATE.md
index f0908e880..3808d9c0d 100644
--- a/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE.md
@@ -4,8 +4,8 @@ Before creating a new issue make sure that you
- searched existing (and closed) issues: https://github.com/cryptomator/cryptomator/issues
- searched the knowledge base: https://community.cryptomator.org/c/kb
- have read the support guide: https://github.com/cryptomator/cryptomator/blob/develop/SUPPORT.md
-- have read the contribution guide: https://github.com/cryptomator/cryptomator/blob/develop/CONTRIBUTING.md
-- have read the code of conduct: https://github.com/cryptomator/cryptomator/blob/develop/CODE_OF_CONDUCT.md
+- have read the contribution guide: https://github.com/cryptomator/cryptomator/blob/develop/.github/CONTRIBUTING.md
+- have read the code of conduct: https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md
## Basic Info
diff --git a/.github/ISSUE_TEMPLATE/1.4.0-beta-testing.md b/.github/ISSUE_TEMPLATE/1.4.0-beta-testing.md
new file mode 100644
index 000000000..c78c19e22
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/1.4.0-beta-testing.md
@@ -0,0 +1,15 @@
+## 1.4.0 Beta Issue Checklist
+- Existing 1.4.0 Beta Issues: https://github.com/cryptomator/cryptomator/milestone/27
+- Contribution Guide: https://github.com/cryptomator/cryptomator/blob/develop/.github/CONTRIBUTING.md
+- Code of Conduct: https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md
+
+## Software Used During the Test
+- Cryptomator 1.4.0 Beta 1
+- Ubuntu 16.04 / macOS 10.11.6 / etc
+- Linux Kernel x.y.z
+- Gnome x.y.z
+- OpenOffice x.y.z
+- ...
+
+## Description
+What doesn't work? What did you do? How can the bug be reproduced?
diff --git a/.github/no-response.yml b/.github/no-response.yml
new file mode 100644
index 000000000..090694a5b
--- /dev/null
+++ b/.github/no-response.yml
@@ -0,0 +1,13 @@
+# Configuration for probot-no-response - https://github.com/probot/no-response
+
+# Number of days of inactivity before an Issue is closed for lack of response
+daysUntilClose: 14
+# Label requiring a response
+responseRequiredLabel: state:awaiting-response
+# Comment to post when closing an Issue for lack of response. Set to `false` to disable
+closeComment: >
+ This issue has been automatically closed because there has been no response
+ to our request for more information from the original author. With only the
+ information that is currently in the issue, we don't have enough information
+ to take action. Please reach out if you have or find the answers we need so
+ that we can investigate further.
diff --git a/.github/stale.yml b/.github/stale.yml
new file mode 100644
index 000000000..79663c203
--- /dev/null
+++ b/.github/stale.yml
@@ -0,0 +1,19 @@
+# Number of days of inactivity before an issue becomes stale
+daysUntilStale: 60
+# Number of days of inactivity before a stale issue is closed
+daysUntilClose: 7
+# Issues with these labels will never be considered stale
+exemptLabels:
+ - type:security-issue # never close automatically
+ - state:awaiting-response # handled by different bot
+# Set to true to ignore issues in a milestone (defaults to false)
+exemptMilestones: true
+# Label to use when marking an issue as stale
+staleLabel: state:stale
+# Comment to post when marking an issue as stale. Set to `false` to disable
+markComment: >
+ This issue has been automatically marked as stale because it has not had
+ recent activity. It will be closed if no further activity occurs. Thank you
+ for your contributions.
+# Comment to post when closing a stale issue. Set to `false` to disable
+closeComment: false
diff --git a/.travis.yml b/.travis.yml
index 5b65484a0..8d9c59e8e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,7 @@
language: java
sudo: false
jdk:
-- oraclejdk9
+- oraclejdk10
branches:
except:
- continuous # To avoid infinite loops, as this tag is created by this Travis config
@@ -14,6 +14,7 @@ env:
- secure: "lV9OwUbHMrMpLUH1CY+Z4puLDdFXytudyPlG1eGRsesdpuG6KM3uQVz6uAtf6lrU8DRbMM/T7ML+PmvQ4UoPPYLdLxESLLBat2qUPOIVBOhTSlCc7I0DmGy04CSvkeMy8dPaQC0ukgNiR7zwoNzfcpGRN/U9S8tziDruuHoZSrg=" # BINTRAY_API_KEY
- secure: "oWFgRTVP6lyTa7qVxlvkpm20MtVc3BtmsNXQJS6bfg2A0o/iCQMNx7OD59BaafCLGRKvCcJVESiC8FlSylVMS7CDSyYu0gg70NUiIuHp4NBM5inFWYCy/PdQsCTzr5uvNG+rMFQpMFRaCV0FrfM3tLondcVkhsHL68l93Xoexx4=" # CODACY_PROJECT_TOKEN
- secure: "zJxgytA2Ks5Xzv+7kUaUq+EBFNQw9Qec63lcMJVuXVWczjL16nKW1EzzV515ag+OWL46z3lEPForDhufw0VtFnNmaX68jkO0mp01eLrHApc1llN2Y/U8GBXfNNazN4+Kom4H+z/AO+wJr8EsKMMUczCdQ3APgd9uVI0hzXw/Z3M=" # GITHUB_API_KEY
+ - secure: "PiH/o9MLOyPdjIwECIEfj3TuUxx7QB0CIs3o1WXjqb1PbDdHDbQyvswYit6xDw9NrJp/A+ov2k00jq+n+8fLTSd4AY21y5WiJN/ccCTWUuUiFhGxOyM37aeWAPAn4rUp7D7o8jLxEdpGZAfglIzaz+GCEQYxfV/w3FDwztViXgQ=" # GPG_PASSPHRASE
addons:
apt:
packages:
@@ -28,13 +29,8 @@ install:
- curl -o $HOME/.m2/settings.xml https://gist.githubusercontent.com/cryptobot/cf5fbd909c4782aaeeeb7c7f4a1a43da/raw/e60ee486e34ee0c79f89f947abe2c83b4290c6bb/settings.xml
- mvn -fmain/pom.xml clean install -DskipTests org.codehaus.mojo:versions-maven-plugin:help dependency:go-offline -Pcoverage,release # "clean install" needed until we can exclude artifacts currently in the reactor, see https://maven.apache.org/plugins/maven-dependency-plugin/go-offline-mojo.html#excludeReactor and https://issues.apache.org/jira/browse/MDEP-568
script:
-- mvn --update-snapshots -fmain/pom.xml clean test jacoco:report verify -Pcoverage
-after_success:
-- jdk_switcher use oraclejdk8
-- curl -o ~/codacy-coverage-reporter-assembly-latest.jar https://oss.sonatype.org/service/local/repositories/releases/content/com/codacy/codacy-coverage-reporter/2.0.1/codacy-coverage-reporter-2.0.1-assembly.jar
-- $JAVA_HOME/bin/java -cp ~/codacy-coverage-reporter-assembly-latest.jar com.codacy.CodacyCoverageReporter -l Java -r main/jacoco-report/target/site/jacoco-aggregate/jacoco.xml
+- mvn --update-snapshots -fmain/pom.xml clean test verify -Pcoverage
before_deploy:
-- jdk_switcher use oraclejdk9
- |
if [[ $TRAVIS_BRANCH == "develop" ]] && [[ $TRAVIS_PULL_REQUEST == "false" ]]; then
CONTINUOUS_RELEASE_URL=`curl -s https://api.github.com/repos/cryptomator/cryptomator/releases/tags/continuous | jq -re '.url'`
@@ -54,6 +50,8 @@ before_deploy:
git remote remove gh
fi
- mvn -fmain/pom.xml clean package -Prelease -DskipTests
+- gpg --import 34C80F11.gpg
+- gpg --detach-sign -a -u 34C80F11 --batch --passphrase ${GPG_PASSPHRASE} main/ant-kit/target/antkit.zip
deploy:
- provider: releases # CONTINUOUS
prerelease: true
@@ -63,7 +61,8 @@ deploy:
file_glob: true
file:
- "main/uber-jar/target/Cryptomator-*.jar"
- - "main/ant-kit/target/antkit.tar.gz"
+ - "main/ant-kit/target/antkit.zip"
+ - "main/ant-kit/target/antkit.zip.asc"
skip_cleanup: true
name: Cryptomator continuous build
body: Automatically built on $(date +'%F %T %Z').
@@ -76,7 +75,8 @@ deploy:
api_key: $GITHUB_API_KEY
file:
- "main/uber-jar/target/Cryptomator-$TRAVIS_TAG.jar"
- - "main/ant-kit/target/antkit.tar.gz"
+ - "main/ant-kit/target/antkit.zip"
+ - "main/ant-kit/target/antkit.zip.asc"
skip_cleanup: true
on:
repo: cryptomator/cryptomator
@@ -91,3 +91,11 @@ deploy:
on:
repo: cryptomator/cryptomator
tags: true
+after_script:
+- jdk_switcher use oraclejdk8
+- curl -o ~/codacy-coverage-reporter-assembly-latest.jar https://oss.sonatype.org/service/local/repositories/releases/content/com/codacy/codacy-coverage-reporter/4.0.1/codacy-coverage-reporter-4.0.1-assembly.jar
+- $JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter-assembly-latest.jar report -l Java -r main/commons/target/site/jacoco/jacoco.xml --partial
+- $JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter-assembly-latest.jar report -l Java -r main/keychain/target/site/jacoco/jacoco.xml --partial
+- $JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter-assembly-latest.jar report -l Java -r main/ui/target/site/jacoco/jacoco.xml --partial
+- $JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter-assembly-latest.jar report -l Java -r main/launcher/target/site/jacoco/jacoco.xml --partial
+- $JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter-assembly-latest.jar final
diff --git a/34C80F11.gpg b/34C80F11.gpg
new file mode 100644
index 000000000..e40ebc7fe
--- /dev/null
+++ b/34C80F11.gpg
@@ -0,0 +1,57 @@
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+Version: GnuPG v1
+
+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
+=BRSB
+-----END PGP PRIVATE KEY BLOCK-----
\ No newline at end of file
diff --git a/README.md b/README.md
index 1fe176f9a..dc3912b94 100644
--- a/README.md
+++ b/README.md
@@ -46,8 +46,7 @@ For more information on the security details visit [cryptomator.org](https://cry
### Dependencies
-* Java 8 (min. 8u51, we recommend to use the current version)
-* [JCE unlimited strength policy files](http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html) (needed for 256-bit keys)
+* Java 10 (min. 10.0.1, we recommend to use the current version)
* 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))
diff --git a/main/ant-kit/assembly.xml b/main/ant-kit/assembly.xml
index 182a1b654..661711fe4 100644
--- a/main/ant-kit/assembly.xml
+++ b/main/ant-kit/assembly.xml
@@ -4,7 +4,7 @@
tarball
false
- tar.gz
+ zip
diff --git a/main/ant-kit/pom.xml b/main/ant-kit/pom.xml
index 83401f36b..24c4898d1 100644
--- a/main/ant-kit/pom.xml
+++ b/main/ant-kit/pom.xml
@@ -4,7 +4,7 @@
org.cryptomator
main
- 1.4.0-beta1
+ 1.4.0-beta2
ant-kit
pom
@@ -73,7 +73,7 @@
-
+
maven-assembly-plugin
3.1.0
diff --git a/main/ant-kit/src/main/resources/build.xml b/main/ant-kit/src/main/resources/build.xml
index aae41cbe3..7ed445448 100644
--- a/main/ant-kit/src/main/resources/build.xml
+++ b/main/ant-kit/src/main/resources/build.xml
@@ -4,9 +4,14 @@
+
+
+
+
+
-
+
@@ -21,27 +26,26 @@
-
+
-
-
-
-
+
+
+
+
+
-
-
-
+
diff --git a/main/ant-kit/src/main/resources/logback.xml b/main/ant-kit/src/main/resources/logback.xml
deleted file mode 100644
index 1682a356f..000000000
--- a/main/ant-kit/src/main/resources/logback.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
-
-
-
-
- %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
-
-
-
-
- ${user.home}/.Cryptomator/cryptomator.log
- false
-
- ${user.home}/.Cryptomator/cryptomator%i.log
- 0
- 9
-
-
-
- %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
-
-
-
-
- ${user.home}/.Cryptomator/upgrade.log
- true
-
- %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/main/commons/pom.xml b/main/commons/pom.xml
index c6097c3be..b3223aa0c 100644
--- a/main/commons/pom.xml
+++ b/main/commons/pom.xml
@@ -4,7 +4,7 @@
org.cryptomator
main
- 1.4.0-beta1
+ 1.4.0-beta2
commons
Cryptomator Commons
diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/Settings.java b/main/commons/src/main/java/org/cryptomator/common/settings/Settings.java
index bd32a1cb6..7f57122a3 100644
--- a/main/commons/src/main/java/org/cryptomator/common/settings/Settings.java
+++ b/main/commons/src/main/java/org/cryptomator/common/settings/Settings.java
@@ -8,39 +8,34 @@
******************************************************************************/
package org.cryptomator.common.settings;
-import java.util.function.Consumer;
-
-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 javafx.beans.property.*;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
+import java.util.function.Consumer;
+
public class Settings {
public static final int MIN_PORT = 1024;
public static final int MAX_PORT = 65535;
- public static final boolean DEFAULT_CHECK_FOR_UDPATES = true;
+ public static final boolean DEFAULT_ASKED_FOR_UPDATE_CHECK = false;
+ public static final boolean DEFAULT_CHECK_FOR_UDPATES = false;
public static final int DEFAULT_PORT = 42427;
public static final int DEFAULT_NUM_TRAY_NOTIFICATIONS = 3;
public static final String DEFAULT_GVFS_SCHEME = "dav";
public static final boolean DEFAULT_DEBUG_MODE = false;
- public static final VolumeImpl DEFAULT_VOLUME_IMPL = VolumeImpl.FUSE;
+ public static final VolumeImpl DEFAULT_PREFERRED_VOLUME_IMPL = System.getProperty("os.name").toLowerCase().contains("windows") ? VolumeImpl.DOKANY : VolumeImpl.FUSE;
private final ObservableList directories = FXCollections.observableArrayList(VaultSettings::observables);
+ private final BooleanProperty askedForUpdateCheck = new SimpleBooleanProperty(DEFAULT_ASKED_FOR_UPDATE_CHECK);
private final BooleanProperty checkForUpdates = new SimpleBooleanProperty(DEFAULT_CHECK_FOR_UDPATES);
private final IntegerProperty port = new SimpleIntegerProperty(DEFAULT_PORT);
private final IntegerProperty numTrayNotifications = new SimpleIntegerProperty(DEFAULT_NUM_TRAY_NOTIFICATIONS);
private final StringProperty preferredGvfsScheme = new SimpleStringProperty(DEFAULT_GVFS_SCHEME);
private final BooleanProperty debugMode = new SimpleBooleanProperty(DEFAULT_DEBUG_MODE);
- private final ObjectProperty volumeImpl = new SimpleObjectProperty<>(DEFAULT_VOLUME_IMPL);
+ private final ObjectProperty preferredVolumeImpl = new SimpleObjectProperty<>(DEFAULT_PREFERRED_VOLUME_IMPL);
private Consumer saveCmd;
@@ -49,12 +44,13 @@ public class Settings {
*/
Settings() {
directories.addListener((ListChangeListener.Change extends VaultSettings> change) -> this.save());
+ askedForUpdateCheck.addListener(this::somethingChanged);
checkForUpdates.addListener(this::somethingChanged);
port.addListener(this::somethingChanged);
numTrayNotifications.addListener(this::somethingChanged);
preferredGvfsScheme.addListener(this::somethingChanged);
debugMode.addListener(this::somethingChanged);
- volumeImpl.addListener(this::somethingChanged);
+ preferredVolumeImpl.addListener(this::somethingChanged);
}
void setSaveCmd(Consumer saveCmd) {
@@ -77,6 +73,10 @@ public class Settings {
return directories;
}
+ public BooleanProperty askedForUpdateCheck() {
+ return askedForUpdateCheck;
+ }
+
public BooleanProperty checkForUpdates() {
return checkForUpdates;
}
@@ -97,8 +97,8 @@ public class Settings {
return debugMode;
}
- public ObjectProperty volumeImpl() {
- return volumeImpl;
+ public ObjectProperty preferredVolumeImpl() {
+ return preferredVolumeImpl;
}
}
diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/SettingsJsonAdapter.java b/main/commons/src/main/java/org/cryptomator/common/settings/SettingsJsonAdapter.java
index 00dc439f7..2ece80909 100644
--- a/main/commons/src/main/java/org/cryptomator/common/settings/SettingsJsonAdapter.java
+++ b/main/commons/src/main/java/org/cryptomator/common/settings/SettingsJsonAdapter.java
@@ -5,17 +5,16 @@
*******************************************************************************/
package org.cryptomator.common.settings;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
public class SettingsJsonAdapter extends TypeAdapter {
@@ -28,12 +27,13 @@ public class SettingsJsonAdapter extends TypeAdapter {
out.beginObject();
out.name("directories");
writeVaultSettingsArray(out, value.getDirectories());
+ out.name("askedForUpdateCheck").value(value.askedForUpdateCheck().get());
out.name("checkForUpdatesEnabled").value(value.checkForUpdates().get());
out.name("port").value(value.port().get());
out.name("numTrayNotifications").value(value.numTrayNotifications().get());
out.name("preferredGvfsScheme").value(value.preferredGvfsScheme().get());
out.name("debugMode").value(value.debugMode().get());
- out.name("volumeImpl").value(value.volumeImpl().get().name());
+ out.name("preferredVolumeImpl").value(value.preferredVolumeImpl().get().name());
out.endObject();
}
@@ -56,6 +56,9 @@ public class SettingsJsonAdapter extends TypeAdapter {
case "directories":
settings.getDirectories().addAll(readVaultSettingsArray(in));
break;
+ case "askedForUpdateCheck":
+ settings.askedForUpdateCheck().set(in.nextBoolean());
+ break;
case "checkForUpdatesEnabled":
settings.checkForUpdates().set(in.nextBoolean());
break;
@@ -71,8 +74,8 @@ public class SettingsJsonAdapter extends TypeAdapter {
case "debugMode":
settings.debugMode().set(in.nextBoolean());
break;
- case "volumeImpl":
- settings.volumeImpl().set(parseNioAdapterName(in.nextString()));
+ case "preferredVolumeImpl":
+ settings.preferredVolumeImpl().set(parsePreferredVolumeImplName(in.nextString()));
break;
default:
LOG.warn("Unsupported vault setting found in JSON: " + name);
@@ -84,11 +87,11 @@ public class SettingsJsonAdapter extends TypeAdapter {
return settings;
}
- private VolumeImpl parseNioAdapterName(String nioAdapterName) {
+ private VolumeImpl parsePreferredVolumeImplName(String nioAdapterName) {
try {
return VolumeImpl.valueOf(nioAdapterName);
} catch (IllegalArgumentException e) {
- return Settings.DEFAULT_VOLUME_IMPL;
+ return Settings.DEFAULT_PREFERRED_VOLUME_IMPL;
}
}
diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java
index f6a0aa805..1f8510d99 100644
--- a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java
+++ b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java
@@ -26,7 +26,6 @@ import javafx.beans.property.StringProperty;
public class VaultSettings {
public static final boolean DEFAULT_UNLOCK_AFTER_STARTUP = false;
- public static final boolean DEFAULT_MOUNT_AFTER_UNLOCK = true;
public static final boolean DEFAULT_REAVEAL_AFTER_MOUNT = true;
public static final boolean DEFAULT_USES_INDIVIDUAL_MOUNTPATH = false;
@@ -35,7 +34,6 @@ public class VaultSettings {
private final StringProperty mountName = new SimpleStringProperty();
private final StringProperty winDriveLetter = new SimpleStringProperty();
private final BooleanProperty unlockAfterStartup = new SimpleBooleanProperty(DEFAULT_UNLOCK_AFTER_STARTUP);
- private final BooleanProperty mountAfterUnlock = new SimpleBooleanProperty(DEFAULT_MOUNT_AFTER_UNLOCK);
private final BooleanProperty revealAfterMount = new SimpleBooleanProperty(DEFAULT_REAVEAL_AFTER_MOUNT);
private final BooleanProperty usesIndividualMountPath = new SimpleBooleanProperty(DEFAULT_USES_INDIVIDUAL_MOUNTPATH);
private final StringProperty individualMountPath = new SimpleStringProperty();
@@ -47,7 +45,7 @@ public class VaultSettings {
}
Observable[] observables() {
- return new Observable[]{path, mountName, winDriveLetter, unlockAfterStartup, mountAfterUnlock, revealAfterMount, usesIndividualMountPath, individualMountPath};
+ return new Observable[]{path, mountName, winDriveLetter, unlockAfterStartup, revealAfterMount, usesIndividualMountPath, individualMountPath};
}
private void deriveMountNameFromPath(Path path) {
@@ -118,10 +116,6 @@ public class VaultSettings {
return unlockAfterStartup;
}
- public BooleanProperty mountAfterUnlock() {
- return mountAfterUnlock;
- }
-
public BooleanProperty revealAfterMount() {
return revealAfterMount;
}
diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java
index f63ab3c33..5fb30ef88 100644
--- a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java
+++ b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java
@@ -25,7 +25,6 @@ class VaultSettingsJsonAdapter {
out.name("mountName").value(value.mountName().get());
out.name("winDriveLetter").value(value.winDriveLetter().get());
out.name("unlockAfterStartup").value(value.unlockAfterStartup().get());
- out.name("mountAfterUnlock").value(value.mountAfterUnlock().get());
out.name("revealAfterMount").value(value.revealAfterMount().get());
out.name("usesIndividualMountPath").value(value.usesIndividualMountPath().get());
//TODO: should this always be written? ( because it could contain metadata, which the user does not want to save!)
@@ -40,7 +39,6 @@ class VaultSettingsJsonAdapter {
String individualMountPath = null;
String winDriveLetter = null;
boolean unlockAfterStartup = VaultSettings.DEFAULT_UNLOCK_AFTER_STARTUP;
- boolean mountAfterUnlock = VaultSettings.DEFAULT_MOUNT_AFTER_UNLOCK;
boolean revealAfterMount = VaultSettings.DEFAULT_REAVEAL_AFTER_MOUNT;
boolean usesIndividualMountPath = VaultSettings.DEFAULT_USES_INDIVIDUAL_MOUNTPATH;
@@ -63,9 +61,6 @@ class VaultSettingsJsonAdapter {
case "unlockAfterStartup":
unlockAfterStartup = in.nextBoolean();
break;
- case "mountAfterUnlock":
- mountAfterUnlock = in.nextBoolean();
- break;
case "revealAfterMount":
revealAfterMount = in.nextBoolean();
break;
@@ -87,7 +82,6 @@ class VaultSettingsJsonAdapter {
vaultSettings.path().set(Paths.get(path));
vaultSettings.winDriveLetter().set(winDriveLetter);
vaultSettings.unlockAfterStartup().set(unlockAfterStartup);
- vaultSettings.mountAfterUnlock().set(mountAfterUnlock);
vaultSettings.revealAfterMount().set(revealAfterMount);
vaultSettings.usesIndividualMountPath().set(usesIndividualMountPath);
vaultSettings.individualMountPath().set(individualMountPath);
diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/VolumeImpl.java b/main/commons/src/main/java/org/cryptomator/common/settings/VolumeImpl.java
index 0862c499b..634f528f4 100644
--- a/main/commons/src/main/java/org/cryptomator/common/settings/VolumeImpl.java
+++ b/main/commons/src/main/java/org/cryptomator/common/settings/VolumeImpl.java
@@ -4,7 +4,8 @@ import java.util.Arrays;
public enum VolumeImpl {
WEBDAV("WebDAV"),
- FUSE("FUSE");
+ FUSE("FUSE"),
+ DOKANY("DOKANY");
private String displayName;
diff --git a/main/commons/src/test/java/org/cryptomator/common/settings/SettingsJsonAdapterTest.java b/main/commons/src/test/java/org/cryptomator/common/settings/SettingsJsonAdapterTest.java
index 511197d29..cee09295a 100644
--- a/main/commons/src/test/java/org/cryptomator/common/settings/SettingsJsonAdapterTest.java
+++ b/main/commons/src/test/java/org/cryptomator/common/settings/SettingsJsonAdapterTest.java
@@ -22,7 +22,7 @@ public class SettingsJsonAdapterTest {
+ "\"checkForUpdatesEnabled\": true,"//
+ "\"port\": 8080,"//
+ "\"numTrayNotifications\": 42,"//
- + "\"volumeImpl\": \"FUSE\"}";
+ + "\"preferredVolumeImpl\": \"FUSE\"}";
Settings settings = adapter.fromJson(json);
@@ -31,7 +31,7 @@ public class SettingsJsonAdapterTest {
Assert.assertEquals(8080, settings.port().get());
Assert.assertEquals(42, settings.numTrayNotifications().get());
Assert.assertEquals("dav", settings.preferredGvfsScheme().get());
- Assert.assertEquals(VolumeImpl.FUSE, settings.volumeImpl().get());
+ Assert.assertEquals(VolumeImpl.FUSE, settings.preferredVolumeImpl().get());
}
}
diff --git a/main/jacoco-report/.gitignore b/main/jacoco-report/.gitignore
deleted file mode 100644
index b83d22266..000000000
--- a/main/jacoco-report/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/target/
diff --git a/main/jacoco-report/pom.xml b/main/jacoco-report/pom.xml
deleted file mode 100644
index cd65ba3dd..000000000
--- a/main/jacoco-report/pom.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-
-
- 4.0.0
-
- org.cryptomator
- main
- 1.4.0-beta1
-
- jacoco-report
- Cryptomator Code Coverage Report
- pom
-
-
-
-
- org.cryptomator
- commons
-
-
- org.cryptomator
- keychain
-
-
- org.cryptomator
- ui
-
-
- org.cryptomator
- launcher
-
-
-
-
-
-
- org.jacoco
- jacoco-maven-plugin
-
-
- report-aggregate
- verify
-
- report-aggregate
-
-
-
-
-
-
-
diff --git a/main/keychain/pom.xml b/main/keychain/pom.xml
index 084fafbf0..211a29688 100644
--- a/main/keychain/pom.xml
+++ b/main/keychain/pom.xml
@@ -4,7 +4,7 @@
org.cryptomator
main
- 1.4.0-beta1
+ 1.4.0-beta2
keychain
System Keychain Access
diff --git a/main/launcher/pom.xml b/main/launcher/pom.xml
index ca4a8bfac..a3e8ca84b 100644
--- a/main/launcher/pom.xml
+++ b/main/launcher/pom.xml
@@ -4,7 +4,7 @@
org.cryptomator
main
- 1.4.0-beta1
+ 1.4.0-beta2
launcher
Cryptomator Launcher
diff --git a/main/launcher/src/main/java/org/cryptomator/launcher/Cryptomator.java b/main/launcher/src/main/java/org/cryptomator/launcher/Cryptomator.java
index 171447c6c..8a97e336d 100644
--- a/main/launcher/src/main/java/org/cryptomator/launcher/Cryptomator.java
+++ b/main/launcher/src/main/java/org/cryptomator/launcher/Cryptomator.java
@@ -37,6 +37,8 @@ public class Cryptomator {
}
} catch (IOException e) {
LOG.error("Failed to initiate inter-process communication.", e);
+ } catch (Throwable e) {
+ LOG.error("Error during startup", e);
}
System.exit(0); // end remaining non-daemon threads.
}
diff --git a/main/pom.xml b/main/pom.xml
index 7ff14adfd..f909bfe57 100644
--- a/main/pom.xml
+++ b/main/pom.xml
@@ -3,7 +3,7 @@
4.0.0
org.cryptomator
main
- 1.4.0-beta1
+ 1.4.0-beta2
pom
Cryptomator
@@ -26,25 +26,26 @@
1.2.0
1.5.2
- 1.0.4
2.0.0
- 0.1.4
+ 0.1.5
+ 0.1.2
+ 1.0.4
2.5
3.6
1.0.3
-
- 24.1-jre
- 2.14.1
- 2.8.2
-
+
+ 25.1-jre
+ 2.16
+ 2.8.5
+
1.7.25
1.2.3
-
+
4.12
4.12.1
- 2.11.0
+ 2.19.0
1.3
@@ -59,6 +60,10 @@
true
+
+ jcenter
+ http://jcenter.bintray.com
+
@@ -101,6 +106,11 @@
fuse-nio-adapter
${cryptomator.fuse.version}
+
+ org.cryptomator
+ dokany-nio-adapter
+ ${cryptomator.dokany.version}
+
org.cryptomator
webdav-nio-adapter
@@ -245,9 +255,6 @@
coverage
-
- jacoco-report
-
@@ -289,6 +296,12 @@
prepare-agent
+
+ report
+
+ report
+
+
@@ -304,9 +317,9 @@
maven-compiler-plugin
3.7.0
- 9
- 9
- 9
+ 10
+ 10
+ 10
--add-modules
jdk.incubator.httpclient
diff --git a/main/uber-jar/pom.xml b/main/uber-jar/pom.xml
index 8e9da7d37..6b87edde7 100644
--- a/main/uber-jar/pom.xml
+++ b/main/uber-jar/pom.xml
@@ -4,7 +4,7 @@
org.cryptomator
main
- 1.4.0-beta1
+ 1.4.0-beta2
uber-jar
Single über jar with all dependencies
diff --git a/main/ui/pom.xml b/main/ui/pom.xml
index 4b3f8098a..96f74d750 100644
--- a/main/ui/pom.xml
+++ b/main/ui/pom.xml
@@ -4,35 +4,40 @@
org.cryptomator
main
- 1.4.0-beta1
+ 1.4.0-beta2
ui
Cryptomator GUI
+
+ org.cryptomator
+ keychain
+
org.cryptomator
commons
+
org.cryptomator
cryptofs
-
- org.cryptomator
- webdav-nio-adapter
-
org.cryptomator
jni
org.cryptomator
- keychain
+ fuse-nio-adapter
org.cryptomator
- fuse-nio-adapter
+ dokany-nio-adapter
+
+
+ org.cryptomator
+ webdav-nio-adapter
diff --git a/main/ui/src/main/java/org/cryptomator/ui/ExitUtil.java b/main/ui/src/main/java/org/cryptomator/ui/ExitUtil.java
index 6694c21b4..eca371bbf 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/ExitUtil.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/ExitUtil.java
@@ -53,6 +53,7 @@ public class ExitUtil {
private final Localization localization;
private final Settings settings;
private final Optional macFunctions;
+ private TrayIcon trayIcon;
@Inject
public ExitUtil(@Named("mainWindow") Stage mainWindow, Localization localization, Settings settings, Optional macFunctions) {
@@ -82,7 +83,7 @@ public class ExitUtil {
}
private void initTrayIconExitHandler(Runnable exitCommand) {
- final TrayIcon trayIcon = createTrayIcon(exitCommand);
+ trayIcon = createTrayIcon(exitCommand);
try {
// double clicking tray icon should open Cryptomator
if (SystemUtils.IS_OS_WINDOWS) {
@@ -118,14 +119,7 @@ public class ExitUtil {
exitItem.addActionListener(e -> exitCommand.run());
popup.add(exitItem);
- final Image image;
- if (SystemUtils.IS_OS_MAC_OSX && isMacMenuBarDarkMode()) {
- image = Toolkit.getDefaultToolkit().getImage(getClass().getResource("/tray_icon_mac_white.png"));
- } else if (SystemUtils.IS_OS_MAC_OSX) {
- image = Toolkit.getDefaultToolkit().getImage(getClass().getResource("/tray_icon_mac_black.png"));
- } else {
- image = Toolkit.getDefaultToolkit().getImage(getClass().getResource("/tray_icon.png"));
- }
+ final Image image = getAppropriateTrayIconImage(true);
return new TrayIcon(image, localization.getString("app.name"), popup);
}
@@ -202,4 +196,23 @@ public class ExitUtil {
});
}
+ public void updateTrayIcon(boolean areAllVaultsLocked) {
+ if (trayIcon != null) {
+ Image image = getAppropriateTrayIconImage(areAllVaultsLocked);
+ trayIcon.setImage(image);
+ }
+ }
+
+ private Image getAppropriateTrayIconImage(boolean areAllVaultsLocked) {
+ String resourceName;
+ if (SystemUtils.IS_OS_MAC_OSX && isMacMenuBarDarkMode()) {
+ resourceName = areAllVaultsLocked ? "/tray_icon_mac_white.png" : "/tray_icon_unlocked_mac_white.png";
+ } else if (SystemUtils.IS_OS_MAC_OSX) {
+ resourceName = areAllVaultsLocked ? "/tray_icon_mac_black.png" : "/tray_icon_unlocked_mac_black.png";
+ } else {
+ resourceName = areAllVaultsLocked ? "/tray_icon.png" : "/tray_icon_unlocked.png";
+ }
+ return Toolkit.getDefaultToolkit().getImage(getClass().getResource(resourceName));
+ }
+
}
diff --git a/main/ui/src/main/java/org/cryptomator/ui/UiModule.java b/main/ui/src/main/java/org/cryptomator/ui/UiModule.java
index 4bcc9b877..8b94936b0 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/UiModule.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/UiModule.java
@@ -11,6 +11,8 @@ package org.cryptomator.ui;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import javax.inject.Named;
@@ -32,16 +34,38 @@ import org.fxmisc.easybind.EasyBind;
@Module(includes = {ViewControllerModule.class, CommonsModule.class, KeychainModule.class}, subcomponents = {VaultComponent.class})
public class UiModule {
+ private static final int NUM_SCHEDULER_THREADS = 4;
+
@Provides
@Singleton
Settings provideSettings(SettingsProvider settingsProvider) {
return settingsProvider.get();
}
+ @Provides
+ @Singleton
+ ScheduledExecutorService provideScheduledExecutorService(@Named("shutdownTaskScheduler") Consumer shutdownTaskScheduler) {
+ final AtomicInteger threadNumber = new AtomicInteger(1);
+ ScheduledExecutorService executorService = Executors.newScheduledThreadPool(NUM_SCHEDULER_THREADS, r -> {
+ Thread t = new Thread(r);
+ t.setName("Scheduler Thread " + threadNumber.getAndIncrement());
+ t.setDaemon(true);
+ return t;
+ });
+ shutdownTaskScheduler.accept(executorService::shutdown);
+ return executorService;
+ }
+
@Provides
@Singleton
ExecutorService provideExecutorService(@Named("shutdownTaskScheduler") Consumer shutdownTaskScheduler) {
- ExecutorService executorService = Executors.newCachedThreadPool();
+ final AtomicInteger threadNumber = new AtomicInteger(1);
+ ExecutorService executorService = Executors.newCachedThreadPool(r -> {
+ Thread t = new Thread(r);
+ t.setName("Background Thread " + threadNumber.getAndIncrement());
+ t.setDaemon(true);
+ return t;
+ });
shutdownTaskScheduler.accept(executorService::shutdown);
return executorService;
}
diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java
index 0f6010eec..e0e4d70e5 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java
@@ -125,6 +125,7 @@ public class MainController implements ViewController {
this.upgradeStrategyForSelectedVault = EasyBind.monadic(selectedVault).map(upgradeStrategies::getUpgradeStrategy);
this.areAllVaultsLocked = Bindings.isEmpty(FXCollections.observableList(vaults, Vault::observables).filtered(Vault.NOT_LOCKED));
+ EasyBind.subscribe(areAllVaultsLocked, exitUtil::updateTrayIcon);
EasyBind.subscribe(areAllVaultsLocked, Platform::setImplicitExit);
autoUnlocker.unlockAllSilently();
@@ -395,7 +396,7 @@ public class MainController implements ViewController {
return;
}
if (newValue.getState() != Vault.State.LOCKED) {
- this.showUnlockedView(newValue);
+ this.showUnlockedView(newValue, false);
} else if (!newValue.doesVaultDirectoryExist()) {
this.showNotFoundView();
} else if (newValue.isValidVaultDirectory() && upgradeStrategyForSelectedVault.isPresent()) {
@@ -494,22 +495,25 @@ public class MainController implements ViewController {
public void didUnlock(Vault vault) {
if (vault.equals(selectedVault.getValue())) {
- this.showUnlockedView(vault);
+ this.showUnlockedView(vault, vault.getVaultSettings().revealAfterMount().getValue());
}
}
- private void showUnlockedView(Vault vault) {
- final UnlockedController ctrl = unlockedVaults.computeIfAbsent(vault, k -> {
- return viewControllerLoader.load("/fxml/unlocked.fxml");
- });
+ private void showUnlockedView(Vault vault, boolean reveal) {
+ final UnlockedController ctrl = unlockedVaults.computeIfAbsent(vault, k -> viewControllerLoader.load("/fxml/unlocked.fxml"));
ctrl.setVault(vault);
ctrl.setListener(this::didLock);
+ if (reveal) {
+ ctrl.revealVault(vault);
+ }
activeController.set(ctrl);
}
public void didLock(UnlockedController ctrl) {
unlockedVaults.remove(ctrl.getVault());
- showUnlockView(UnlockController.State.UNLOCKING);
+ if (ctrl.getVault().getId() == selectedVault.get().getId()) {
+ showUnlockView(UnlockController.State.UNLOCKING);
+ }
activeController.get().focus();
}
diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/SettingsController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/SettingsController.java
index f4b997314..0cc884943 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/controllers/SettingsController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/SettingsController.java
@@ -77,9 +77,6 @@ public class SettingsController implements ViewController {
@FXML
private ChoiceBox prefGvfsScheme;
- @FXML
- private Label volumeLabel;
-
@FXML
private ChoiceBox volume;
@@ -97,8 +94,7 @@ public class SettingsController implements ViewController {
//NIOADAPTER
volume.getItems().addAll(getSupportedAdapters());
- volume.setValue(settings.volumeImpl().get());
- volume.setVisible(true);
+ volume.setValue(settings.preferredVolumeImpl().get());
volume.setConverter(new NioAdapterImplStringConverter());
//WEBDAV
@@ -127,13 +123,13 @@ public class SettingsController implements ViewController {
settings.checkForUpdates().bind(checkForUpdatesCheckbox.selectedProperty());
settings.preferredGvfsScheme().bind(prefGvfsScheme.valueProperty());
- settings.volumeImpl().bind(volume.valueProperty());
+ settings.preferredVolumeImpl().bind(volume.valueProperty());
settings.debugMode().bind(debugModeCheckbox.selectedProperty());
}
- //TODO: how to implement this?
private VolumeImpl[] getSupportedAdapters() {
- return new VolumeImpl[]{VolumeImpl.FUSE, VolumeImpl.WEBDAV};
+ // TODO: filter depending on supported drivers
+ return VolumeImpl.values();
}
@Override
diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java
index fe2c2ca90..2001e50b6 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java
@@ -8,41 +8,21 @@
******************************************************************************/
package org.cryptomator.ui.controllers;
-import java.io.IOException;
-import java.nio.file.*;
+import javax.inject.Inject;
+import java.nio.file.Files;
+import java.nio.file.InvalidPathException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Objects;
import java.util.Optional;
-
-import javax.inject.Inject;
-
-import javafx.beans.binding.Bindings;
-import javafx.scene.layout.HBox;
-import org.apache.commons.lang3.CharUtils;
-import org.apache.commons.lang3.SystemUtils;
-import org.cryptomator.common.settings.VolumeImpl;
-import org.cryptomator.common.settings.Settings;
-import org.cryptomator.common.settings.VaultSettings;
-import org.cryptomator.cryptolib.api.InvalidPassphraseException;
-import org.cryptomator.cryptolib.api.UnsupportedVaultFormatException;
-import org.cryptomator.frontend.webdav.ServerLifecycleException;
-import org.cryptomator.keychain.KeychainAccess;
-import org.cryptomator.ui.controls.SecPasswordField;
-import org.cryptomator.ui.l10n.Localization;
-import org.cryptomator.ui.model.Vault;
-import org.cryptomator.ui.model.WindowsDriveLetters;
-import org.cryptomator.ui.util.AsyncTaskService;
-import org.cryptomator.ui.util.DialogBuilderUtil;
-import org.fxmisc.easybind.EasyBind;
-import org.fxmisc.easybind.Subscription;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.util.concurrent.ExecutorService;
import com.google.common.base.CharMatcher;
import com.google.common.base.Strings;
-
import javafx.application.Application;
+import javafx.beans.binding.Bindings;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
@@ -59,8 +39,28 @@ import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.GridPane;
+import javafx.scene.layout.HBox;
import javafx.scene.text.Text;
import javafx.util.StringConverter;
+import org.apache.commons.lang3.CharUtils;
+import org.apache.commons.lang3.SystemUtils;
+import org.cryptomator.common.settings.Settings;
+import org.cryptomator.common.settings.VaultSettings;
+import org.cryptomator.common.settings.VolumeImpl;
+import org.cryptomator.cryptolib.api.InvalidPassphraseException;
+import org.cryptomator.cryptolib.api.UnsupportedVaultFormatException;
+import org.cryptomator.frontend.webdav.ServerLifecycleException;
+import org.cryptomator.keychain.KeychainAccess;
+import org.cryptomator.ui.controls.SecPasswordField;
+import org.cryptomator.ui.l10n.Localization;
+import org.cryptomator.ui.model.Vault;
+import org.cryptomator.ui.model.WindowsDriveLetters;
+import org.cryptomator.ui.util.DialogBuilderUtil;
+import org.cryptomator.ui.util.Tasks;
+import org.fxmisc.easybind.EasyBind;
+import org.fxmisc.easybind.Subscription;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class UnlockController implements ViewController {
@@ -73,23 +73,23 @@ public class UnlockController implements ViewController {
private final Application app;
private final Localization localization;
- private final AsyncTaskService asyncTaskService;
private final WindowsDriveLetters driveLetters;
private final ChangeListener driveLetterChangeListener = this::winDriveLetterDidChange;
private final Optional keychainAccess;
private final Settings settings;
+ private final ExecutorService executor;
private Vault vault;
private Optional listener = Optional.empty();
private Subscription vaultSubs = Subscription.EMPTY;
@Inject
- public UnlockController(Application app, Localization localization, AsyncTaskService asyncTaskService, WindowsDriveLetters driveLetters, Optional keychainAccess, Settings settings) {
+ public UnlockController(Application app, Localization localization, WindowsDriveLetters driveLetters, Optional keychainAccess, Settings settings, ExecutorService executor) {
this.app = app;
this.localization = localization;
- this.asyncTaskService = asyncTaskService;
this.driveLetters = driveLetters;
this.keychainAccess = keychainAccess;
this.settings = settings;
+ this.executor = executor;
}
@FXML
@@ -107,9 +107,6 @@ public class UnlockController implements ViewController {
@FXML
private CheckBox savePassword;
- @FXML
- private CheckBox mountAfterUnlock;
-
@FXML
private TextField mountName;
@@ -159,8 +156,6 @@ public class UnlockController implements ViewController {
public void initialize() {
advancedOptions.managedProperty().bind(advancedOptions.visibleProperty());
unlockButton.disableProperty().bind(passwordField.textProperty().isEmpty());
- mountName.disableProperty().bind(mountAfterUnlock.selectedProperty().not());
- revealAfterMount.disableProperty().bind(mountAfterUnlock.selectedProperty().not());
mountName.addEventFilter(KeyEvent.KEY_TYPED, this::filterAlphanumericKeyEvents);
mountName.textProperty().addListener(this::mountNameDidChange);
savePassword.setDisable(!keychainAccess.isPresent());
@@ -186,7 +181,7 @@ public class UnlockController implements ViewController {
winDriveLetterLabel.setManaged(false);
winDriveLetter.setVisible(false);
winDriveLetter.setManaged(false);
- if (VolumeImpl.WEBDAV.equals(settings.volumeImpl().get())) {
+ if (VolumeImpl.WEBDAV.equals(settings.preferredVolumeImpl().get())) {
useOwnMountPath.setVisible(false);
useOwnMountPath.setManaged(false);
mountPathLabel.setManaged(false);
@@ -250,12 +245,10 @@ public class UnlockController implements ViewController {
}
VaultSettings vaultSettings = vault.getVaultSettings();
unlockAfterStartup.setSelected(savePassword.isSelected() && vaultSettings.unlockAfterStartup().get());
- mountAfterUnlock.setSelected(vaultSettings.mountAfterUnlock().get());
revealAfterMount.setSelected(vaultSettings.revealAfterMount().get());
useOwnMountPath.setSelected(vaultSettings.usesIndividualMountPath().get());
vaultSubs = vaultSubs.and(EasyBind.subscribe(unlockAfterStartup.selectedProperty(), vaultSettings.unlockAfterStartup()::set));
- vaultSubs = vaultSubs.and(EasyBind.subscribe(mountAfterUnlock.selectedProperty(), vaultSettings.mountAfterUnlock()::set));
vaultSubs = vaultSubs.and(EasyBind.subscribe(revealAfterMount.selectedProperty(), vaultSettings.revealAfterMount()::set));
vaultSubs = vaultSubs.and(EasyBind.subscribe(useOwnMountPath.selectedProperty(), vaultSettings.usesIndividualMountPath()::set));
@@ -430,7 +423,7 @@ public class UnlockController implements ViewController {
progressIndicator.setVisible(true);
CharSequence password = passwordField.getCharacters();
- asyncTaskService.asyncTaskOf(() -> {
+ Tasks.create(() -> {
vault.unlock(password);
if (keychainAccess.isPresent() && savePassword.isSelected()) {
keychainAccess.get().storePassphrase(vault.getId(), password);
@@ -457,16 +450,16 @@ public class UnlockController implements ViewController {
}).onError(ServerLifecycleException.class, e -> {
LOG.error("Unlock failed for technical reasons.", e);
messageText.setText(localization.getString("unlock.errorMessage.unlockFailed"));
- }).onError(IOException.class, e -> {
- LOG.error("Unlock failed for technical reasons.", e);
- messageText.setText(localization.getString("unlock.errorMessage.unlockFailed"));
+ }).onError(Exception.class, e -> {
+ LOG.error("Unlock failed for technical reasons.", e);
+ messageText.setText(localization.getString("unlock.errorMessage.unlockFailed"));
}).andFinally(() -> {
if (!savePassword.isSelected()) {
passwordField.swipe();
}
advancedOptions.setDisable(false);
progressIndicator.setVisible(false);
- }).run();
+ }).runOnce(executor);
}
/* callback */
diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockedController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockedController.java
index d1f0e0417..3143f8c3d 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockedController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockedController.java
@@ -8,29 +8,13 @@
******************************************************************************/
package org.cryptomator.ui.controllers;
-import static java.lang.String.format;
-
-import java.io.IOException;
-import java.util.Optional;
-
import javax.inject.Inject;
-
-import org.cryptomator.frontend.webdav.ServerLifecycleException;
-import org.cryptomator.frontend.webdav.mount.Mounter.CommandFailedException;
-import org.cryptomator.ui.l10n.Localization;
-import org.cryptomator.ui.model.Vault;
-import org.cryptomator.ui.util.AsyncTaskService;
-import org.cryptomator.ui.util.DialogBuilderUtil;
-import org.fxmisc.easybind.EasyBind;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.util.concurrent.Runnables;
+import java.util.Optional;
+import java.util.concurrent.ExecutorService;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
-import javafx.beans.binding.ObjectExpression;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.event.ActionEvent;
@@ -46,13 +30,19 @@ import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
-import javafx.scene.control.MenuItem;
import javafx.scene.control.ToggleButton;
-import javafx.scene.input.Clipboard;
-import javafx.scene.input.ClipboardContent;
import javafx.scene.layout.VBox;
import javafx.stage.PopupWindow.AnchorLocation;
import javafx.util.Duration;
+import org.cryptomator.ui.l10n.Localization;
+import org.cryptomator.ui.model.Vault;
+import org.cryptomator.ui.util.DialogBuilderUtil;
+import org.cryptomator.ui.util.Tasks;
+import org.fxmisc.easybind.EasyBind;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static java.lang.String.format;
public class UnlockedController implements ViewController {
@@ -62,9 +52,8 @@ public class UnlockedController implements ViewController {
private static final double IO_SAMPLING_INTERVAL = 0.25;
private final Localization localization;
- private final AsyncTaskService asyncTaskService;
+ private final ExecutorService executor;
private final ObjectProperty vault = new SimpleObjectProperty<>();
- private final ObjectExpression vaultState = ObjectExpression.objectExpression(EasyBind.select(vault).selectObject(Vault::stateProperty));
private Optional listener = Optional.empty();
private Timeline ioAnimation;
@@ -83,30 +72,17 @@ public class UnlockedController implements ViewController {
@FXML
private ContextMenu moreOptionsMenu;
- @FXML
- private MenuItem mountVaultMenuItem;
-
- @FXML
- private MenuItem unmountVaultMenuItem;
-
- @FXML
- private MenuItem revealVaultMenuItem;
-
@FXML
private VBox root;
@Inject
- public UnlockedController(Localization localization, AsyncTaskService asyncTaskService) {
+ public UnlockedController(Localization localization, ExecutorService executor) {
this.localization = localization;
- this.asyncTaskService = asyncTaskService;
+ this.executor = executor;
}
@Override
public void initialize() {
- mountVaultMenuItem.disableProperty().bind(vaultState.isEqualTo(Vault.State.UNLOCKED).not()); // enable when unlocked
- unmountVaultMenuItem.disableProperty().bind(vaultState.isEqualTo(Vault.State.MOUNTED).not()); // enable when mounted
- revealVaultMenuItem.disableProperty().bind(vaultState.isEqualTo(Vault.State.MOUNTED).not()); // enable when mounted
-
EasyBind.subscribe(vault, this::vaultChanged);
EasyBind.subscribe(moreOptionsMenu.showingProperty(), moreOptionsButton::setSelected);
}
@@ -121,10 +97,6 @@ public class UnlockedController implements ViewController {
return;
}
- if (newVault.getState() == Vault.State.UNLOCKED && newVault.getVaultSettings().mountAfterUnlock().get()) {
- mountVault(newVault);
- }
-
// (re)start throughput statistics:
stopIoSampling();
startIoSampling();
@@ -132,75 +104,22 @@ public class UnlockedController implements ViewController {
@FXML
private void didClickLockVault(ActionEvent event) {
- regularUnmountVault(this::lockVault);
+ regularLockVault(this::lockVaultSucceeded);
}
- private void lockVault() {
- try {
- vault.get().lock();
- } catch (ServerLifecycleException | IOException e) {
- LOG.error("Lock failed", e);
- }
+ private void lockVaultSucceeded() {
listener.ifPresent(listener -> listener.didLock(this));
}
- @FXML
- private void didClickMoreOptions(ActionEvent event) {
- if (moreOptionsMenu.isShowing()) {
- moreOptionsMenu.hide();
- } else {
- moreOptionsMenu.setAnchorLocation(AnchorLocation.CONTENT_TOP_RIGHT);
- moreOptionsMenu.show(moreOptionsButton, Side.BOTTOM, moreOptionsButton.getWidth(), 0.0);
- }
- }
-
- @FXML
- public void didClickMountVault(ActionEvent event) {
- mountVault(vault.get());
- }
-
- private void mountVault(Vault vault) {
- asyncTaskService.asyncTaskOf(() -> {
- vault.mount();
- }).onSuccess(() -> {
- LOG.trace("Mount succeeded.");
- messageLabel.setText(null);
- if (vault.getVaultSettings().revealAfterMount().get()) {
- revealVault(vault);
- }
- }).onError(CommandFailedException.class, e -> {
- LOG.error("Mount failed.", e);
- // TODO Markus Kreusch #393: hyperlink auf FAQ oder sowas?
- messageLabel.setText(localization.getString("unlocked.label.mountFailed"));
- }).run();
- }
-
- @FXML
- public void didClickUnmountVault(ActionEvent event) {
- regularUnmountVault(Runnables.doNothing());
- }
-
- private void regularUnmountVault(Runnable onSuccess) {
- asyncTaskService.asyncTaskOf(() -> {
- vault.get().unmount();
+ private void regularLockVault(Runnable onSuccess) {
+ Tasks.create(() -> {
+ vault.get().lock(false);
}).onSuccess(() -> {
LOG.trace("Regular unmount succeeded.");
onSuccess.run();
}).onError(Exception.class, e -> {
onRegularUnmountVaultFailed(e, onSuccess);
- }).run();
- }
-
- private void forcedUnmountVault(Runnable onSuccess) {
- asyncTaskService.asyncTaskOf(() -> {
- vault.get().unmountForced();
- }).onSuccess(() -> {
- LOG.trace("Forced unmount succeeded.");
- onSuccess.run();
- }).onError(Exception.class, e -> {
- LOG.error("Forced unmount failed.", e);
- messageLabel.setText(localization.getString("unlocked.label.unmountFailed"));
- }).run();
+ }).runOnce(executor);
}
private void onRegularUnmountVaultFailed(Exception e, Runnable onSuccess) {
@@ -214,7 +133,7 @@ public class UnlockedController implements ViewController {
Optional choice = confirmDialog.showAndWait();
if (ButtonType.YES.equals(choice.get())) {
- forcedUnmountVault(onSuccess);
+ forcedLockVault(onSuccess);
} else {
LOG.trace("Unmount cancelled.", e);
}
@@ -224,29 +143,43 @@ public class UnlockedController implements ViewController {
}
}
+ private void forcedLockVault(Runnable onSuccess) {
+ Tasks.create(() -> {
+ vault.get().lock(true);
+ }).onSuccess(() -> {
+ LOG.trace("Forced unmount succeeded.");
+ onSuccess.run();
+ }).onError(Exception.class, e -> {
+ LOG.error("Forced unmount failed.", e);
+ messageLabel.setText(localization.getString("unlocked.label.unmountFailed"));
+ }).runOnce(executor);
+ }
+
+ @FXML
+ private void didClickMoreOptions(ActionEvent event) {
+ if (moreOptionsMenu.isShowing()) {
+ moreOptionsMenu.hide();
+ } else {
+ moreOptionsMenu.setAnchorLocation(AnchorLocation.CONTENT_TOP_RIGHT);
+ moreOptionsMenu.show(moreOptionsButton, Side.BOTTOM, moreOptionsButton.getWidth(), 0.0);
+ }
+ }
+
@FXML
private void didClickRevealVault(ActionEvent event) {
revealVault(vault.get());
}
- private void revealVault(Vault vault) {
- asyncTaskService.asyncTaskOf(() -> {
+ void revealVault(Vault vault) {
+ Tasks.create(() -> {
vault.reveal();
}).onSuccess(() -> {
LOG.trace("Reveal succeeded.");
messageLabel.setText(null);
- }).onError(CommandFailedException.class, e -> {
+ }).onError(Exception.class, e -> {
LOG.error("Reveal failed.", e);
messageLabel.setText(localization.getString("unlocked.label.revealFailed"));
- }).run();
- }
-
- @FXML
- private void didClickCopyUrl(ActionEvent event) {
- ClipboardContent clipboardContent = new ClipboardContent();
- clipboardContent.putUrl(vault.get().getFilesystemRootUrl());
- clipboardContent.putString(vault.get().getFilesystemRootUrl());
- Clipboard.getSystemClipboard().setContent(clipboardContent);
+ }).runOnce(executor);
}
// ****************************************
diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/UpgradeController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/UpgradeController.java
index 2d7cb7fa9..1eb0c7307 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/controllers/UpgradeController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/UpgradeController.java
@@ -5,19 +5,10 @@
*******************************************************************************/
package org.cryptomator.ui.controllers;
+import javax.inject.Inject;
import java.util.Objects;
import java.util.Optional;
-
-import javax.inject.Inject;
-
-import org.cryptomator.ui.controls.SecPasswordField;
-import org.cryptomator.ui.l10n.Localization;
-import org.cryptomator.ui.model.UpgradeStrategies;
-import org.cryptomator.ui.model.UpgradeStrategy;
-import org.cryptomator.ui.model.UpgradeStrategy.UpgradeFailedException;
-import org.cryptomator.ui.model.Vault;
-import org.cryptomator.ui.util.AsyncTaskService;
-import org.fxmisc.easybind.EasyBind;
+import java.util.concurrent.ExecutorService;
import javafx.beans.binding.BooleanExpression;
import javafx.beans.property.ObjectProperty;
@@ -30,19 +21,26 @@ import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.GridPane;
+import org.cryptomator.ui.controls.SecPasswordField;
+import org.cryptomator.ui.model.UpgradeStrategies;
+import org.cryptomator.ui.model.UpgradeStrategy;
+import org.cryptomator.ui.model.UpgradeStrategy.UpgradeFailedException;
+import org.cryptomator.ui.model.Vault;
+import org.cryptomator.ui.util.Tasks;
+import org.fxmisc.easybind.EasyBind;
public class UpgradeController implements ViewController {
private final ObjectProperty strategy = new SimpleObjectProperty<>();
private final UpgradeStrategies strategies;
- private final AsyncTaskService asyncTaskService;
+ private final ExecutorService executor;
private Optional listener = Optional.empty();
private Vault vault;
@Inject
- public UpgradeController(Localization localization, UpgradeStrategies strategies, AsyncTaskService asyncTaskService) {
+ public UpgradeController(UpgradeStrategies strategies, ExecutorService executor) {
this.strategies = strategies;
- this.asyncTaskService = asyncTaskService;
+ this.executor = executor;
}
@FXML
@@ -122,8 +120,8 @@ public class UpgradeController implements ViewController {
private void upgrade(UpgradeStrategy instruction) {
passwordField.setDisable(true);
progressIndicator.setVisible(true);
- asyncTaskService //
- .asyncTaskOf(() -> {
+ Tasks //
+ .create(() -> {
if (!instruction.isApplicable(vault)) {
throw new IllegalStateException("No ugprade needed for " + vault.getPath());
}
@@ -137,7 +135,7 @@ public class UpgradeController implements ViewController {
progressIndicator.setVisible(false);
passwordField.setDisable(false);
passwordField.swipe();
- }).run();
+ }).runOnce(executor);
}
private void showNextUpgrade() {
diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/WelcomeController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/WelcomeController.java
index aed401acc..353576862 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/controllers/WelcomeController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/WelcomeController.java
@@ -2,24 +2,27 @@
* Copyright (c) 2014, 2017 Sebastian Stenzel
* All rights reserved.
* This program and the accompanying materials are made available under the terms of the accompanying LICENSE file.
- *
+ *
* Contributors:
* Sebastian Stenzel - initial API and implementation
******************************************************************************/
package org.cryptomator.ui.controllers;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;
-import java.time.Duration;
import java.util.Comparator;
import java.util.Map;
import java.util.Optional;
import java.util.ResourceBundle;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -30,20 +33,20 @@ import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.Parent;
+import javafx.scene.control.ButtonType;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.VBox;
-import jdk.incubator.http.HttpClient;
-import jdk.incubator.http.HttpRequest;
-import jdk.incubator.http.HttpResponse;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.ui.l10n.Localization;
-import org.cryptomator.ui.util.AsyncTaskService;
+import org.cryptomator.ui.util.Tasks;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static org.cryptomator.ui.util.DialogBuilderUtil.buildYesNoDialog;
+
@Singleton
public class WelcomeController implements ViewController {
@@ -54,17 +57,17 @@ public class WelcomeController implements ViewController {
private final Localization localization;
private final Settings settings;
private final Comparator semVerComparator;
- private final AsyncTaskService asyncTaskService;
+ private final ScheduledExecutorService executor;
@Inject
public WelcomeController(Application app, @Named("applicationVersion") Optional applicationVersion, Localization localization, Settings settings, @Named("SemVer") Comparator semVerComparator,
- AsyncTaskService asyncTaskService) {
+ ScheduledExecutorService executor) {
this.app = app;
this.applicationVersion = applicationVersion;
this.localization = localization;
this.settings = settings;
this.semVerComparator = semVerComparator;
- this.asyncTaskService = asyncTaskService;
+ this.executor = executor;
}
@FXML
@@ -86,6 +89,8 @@ public class WelcomeController implements ViewController {
public void initialize(URL location, ResourceBundle resources) {
if (areUpdatesManagedExternally()) {
checkForUpdatesContainer.setVisible(false);
+ } else if (!settings.askedForUpdateCheck().get()) {
+ this.askForUpdateCheck();
} else if (settings.checkForUpdates().get()) {
this.checkForUpdates();
}
@@ -104,34 +109,63 @@ public class WelcomeController implements ViewController {
return Boolean.parseBoolean(System.getProperty("cryptomator.updatesManagedExternally", "false"));
}
+ private void askForUpdateCheck() {
+ Tasks.create(() -> {}).onSuccess(() -> {
+ Optional result = buildYesNoDialog(
+ localization.getString("welcome.askForUpdateCheck.dialog.title"),
+ localization.getString("welcome.askForUpdateCheck.dialog.header"),
+ localization.getString("welcome.askForUpdateCheck.dialog.content"),
+ ButtonType.YES).showAndWait();
+ if (result.isPresent()) {
+ settings.askedForUpdateCheck().set(true);
+ settings.checkForUpdates().set(result.get().equals(ButtonType.YES));
+ }
+ if (settings.checkForUpdates().get()) {
+ this.checkForUpdates();
+ }
+ }).scheduleOnce(executor, 1, TimeUnit.SECONDS);
+ }
+
private void checkForUpdates() {
checkForUpdatesStatus.setText(localization.getString("welcome.checkForUpdates.label.currentlyChecking"));
checkForUpdatesIndicator.setVisible(true);
- asyncTaskService.asyncTaskOf(() -> {
+ Tasks.create(() -> {
String userAgent = String.format("Cryptomator VersionChecker/%s %s %s (%s)", applicationVersion.orElse("SNAPSHOT"), SystemUtils.OS_NAME, SystemUtils.OS_VERSION, SystemUtils.OS_ARCH);
- HttpClient client = HttpClient.newHttpClient();
- HttpRequest request = HttpRequest.newBuilder()
- .GET()
- .uri(new URI("https://api.cryptomator.org/updates/latestVersion.json"))
- .header("User-Agent", userAgent)
- .timeout(Duration.ofSeconds(5))
- .build();
- HttpResponse response = client.send(request, HttpResponse.BodyHandler.asString(StandardCharsets.UTF_8));
- if (response.statusCode() == 200) {
+ URL url = URI.create("https://api.cryptomator.org/updates/latestVersion.json").toURL();
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ conn.addRequestProperty("User-Agent", userAgent);
+ conn.connect();
+ try {
+ if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
+ return Optional.empty();
+ }
+ try (InputStream in = conn.getInputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+ in.transferTo(out);
+ return Optional.of(out.toByteArray());
+ }
+ } finally {
+ conn.disconnect();
+ }
+ }).onSuccess(response -> {
+ response.ifPresent(bytes -> {
Gson gson = new GsonBuilder().setLenient().create();
- Map map = gson.fromJson(response.body(), new TypeToken