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/pom.xml b/main/pom.xml
index 5f0d7e5ea..618793f93 100644
--- a/main/pom.xml
+++ b/main/pom.xml
@@ -25,7 +25,7 @@
1.9.12
- 2.2.2
+ 2.2.3
1.2.3
1.1.15
1.0.11
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..4d80a3451 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
@@ -6,7 +6,6 @@ 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 +45,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;
@@ -115,21 +116,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/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/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/i18n/strings.properties b/main/ui/src/main/resources/i18n/strings.properties
index cd6a2d625..6b1a89136 100644
--- a/main/ui/src/main/resources/i18n/strings.properties
+++ b/main/ui/src/main/resources/i18n/strings.properties
@@ -131,6 +131,7 @@ preferences.title=Preferences
## General
preferences.general=General
preferences.general.theme=Look & Feel
+preferences.general.theme.automatic=Automatic
preferences.general.theme.light=Light
preferences.general.theme.dark=Dark
preferences.general.unlockThemes=Unlock dark mode