diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index d6cb2c866..0c9e1cbd8 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -36,6 +36,9 @@
+
+
+
diff --git a/main/commons/pom.xml b/main/commons/pom.xml
index 54e711559..a6d00c2db 100644
--- a/main/commons/pom.xml
+++ b/main/commons/pom.xml
@@ -44,7 +44,7 @@
- org.fxmisc.easybind
+ com.tobiasdiez
easybind
diff --git a/main/commons/src/main/java/org/cryptomator/common/CommonsModule.java b/main/commons/src/main/java/org/cryptomator/common/CommonsModule.java
index bac0114da..93e0d3d44 100644
--- a/main/commons/src/main/java/org/cryptomator/common/CommonsModule.java
+++ b/main/commons/src/main/java/org/cryptomator/common/CommonsModule.java
@@ -5,6 +5,7 @@
*******************************************************************************/
package org.cryptomator.common;
+import com.tobiasdiez.easybind.EasyBind;
import dagger.Module;
import dagger.Provides;
import javafx.beans.binding.Binding;
@@ -17,7 +18,6 @@ import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultComponent;
import org.cryptomator.common.vaults.VaultListManager;
import org.cryptomator.frontend.webdav.WebDavServer;
-import org.fxmisc.easybind.EasyBind;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/UiTheme.java b/main/commons/src/main/java/org/cryptomator/common/settings/UiTheme.java
index a8b66c65c..8df1e7f89 100644
--- a/main/commons/src/main/java/org/cryptomator/common/settings/UiTheme.java
+++ b/main/commons/src/main/java/org/cryptomator/common/settings/UiTheme.java
@@ -1,11 +1,21 @@
package org.cryptomator.common.settings;
-public enum UiTheme {
- LIGHT("preferences.general.theme.light"),
- DARK("preferences.general.theme.dark");
- // CUSTOM("Custom (%s)");
+import org.apache.commons.lang3.SystemUtils;
- private String displayName;
+public enum UiTheme {
+ LIGHT("preferences.general.theme.light"), //
+ DARK("preferences.general.theme.dark"), //
+ AUTOMATIC("preferences.general.theme.automatic");
+
+ public static UiTheme[] applicableValues() {
+ if (SystemUtils.IS_OS_MAC) {
+ return values();
+ } else {
+ return new UiTheme[]{LIGHT, DARK};
+ }
+ }
+
+ private final String displayName;
UiTheme(String displayName) {
this.displayName = displayName;
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 13a0c8eed..a440b2bab 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
@@ -7,6 +7,7 @@ package org.cryptomator.common.settings;
import com.google.common.base.Strings;
import com.google.common.io.BaseEncoding;
+import com.tobiasdiez.easybind.EasyBind;
import javafx.beans.Observable;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty;
@@ -17,7 +18,6 @@ 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.file.Path;
import java.util.Objects;
diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSecretServiceKeychainAccessImpl.java b/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSecretServiceKeychainAccessImpl.java
index 675992e5c..48b76fccb 100644
--- a/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSecretServiceKeychainAccessImpl.java
+++ b/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSecretServiceKeychainAccessImpl.java
@@ -28,6 +28,9 @@ class LinuxSecretServiceKeychainAccessImpl implements KeychainAccessStrategy {
if (list == null) {
keyring.createItem(LABEL_FOR_SECRET_IN_KEYRING, passphrase, createAttributes(key));
}
+ else {
+ changePassphrase(key, passphrase);
+ }
} catch (IOException e) {
throw new KeychainAccessException(e);
}
diff --git a/main/pom.xml b/main/pom.xml
index d4fe8da87..8702b89d9 100644
--- a/main/pom.xml
+++ b/main/pom.xml
@@ -25,18 +25,18 @@
1.9.12
- 2.2.2
+ 2.2.3
1.2.3
1.1.15
- 1.0.11
+ 1.0.12
14
- 3.10
- 1.0.0
+ 3.11
+ 1.1.0
1.0.1
3.10.3
- 1.0.3
+ 2.1.0
29.0-jre
2.22
2.8.6
@@ -184,7 +184,7 @@
- org.fxmisc.easybind
+ com.tobiasdiez
easybind
${easybind.version}
diff --git a/main/ui/pom.xml b/main/ui/pom.xml
index c27fbb1aa..0991215cc 100644
--- a/main/ui/pom.xml
+++ b/main/ui/pom.xml
@@ -35,7 +35,7 @@
- org.fxmisc.easybind
+ com.tobiasdiez
easybind
diff --git a/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java b/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java
index 5b4549db1..c1f224529 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java
@@ -1,5 +1,6 @@
package org.cryptomator.ui.addvaultwizard;
+import com.tobiasdiez.easybind.EasyBind;
import dagger.Lazy;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
@@ -83,11 +84,11 @@ public class CreateNewVaultLocationController implements FxController {
public void initialize() {
predefinedLocationToggler.selectedToggleProperty().addListener(this::togglePredefinedLocation);
usePresetPath.bind(predefinedLocationToggler.selectedToggleProperty().isNotEqualTo(customRadioButton));
- vaultPath.addListener(this::vaultPathDidChange);
+ EasyBind.subscribe(vaultPath, this::vaultPathDidChange);
}
- private void vaultPathDidChange(@SuppressWarnings("unused") ObservableValue extends Path> observable, @SuppressWarnings("unused") Path oldValue, Path newValue) {
- if (!Files.notExists(newValue)) {
+ private void vaultPathDidChange(Path newValue) {
+ if ( newValue != null && !Files.notExists(newValue)) {
warningText.set(resourceBundle.getString("addvaultwizard.new.fileAlreadyExists"));
} else {
warningText.set(null);
diff --git a/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultPasswordController.java b/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultPasswordController.java
index 2c2f3885a..87152f7b5 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultPasswordController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultPasswordController.java
@@ -32,7 +32,6 @@ import javax.inject.Named;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.channels.WritableByteChannel;
-import java.nio.file.FileAlreadyExistsException;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
diff --git a/main/ui/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordController.java b/main/ui/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordController.java
index 7a641b1e7..2d9998fb1 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordController.java
@@ -53,9 +53,10 @@ public class ChangePasswordController implements FxController {
@FXML
public void initialize() {
- BooleanBinding hasNotConfirmedCheckbox = finalConfirmationCheckbox.selectedProperty().not();
- BooleanBinding isInvalidNewPassword = Bindings.createBooleanBinding(() -> newPassword.get() == null || newPassword.get().length() == 0, newPassword);
- finishButton.disableProperty().bind(hasNotConfirmedCheckbox.or(isInvalidNewPassword));
+ BooleanBinding checkboxNotConfirmed = finalConfirmationCheckbox.selectedProperty().not();
+ BooleanBinding oldPasswordFieldEmpty = oldPasswordField.textProperty().isEmpty();
+ BooleanBinding newPasswordInvalid = Bindings.createBooleanBinding(() -> newPassword.get() == null || newPassword.get().length() == 0, newPassword);
+ finishButton.disableProperty().bind(checkboxNotConfirmed.or(oldPasswordFieldEmpty).or(newPasswordInvalid));
}
@FXML
@@ -96,5 +97,5 @@ public class ChangePasswordController implements FxController {
public Vault getVault() {
return vault;
}
-
+
}
diff --git a/main/ui/src/main/java/org/cryptomator/ui/common/NewPasswordController.java b/main/ui/src/main/java/org/cryptomator/ui/common/NewPasswordController.java
index 2d0c424eb..310a2379d 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/common/NewPasswordController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/common/NewPasswordController.java
@@ -1,5 +1,6 @@
package org.cryptomator.ui.common;
+import com.tobiasdiez.easybind.EasyBind;
import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
@@ -10,7 +11,6 @@ import javafx.fxml.FXML;
import javafx.scene.control.Label;
import org.cryptomator.ui.controls.FontAwesome5IconView;
import org.cryptomator.ui.controls.NiceSecurePasswordField;
-import org.fxmisc.easybind.EasyBind;
import java.util.ResourceBundle;
@@ -24,9 +24,12 @@ public class NewPasswordController implements FxController {
public NiceSecurePasswordField passwordField;
public NiceSecurePasswordField reenterField;
public Label passwordStrengthLabel;
+ public FontAwesome5IconView passwordStrengthCheckmark;
+ public FontAwesome5IconView passwordStrengthWarning;
+ public FontAwesome5IconView passwordStrengthCross;
public Label passwordMatchLabel;
- public FontAwesome5IconView checkmark;
- public FontAwesome5IconView cross;
+ public FontAwesome5IconView passwordMatchCheckmark;
+ public FontAwesome5IconView passwordMatchCross;
public NewPasswordController(ResourceBundle resourceBundle, PasswordStrengthUtil strengthRater, ObjectProperty password) {
this.resourceBundle = resourceBundle;
@@ -36,19 +39,33 @@ public class NewPasswordController implements FxController {
@FXML
public void initialize() {
+ passwordStrength.bind(Bindings.createIntegerBinding(() -> strengthRater.computeRate(passwordField.getCharacters()), passwordField.textProperty()));
+
+ passwordStrengthLabel.graphicProperty().bind(Bindings.createObjectBinding(this::getIconViewForPasswordStrengthLabel, passwordField.textProperty(), passwordStrength));
+ passwordStrengthLabel.textProperty().bind(EasyBind.map(passwordStrength, strengthRater::getStrengthDescription));
+
BooleanBinding passwordsMatch = Bindings.createBooleanBinding(this::hasSamePasswordInBothFields, passwordField.textProperty(), reenterField.textProperty());
BooleanBinding reenterFieldNotEmpty = reenterField.textProperty().isNotEmpty();
- passwordStrength.bind(Bindings.createIntegerBinding(() -> strengthRater.computeRate(passwordField.getCharacters()), passwordField.textProperty()));
- passwordStrengthLabel.textProperty().bind(EasyBind.map(passwordStrength, strengthRater::getStrengthDescription));
-
passwordMatchLabel.visibleProperty().bind(reenterFieldNotEmpty);
- passwordMatchLabel.graphicProperty().bind(Bindings.when(passwordsMatch.and(reenterFieldNotEmpty)).then(checkmark).otherwise(cross));
+ passwordMatchLabel.graphicProperty().bind(Bindings.when(passwordsMatch.and(reenterFieldNotEmpty)).then(passwordMatchCheckmark).otherwise(passwordMatchCross));
passwordMatchLabel.textProperty().bind(Bindings.when(passwordsMatch.and(reenterFieldNotEmpty)).then(resourceBundle.getString("newPassword.passwordsMatch")).otherwise(resourceBundle.getString("newPassword.passwordsDoNotMatch")));
passwordField.textProperty().addListener(this::passwordsDidChange);
reenterField.textProperty().addListener(this::passwordsDidChange);
}
+ private FontAwesome5IconView getIconViewForPasswordStrengthLabel() {
+ if (passwordField.getCharacters().length() == 0) {
+ return null;
+ } else if (passwordStrength.intValue() <= -1) {
+ return passwordStrengthCross;
+ } else if (passwordStrength.intValue() < 3) {
+ return passwordStrengthWarning;
+ } else {
+ return passwordStrengthCheckmark;
+ }
+ }
+
private void passwordsDidChange(@SuppressWarnings("unused") Observable observable) {
if (hasSamePasswordInBothFields() && strengthRater.fulfillsMinimumRequirements(passwordField.getCharacters())) {
password.set(passwordField.getCharacters());
diff --git a/main/ui/src/main/java/org/cryptomator/ui/controls/DraggableListCell.java b/main/ui/src/main/java/org/cryptomator/ui/controls/DraggableListCell.java
index 62f87c1f4..ca78bcac6 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/controls/DraggableListCell.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/controls/DraggableListCell.java
@@ -8,6 +8,7 @@
*******************************************************************************/
package org.cryptomator.ui.controls;
+import com.tobiasdiez.easybind.EasyBind;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.SnapshotParameters;
@@ -18,7 +19,6 @@ import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
-import org.fxmisc.easybind.EasyBind;
import java.util.List;
diff --git a/main/ui/src/main/java/org/cryptomator/ui/controls/FontAwesome5Icon.java b/main/ui/src/main/java/org/cryptomator/ui/controls/FontAwesome5Icon.java
index 7334b69da..f4d0d058a 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/controls/FontAwesome5Icon.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/controls/FontAwesome5Icon.java
@@ -6,11 +6,13 @@ package org.cryptomator.ui.controls;
public enum FontAwesome5Icon {
ANCHOR("\uF13D"), //
ARROW_UP("\uF062"), //
+ BUG("\uF188"), //
CHECK("\uF00C"), //
COG("\uF013"), //
COGS("\uF085"), //
COPY("\uF0C5"), //
CROWN("\uF521"), //
+ EDIT("\uF044"), //
EXCLAMATION("\uF12A"), //
EXCLAMATION_CIRCLE("\uF06A"), //
EXCLAMATION_TRIANGLE("\uF071"), //
@@ -37,6 +39,7 @@ public enum FontAwesome5Icon {
SPINNER("\uF110"), //
SYNC("\uF021"), //
TIMES("\uF00D"), //
+ TRASH("\uF1F8"), //
UNLINK("\uf127"), //
WRENCH("\uF0AD"), //
WINDOW_MINIMIZE("\uF2D1"), //
diff --git a/main/ui/src/main/java/org/cryptomator/ui/controls/PasswordStrengthIndicator.java b/main/ui/src/main/java/org/cryptomator/ui/controls/PasswordStrengthIndicator.java
index a1619968b..156da3b0b 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/controls/PasswordStrengthIndicator.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/controls/PasswordStrengthIndicator.java
@@ -1,12 +1,12 @@
package org.cryptomator.ui.controls;
+import com.tobiasdiez.easybind.EasyBind;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
-import org.fxmisc.easybind.EasyBind;
public class PasswordStrengthIndicator extends HBox {
diff --git a/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java b/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java
index 3172b6288..e862b8045 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java
@@ -1,12 +1,12 @@
package org.cryptomator.ui.fxapp;
+import com.tobiasdiez.easybind.EasyBind;
import dagger.Lazy;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.value.ObservableValue;
-import javafx.collections.FXCollections;
import javafx.collections.ObservableSet;
import javafx.stage.Stage;
import org.cryptomator.common.LicenseHolder;
@@ -46,6 +46,8 @@ public class FxApplication extends Application {
private final LicenseHolder licenseHolder;
private final BooleanBinding hasVisibleStages;
+ private Optional macApperanceObserverIdentifier = Optional.empty();
+
@Inject
FxApplication(Settings settings, Lazy mainWindow, Lazy preferencesWindow, Provider unlockWindowBuilderProvider, Provider quitWindowBuilderProvider, Optional macFunctions, VaultService vaultService, LicenseHolder licenseHolder, ObservableSet visibleStages) {
this.settings = settings;
@@ -63,7 +65,7 @@ public class FxApplication extends Application {
LOG.trace("FxApplication.start()");
Platform.setImplicitExit(false);
- hasVisibleStages.addListener(this::hasVisibleStagesChanged);
+ EasyBind.subscribe(hasVisibleStages, this::hasVisibleStagesChanged);
settings.theme().addListener(this::themeChanged);
loadSelectedStyleSheet(settings.theme().get());
@@ -74,7 +76,7 @@ public class FxApplication extends Application {
throw new UnsupportedOperationException("Use start() instead.");
}
- private void hasVisibleStagesChanged(@SuppressWarnings("unused") ObservableValue extends Boolean> observableValue, @SuppressWarnings("unused") boolean oldValue, boolean newValue) {
+ private void hasVisibleStagesChanged(boolean newValue) {
if (newValue) {
macFunctions.map(MacFunctions::uiState).ifPresent(MacApplicationUiState::transformToForegroundApplication);
} else {
@@ -115,21 +117,44 @@ public class FxApplication extends Application {
}
private void themeChanged(@SuppressWarnings("unused") ObservableValue extends UiTheme> observable, @SuppressWarnings("unused") UiTheme oldValue, UiTheme newValue) {
+ if (macApperanceObserverIdentifier.isPresent()) {
+ macFunctions.map(MacFunctions::uiAppearance).ifPresent(uiAppearance -> uiAppearance.removeListener(macApperanceObserverIdentifier.get()));
+ macApperanceObserverIdentifier = Optional.empty();
+ }
loadSelectedStyleSheet(newValue);
}
private void loadSelectedStyleSheet(UiTheme desiredTheme) {
UiTheme theme = licenseHolder.isValidLicense() ? desiredTheme : UiTheme.LIGHT;
switch (theme) {
- case DARK -> {
- Application.setUserAgentStylesheet(getClass().getResource("/css/dark_theme.css").toString());
- macFunctions.map(MacFunctions::uiAppearance).ifPresent(JniException.ignore(MacApplicationUiAppearance::setToDarkAqua));
- }
- case LIGHT -> {
- Application.setUserAgentStylesheet(getClass().getResource("/css/light_theme.css").toString());
- macFunctions.map(MacFunctions::uiAppearance).ifPresent(JniException.ignore(MacApplicationUiAppearance::setToAqua));
+ case LIGHT -> setToLightTheme();
+ case DARK -> setToDarkTheme();
+ case AUTOMATIC -> {
+ macFunctions.map(MacFunctions::uiAppearance).ifPresent(uiAppearance -> {
+ macApperanceObserverIdentifier = Optional.of(uiAppearance.addListener(this::macInterfaceThemeChanged));
+ });
+ macInterfaceThemeChanged();
}
}
}
+ private void macInterfaceThemeChanged() {
+ macFunctions.map(MacFunctions::uiAppearance).ifPresent(uiAppearance -> {
+ switch (uiAppearance.getCurrentInterfaceStyle()) {
+ case LIGHT -> setToLightTheme();
+ case DARK -> setToDarkTheme();
+ }
+ });
+ }
+
+ private void setToLightTheme() {
+ Application.setUserAgentStylesheet(getClass().getResource("/css/light_theme.css").toString());
+ macFunctions.map(MacFunctions::uiAppearance).ifPresent(JniException.ignore(MacApplicationUiAppearance::setToAqua));
+ }
+
+ private void setToDarkTheme() {
+ Application.setUserAgentStylesheet(getClass().getResource("/css/dark_theme.css").toString());
+ macFunctions.map(MacFunctions::uiAppearance).ifPresent(JniException.ignore(MacApplicationUiAppearance::setToDarkAqua));
+ }
+
}
diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/MainWindowTitleController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/MainWindowTitleController.java
index 53044e00a..1f8fbc271 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/MainWindowTitleController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/MainWindowTitleController.java
@@ -1,10 +1,12 @@
package org.cryptomator.ui.mainwindow;
+import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.fxml.FXML;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import org.cryptomator.common.LicenseHolder;
+import org.cryptomator.common.settings.Settings;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.fxapp.FxApplication;
import org.cryptomator.ui.fxapp.UpdateChecker;
@@ -30,12 +32,14 @@ public class MainWindowTitleController implements FxController {
private final UpdateChecker updateChecker;
private final BooleanBinding updateAvailable;
private final LicenseHolder licenseHolder;
+ private final Settings settings;
+ private final BooleanBinding debugModeEnabled;
private double xOffset;
private double yOffset;
@Inject
- MainWindowTitleController(AppLifecycleListener appLifecycle, @MainWindow Stage window, FxApplication application, @Named("trayMenuSupported") boolean minimizeToSysTray, UpdateChecker updateChecker, LicenseHolder licenseHolder) {
+ MainWindowTitleController(AppLifecycleListener appLifecycle, @MainWindow Stage window, FxApplication application, @Named("trayMenuSupported") boolean minimizeToSysTray, UpdateChecker updateChecker, LicenseHolder licenseHolder, Settings settings) {
this.appLifecycle = appLifecycle;
this.window = window;
this.application = application;
@@ -43,6 +47,8 @@ public class MainWindowTitleController implements FxController {
this.updateChecker = updateChecker;
this.updateAvailable = updateChecker.latestVersionProperty().isNotNull();
this.licenseHolder = licenseHolder;
+ this.settings = settings;
+ this.debugModeEnabled = Bindings.createBooleanBinding(this::isDebugModeEnabled, settings.debugMode());
}
@FXML
@@ -82,6 +88,11 @@ public class MainWindowTitleController implements FxController {
application.showPreferencesWindow(SelectedPreferencesTab.ANY);
}
+ @FXML
+ public void showGeneralPreferences() {
+ application.showPreferencesWindow(SelectedPreferencesTab.GENERAL);
+ }
+
@FXML
public void showDonationKeyPreferences() {
application.showPreferencesWindow(SelectedPreferencesTab.DONATION_KEY);
@@ -104,4 +115,12 @@ public class MainWindowTitleController implements FxController {
public boolean isMinimizeToSysTray() {
return minimizeToSysTray;
}
+
+ public BooleanBinding debugModeEnabledProperty() {
+ return debugModeEnabled;
+ }
+
+ public boolean isDebugModeEnabled() {
+ return settings.debugMode().get();
+ }
}
diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailController.java
index 36a746039..e384a67bc 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailController.java
@@ -1,5 +1,6 @@
package org.cryptomator.ui.mainwindow;
+import com.tobiasdiez.easybind.EasyBind;
import javafx.beans.binding.Binding;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.ObjectProperty;
@@ -10,7 +11,6 @@ import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.controls.FontAwesome5Icon;
import org.cryptomator.ui.fxapp.FxApplication;
-import org.fxmisc.easybind.EasyBind;
import javax.inject.Inject;
@@ -26,17 +26,23 @@ public class VaultDetailController implements FxController {
VaultDetailController(ObjectProperty vault, FxApplication application) {
this.vault = vault;
this.application = application;
- this.glyph = EasyBind.select(vault).selectObject(Vault::stateProperty).map(this::getGlyphForVaultState).orElse(FontAwesome5Icon.EXCLAMATION_TRIANGLE);
+ this.glyph = EasyBind.select(vault) //
+ .selectObject(Vault::stateProperty) //
+ .map(this::getGlyphForVaultState);
this.anyVaultSelected = vault.isNotNull();
}
private FontAwesome5Icon getGlyphForVaultState(VaultState state) {
- return switch (state) {
- case LOCKED -> FontAwesome5Icon.LOCK;
- case PROCESSING -> FontAwesome5Icon.SPINNER;
- case UNLOCKED -> FontAwesome5Icon.LOCK_OPEN;
- case NEEDS_MIGRATION, MISSING, ERROR -> FontAwesome5Icon.EXCLAMATION_TRIANGLE;
- };
+ if (state != null) {
+ return switch (state) {
+ case LOCKED -> FontAwesome5Icon.LOCK;
+ case PROCESSING -> FontAwesome5Icon.SPINNER;
+ case UNLOCKED -> FontAwesome5Icon.LOCK_OPEN;
+ case NEEDS_MIGRATION, MISSING, ERROR -> FontAwesome5Icon.EXCLAMATION_TRIANGLE;
+ };
+ } else {
+ return FontAwesome5Icon.EXCLAMATION_TRIANGLE;
+ }
}
@FXML
diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailLockedController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailLockedController.java
index 55720521b..f615d51ca 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailLockedController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailLockedController.java
@@ -1,5 +1,6 @@
package org.cryptomator.ui.mainwindow;
+import com.tobiasdiez.easybind.EasyBind;
import javafx.beans.binding.BooleanExpression;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
@@ -11,7 +12,6 @@ import org.cryptomator.keychain.KeychainManager;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.fxapp.FxApplication;
import org.cryptomator.ui.vaultoptions.VaultOptionsComponent;
-import org.fxmisc.easybind.EasyBind;
import javax.inject.Inject;
import java.util.Optional;
diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailMissingVaultController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailMissingVaultController.java
index f54bc447b..095743490 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailMissingVaultController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailMissingVaultController.java
@@ -1,26 +1,55 @@
package org.cryptomator.ui.mainwindow;
import javafx.beans.property.ObjectProperty;
-import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.fxml.FXML;
+import javafx.stage.FileChooser;
+import javafx.stage.Stage;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultListManager;
import org.cryptomator.ui.common.FxController;
+import org.cryptomator.ui.removevault.RemoveVaultComponent;
import javax.inject.Inject;
+import java.io.File;
+import java.util.ResourceBundle;
@MainWindowScoped
public class VaultDetailMissingVaultController implements FxController {
- private final ReadOnlyObjectProperty vault;
+ private final ObjectProperty vault;
+ private final RemoveVaultComponent.Builder removeVault;
+ private final ResourceBundle resourceBundle;
+ private final Stage window;
+
@Inject
- public VaultDetailMissingVaultController(ObjectProperty vault) {
+ public VaultDetailMissingVaultController(ObjectProperty vault, RemoveVaultComponent.Builder removeVault, ResourceBundle resourceBundle, @MainWindow Stage window) {
this.vault = vault;
+ this.removeVault = removeVault;
+ this.resourceBundle = resourceBundle;
+ this.window = window;
}
@FXML
public void recheck() {
VaultListManager.redetermineVaultState(vault.get());
}
+
+ @FXML
+ void didClickRemoveVault() {
+ removeVault.vault(vault.get()).build().showRemoveVault();
+ }
+
+ @FXML
+ void changeLocation() {
+ // copied from ChooseExistingVaultController class
+ FileChooser fileChooser = new FileChooser();
+ fileChooser.setTitle(resourceBundle.getString("addvaultwizard.existing.filePickerTitle"));
+ fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Cryptomator Masterkey", "*.cryptomator"));
+ File masterkeyFile = fileChooser.showOpenDialog(window);
+ if (masterkeyFile != null) {
+ vault.get().getVaultSettings().path().setValue(masterkeyFile.toPath().toAbsolutePath().getParent());
+ recheck();
+ }
+ }
}
diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnknownErrorController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnknownErrorController.java
index 4c23ba4ae..b975174f8 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnknownErrorController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnknownErrorController.java
@@ -1,10 +1,10 @@
package org.cryptomator.ui.mainwindow;
+import com.tobiasdiez.easybind.EasyBind;
import javafx.beans.binding.Binding;
import javafx.beans.property.ObjectProperty;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.common.FxController;
-import org.fxmisc.easybind.EasyBind;
import javax.inject.Inject;
import java.io.ByteArrayOutputStream;
@@ -18,14 +18,20 @@ public class VaultDetailUnknownErrorController implements FxController {
@Inject
public VaultDetailUnknownErrorController(ObjectProperty vault) {
- this.stackTrace = EasyBind.select(vault).selectObject(Vault::lastKnownExceptionProperty).map(this::provideStackTrace).orElse("");
+ this.stackTrace = EasyBind.select(vault) //
+ .selectObject(Vault::lastKnownExceptionProperty) //
+ .map(this::provideStackTrace);
}
private String provideStackTrace(Throwable cause) {
// TODO deduplicate ErrorModule.java
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- cause.printStackTrace(new PrintStream(baos));
- return baos.toString(StandardCharsets.UTF_8);
+ if (cause != null) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ cause.printStackTrace(new PrintStream(baos));
+ return baos.toString(StandardCharsets.UTF_8);
+ } else {
+ return "";
+ }
}
/* Getter/Setter */
diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListCellController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListCellController.java
index 6703ec674..999afaaf1 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListCellController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListCellController.java
@@ -1,5 +1,6 @@
package org.cryptomator.ui.mainwindow;
+import com.tobiasdiez.easybind.EasyBind;
import javafx.beans.binding.Binding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
@@ -7,7 +8,6 @@ import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.controls.FontAwesome5Icon;
-import org.fxmisc.easybind.EasyBind;
import javax.inject.Inject;
@@ -19,16 +19,22 @@ public class VaultListCellController implements FxController {
@Inject
VaultListCellController() {
- this.glyph = EasyBind.select(vault).selectObject(Vault::stateProperty).map(this::getGlyphForVaultState).orElse(FontAwesome5Icon.EXCLAMATION_TRIANGLE);
+ this.glyph = EasyBind.select(vault) //
+ .selectObject(Vault::stateProperty) //
+ .map(this::getGlyphForVaultState);
}
private FontAwesome5Icon getGlyphForVaultState(VaultState state) {
- return switch (state) {
- case LOCKED -> FontAwesome5Icon.LOCK;
- case PROCESSING -> FontAwesome5Icon.SPINNER;
- case UNLOCKED -> FontAwesome5Icon.LOCK_OPEN;
- case NEEDS_MIGRATION, MISSING, ERROR -> FontAwesome5Icon.EXCLAMATION_TRIANGLE;
- };
+ if(state != null){
+ return switch (state) {
+ case LOCKED -> FontAwesome5Icon.LOCK;
+ case PROCESSING -> FontAwesome5Icon.SPINNER;
+ case UNLOCKED -> FontAwesome5Icon.LOCK_OPEN;
+ case NEEDS_MIGRATION, MISSING, ERROR -> FontAwesome5Icon.EXCLAMATION_TRIANGLE;
+ };
+ } else {
+ return FontAwesome5Icon.EXCLAMATION_TRIANGLE;
+ }
}
/* Getter/Setter */
diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java
index c0a6c7720..d1aecb19f 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java
@@ -1,16 +1,15 @@
package org.cryptomator.ui.mainwindow;
+import com.tobiasdiez.easybind.EasyBind;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.ObjectProperty;
-import javafx.beans.value.ObservableValue;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.ListView;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultListManager;
-import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.ui.addvaultwizard.AddVaultWizardComponent;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.removevault.RemoveVaultComponent;
@@ -18,7 +17,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
-import java.io.IOException;
@MainWindowScoped
public class VaultListController implements FxController {
@@ -43,7 +41,7 @@ public class VaultListController implements FxController {
this.removeVault = removeVault;
this.noVaultSelected = selectedVault.isNull();
this.emptyVaultList = Bindings.isEmpty(vaults);
- selectedVault.addListener(this::selectedVaultDidChange);
+ EasyBind.subscribe(selectedVault, this::selectedVaultDidChange);
}
public void initialize() {
@@ -60,11 +58,10 @@ public class VaultListController implements FxController {
});
}
- private void selectedVaultDidChange(@SuppressWarnings("unused") ObservableValue extends Vault> observableValue, @SuppressWarnings("unused") Vault oldValue, Vault newValue) {
- if (newValue == null) {
- return;
+ private void selectedVaultDidChange(Vault newValue) {
+ if (newValue != null) {
+ VaultListManager.redetermineVaultState(newValue);
}
- VaultListManager.redetermineVaultState(newValue);
}
@FXML
diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/DonationKeyPreferencesController.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/DonationKeyPreferencesController.java
index 476887b26..21a2d3d9a 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/preferences/DonationKeyPreferencesController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/preferences/DonationKeyPreferencesController.java
@@ -5,23 +5,27 @@ import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.scene.control.TextArea;
import org.cryptomator.common.LicenseHolder;
+import org.cryptomator.common.settings.Settings;
+import org.cryptomator.common.settings.UiTheme;
import org.cryptomator.ui.common.FxController;
import javax.inject.Inject;
@PreferencesScoped
public class DonationKeyPreferencesController implements FxController {
-
+
private static final String DONATION_URI = "https://store.cryptomator.org/desktop";
private final Application application;
private final LicenseHolder licenseHolder;
+ private final Settings settings;
public TextArea donationKeyField;
@Inject
- DonationKeyPreferencesController(Application application, LicenseHolder licenseHolder) {
+ DonationKeyPreferencesController(Application application, LicenseHolder licenseHolder, Settings settings) {
this.application = application;
this.licenseHolder = licenseHolder;
+ this.settings = settings;
}
@FXML
@@ -32,6 +36,9 @@ public class DonationKeyPreferencesController implements FxController {
private void registrationKeyChanged(@SuppressWarnings("unused") ObservableValue extends String> observable, @SuppressWarnings("unused") String oldValue, String newValue) {
licenseHolder.validateAndStoreLicense(newValue);
+ if (!licenseHolder.isValidLicense()) {
+ settings.theme().set(UiTheme.LIGHT);
+ }
}
@FXML
diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/GeneralPreferencesController.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/GeneralPreferencesController.java
index 30f06b166..fdec00d62 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/preferences/GeneralPreferencesController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/preferences/GeneralPreferencesController.java
@@ -1,5 +1,6 @@
package org.cryptomator.ui.preferences;
+import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.ObjectProperty;
import javafx.beans.value.ObservableValue;
@@ -12,11 +13,10 @@ import javafx.scene.control.RadioButton;
import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleGroup;
import javafx.util.StringConverter;
-import javafx.application.Application;
+import org.cryptomator.common.Environment;
import org.cryptomator.common.LicenseHolder;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.common.settings.UiTheme;
-import org.cryptomator.common.Environment;
import org.cryptomator.ui.common.FxController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -64,7 +64,10 @@ public class GeneralPreferencesController implements FxController {
@FXML
public void initialize() {
- themeChoiceBox.getItems().addAll(UiTheme.values());
+ themeChoiceBox.getItems().addAll(UiTheme.applicableValues());
+ if (!themeChoiceBox.getItems().contains(settings.theme().get())) {
+ settings.theme().set(UiTheme.LIGHT);
+ }
themeChoiceBox.valueProperty().bindBidirectional(settings.theme());
themeChoiceBox.setConverter(new UiThemeConverter(resourceBundle));
@@ -122,7 +125,7 @@ public class GeneralPreferencesController implements FxController {
}
@FXML
- public void showLogfileDirectory(){
+ public void showLogfileDirectory() {
environment.getLogDir().ifPresent(logDirPath -> application.getHostServices().showDocument(logDirPath.toUri().toString()));
}
diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/VolumePreferencesController.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/VolumePreferencesController.java
index 44127696c..5faf5b694 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/preferences/VolumePreferencesController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/preferences/VolumePreferencesController.java
@@ -3,7 +3,6 @@ package org.cryptomator.ui.preferences;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.SimpleBooleanProperty;
-import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.control.Button;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.TextField;
@@ -40,9 +39,8 @@ public class VolumePreferencesController implements FxController {
public void initialize() {
volumeTypeChoiceBox.getItems().addAll(Volume.getCurrentSupportedAdapters());
- //If the in the settings specified preferredVolumeImplementation isn't available, overwrite the settings to use the default VolumeImpl.WEBDAV
if (!volumeTypeChoiceBox.getItems().contains(settings.preferredVolumeImpl().get())) {
- settings.preferredVolumeImpl().bind(new SimpleObjectProperty<>(VolumeImpl.WEBDAV));
+ settings.preferredVolumeImpl().set(VolumeImpl.WEBDAV);
}
volumeTypeChoiceBox.valueProperty().bindBidirectional(settings.preferredVolumeImpl());
volumeTypeChoiceBox.setConverter(new VolumeImplConverter());
diff --git a/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayIconController.java b/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayIconController.java
index 78c5cfe62..13183a36e 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayIconController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayIconController.java
@@ -47,7 +47,7 @@ public class TrayIconController {
trayMenuController.initTrayMenu();
}
- public void macInterfaceThemeChanged() {
+ private void macInterfaceThemeChanged() {
trayIcon.setImage(imageFactory.loadImage());
}
diff --git a/main/ui/src/main/resources/css/dark_theme.css b/main/ui/src/main/resources/css/dark_theme.css
index 6f8022beb..b6ab94b9b 100644
--- a/main/ui/src/main/resources/css/dark_theme.css
+++ b/main/ui/src/main/resources/css/dark_theme.css
@@ -143,6 +143,10 @@
-fx-fill: RED_5;
}
+.glyph-icon-orange {
+ -fx-fill: ORANGE_5;
+}
+
/*******************************************************************************
* *
* Main Window *
diff --git a/main/ui/src/main/resources/css/light_theme.css b/main/ui/src/main/resources/css/light_theme.css
index 42f93bfbf..b650b6e17 100644
--- a/main/ui/src/main/resources/css/light_theme.css
+++ b/main/ui/src/main/resources/css/light_theme.css
@@ -143,6 +143,10 @@
-fx-fill: RED_5;
}
+.glyph-icon-orange {
+ -fx-fill: ORANGE_5;
+}
+
/*******************************************************************************
* *
* Main Window *
diff --git a/main/ui/src/main/resources/fxml/main_window_title.fxml b/main/ui/src/main/resources/fxml/main_window_title.fxml
index 31965fea0..031e48b07 100644
--- a/main/ui/src/main/resources/fxml/main_window_title.fxml
+++ b/main/ui/src/main/resources/fxml/main_window_title.fxml
@@ -32,6 +32,14 @@
+