mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-21 12:11:28 +00:00
Migrated from deprecated MacFunctions to UiAppearanceProvider for UI theme switching
This commit is contained in:
@@ -25,9 +25,9 @@
|
||||
|
||||
<!-- cryptomator dependencies -->
|
||||
<cryptomator.cryptofs.version>1.9.12</cryptomator.cryptofs.version>
|
||||
<cryptomator.integrations.version>0.1.4</cryptomator.integrations.version>
|
||||
<cryptomator.integrations.version>0.1.5</cryptomator.integrations.version>
|
||||
<cryptomator.integrations.win.version>0.1.0-beta1</cryptomator.integrations.win.version>
|
||||
<cryptomator.integrations.mac.version>0.1.0-beta1</cryptomator.integrations.mac.version>
|
||||
<cryptomator.integrations.mac.version>0.1.0-beta2</cryptomator.integrations.mac.version>
|
||||
<cryptomator.integrations.linux.version>0.1.0-beta1</cryptomator.integrations.linux.version>
|
||||
<cryptomator.jni.version>2.2.3</cryptomator.jni.version>
|
||||
<cryptomator.fuse.version>1.2.5</cryptomator.fuse.version>
|
||||
|
||||
@@ -6,8 +6,10 @@ import org.cryptomator.common.LicenseHolder;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.common.settings.UiTheme;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.jni.JniException;
|
||||
import org.cryptomator.jni.MacApplicationUiAppearance;
|
||||
import org.cryptomator.integrations.uiappearance.Theme;
|
||||
import org.cryptomator.integrations.uiappearance.UiAppearanceException;
|
||||
import org.cryptomator.integrations.uiappearance.UiAppearanceListener;
|
||||
import org.cryptomator.integrations.uiappearance.UiAppearanceProvider;
|
||||
import org.cryptomator.jni.MacApplicationUiState;
|
||||
import org.cryptomator.jni.MacFunctions;
|
||||
import org.cryptomator.ui.common.VaultService;
|
||||
@@ -42,20 +44,21 @@ public class FxApplication extends Application {
|
||||
private final Provider<UnlockComponent.Builder> unlockWindowBuilderProvider;
|
||||
private final Provider<QuitComponent.Builder> quitWindowBuilderProvider;
|
||||
private final Optional<MacFunctions> macFunctions;
|
||||
private final Optional<UiAppearanceProvider> appearanceProvider;
|
||||
private final VaultService vaultService;
|
||||
private final LicenseHolder licenseHolder;
|
||||
private final BooleanBinding hasVisibleStages;
|
||||
|
||||
private Optional<String> macApperanceObserverIdentifier = Optional.empty();
|
||||
private final UiAppearanceListener systemInterfaceThemeListener = this::systemInterfaceThemeChanged;
|
||||
|
||||
@Inject
|
||||
FxApplication(Settings settings, Lazy<MainWindowComponent> mainWindow, Lazy<PreferencesComponent> preferencesWindow, Provider<UnlockComponent.Builder> unlockWindowBuilderProvider, Provider<QuitComponent.Builder> quitWindowBuilderProvider, Optional<MacFunctions> macFunctions, VaultService vaultService, LicenseHolder licenseHolder, ObservableSet<Stage> visibleStages) {
|
||||
FxApplication(Settings settings, Lazy<MainWindowComponent> mainWindow, Lazy<PreferencesComponent> preferencesWindow, Provider<UnlockComponent.Builder> unlockWindowBuilderProvider, Provider<QuitComponent.Builder> quitWindowBuilderProvider, Optional<MacFunctions> macFunctions, Optional<UiAppearanceProvider> appearanceProvider, VaultService vaultService, LicenseHolder licenseHolder, ObservableSet<Stage> visibleStages) {
|
||||
this.settings = settings;
|
||||
this.mainWindow = mainWindow;
|
||||
this.preferencesWindow = preferencesWindow;
|
||||
this.unlockWindowBuilderProvider = unlockWindowBuilderProvider;
|
||||
this.quitWindowBuilderProvider = quitWindowBuilderProvider;
|
||||
this.macFunctions = macFunctions;
|
||||
this.appearanceProvider = appearanceProvider;
|
||||
this.vaultService = vaultService;
|
||||
this.licenseHolder = licenseHolder;
|
||||
this.hasVisibleStages = Bindings.isNotEmpty(visibleStages);
|
||||
@@ -67,7 +70,7 @@ public class FxApplication extends Application {
|
||||
|
||||
EasyBind.subscribe(hasVisibleStages, this::hasVisibleStagesChanged);
|
||||
|
||||
settings.theme().addListener(this::themeChanged);
|
||||
settings.theme().addListener(this::appThemeChanged);
|
||||
loadSelectedStyleSheet(settings.theme().get());
|
||||
}
|
||||
|
||||
@@ -116,45 +119,60 @@ public class FxApplication extends Application {
|
||||
return vaultService;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
private void appThemeChanged(@SuppressWarnings("unused") ObservableValue<? extends UiTheme> observable, @SuppressWarnings("unused") UiTheme oldValue, UiTheme newValue) {
|
||||
appearanceProvider.ifPresent(appearanceProvider -> {
|
||||
try {
|
||||
appearanceProvider.removeListener(systemInterfaceThemeListener);
|
||||
} catch (UiAppearanceException e) {
|
||||
LOG.error("Failed to disable automatic theme switching.");
|
||||
}
|
||||
});
|
||||
loadSelectedStyleSheet(newValue);
|
||||
}
|
||||
|
||||
private void loadSelectedStyleSheet(UiTheme desiredTheme) {
|
||||
UiTheme theme = licenseHolder.isValidLicense() ? desiredTheme : UiTheme.LIGHT;
|
||||
switch (theme) {
|
||||
case LIGHT -> setToLightTheme();
|
||||
case DARK -> setToDarkTheme();
|
||||
case LIGHT -> applyLightTheme();
|
||||
case DARK -> applyDarkTheme();
|
||||
case AUTOMATIC -> {
|
||||
macFunctions.map(MacFunctions::uiAppearance).ifPresent(uiAppearance -> {
|
||||
macApperanceObserverIdentifier = Optional.of(uiAppearance.addListener(this::macInterfaceThemeChanged));
|
||||
appearanceProvider.ifPresent(appearanceProvider -> {
|
||||
try {
|
||||
appearanceProvider.addListener(systemInterfaceThemeListener);
|
||||
} catch (UiAppearanceException e) {
|
||||
LOG.error("Failed to enable automatic theme switching.");
|
||||
}
|
||||
});
|
||||
macInterfaceThemeChanged();
|
||||
applySystemTheme();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void macInterfaceThemeChanged() {
|
||||
macFunctions.map(MacFunctions::uiAppearance).ifPresent(uiAppearance -> {
|
||||
switch (uiAppearance.getCurrentInterfaceStyle()) {
|
||||
case LIGHT -> setToLightTheme();
|
||||
case DARK -> setToDarkTheme();
|
||||
}
|
||||
private void systemInterfaceThemeChanged(Theme theme) {
|
||||
switch (theme) {
|
||||
case LIGHT -> applyLightTheme();
|
||||
case DARK -> applyDarkTheme();
|
||||
}
|
||||
}
|
||||
|
||||
private void applySystemTheme() {
|
||||
appearanceProvider.ifPresent(appearanceProvider -> {
|
||||
systemInterfaceThemeChanged(appearanceProvider.getSystemTheme());
|
||||
});
|
||||
}
|
||||
|
||||
private void setToLightTheme() {
|
||||
private void applyLightTheme() {
|
||||
Application.setUserAgentStylesheet(getClass().getResource("/css/light_theme.css").toString());
|
||||
macFunctions.map(MacFunctions::uiAppearance).ifPresent(JniException.ignore(MacApplicationUiAppearance::setToAqua));
|
||||
appearanceProvider.ifPresent(appearanceProvider -> {
|
||||
appearanceProvider.adjustToTheme(Theme.LIGHT);
|
||||
});
|
||||
}
|
||||
|
||||
private void setToDarkTheme() {
|
||||
private void applyDarkTheme() {
|
||||
Application.setUserAgentStylesheet(getClass().getResource("/css/dark_theme.css").toString());
|
||||
macFunctions.map(MacFunctions::uiAppearance).ifPresent(JniException.ignore(MacApplicationUiAppearance::setToDarkAqua));
|
||||
appearanceProvider.ifPresent(appearanceProvider -> {
|
||||
appearanceProvider.adjustToTheme(Theme.DARK);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,18 +3,28 @@ package org.cryptomator.ui.launcher;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import org.cryptomator.common.JniModule;
|
||||
import org.cryptomator.integrations.uiappearance.UiAppearanceProvider;
|
||||
import org.cryptomator.ui.fxapp.FxApplicationComponent;
|
||||
import org.cryptomator.ui.fxapp.FxApplicationScoped;
|
||||
import org.cryptomator.ui.traymenu.TrayMenuComponent;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.Optional;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
||||
@Module(includes = {JniModule.class}, subcomponents = {TrayMenuComponent.class, FxApplicationComponent.class})
|
||||
public abstract class UiLauncherModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static Optional<UiAppearanceProvider> provideAppearanceProvider() {
|
||||
return ServiceLoader.load(UiAppearanceProvider.class).findFirst();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static ResourceBundle provideLocalization() {
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package org.cryptomator.ui.traymenu;
|
||||
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.integrations.uiappearance.Theme;
|
||||
import org.cryptomator.integrations.uiappearance.UiAppearanceException;
|
||||
import org.cryptomator.integrations.uiappearance.UiAppearanceProvider;
|
||||
import org.cryptomator.jni.MacFunctions;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -17,20 +20,26 @@ public class TrayIconController {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(TrayIconController.class);
|
||||
|
||||
private final TrayImageFactory imageFactory;
|
||||
private final Optional<UiAppearanceProvider> appearanceProvider;
|
||||
private final TrayMenuController trayMenuController;
|
||||
private final TrayIcon trayIcon;
|
||||
private final Optional<MacFunctions> macFunctions;
|
||||
|
||||
@Inject
|
||||
TrayIconController(TrayImageFactory imageFactory, TrayMenuController trayMenuController, Optional<MacFunctions> macFunctions) {
|
||||
TrayIconController(TrayImageFactory imageFactory, TrayMenuController trayMenuController, Optional<UiAppearanceProvider> appearanceProvider) {
|
||||
this.trayMenuController = trayMenuController;
|
||||
this.imageFactory = imageFactory;
|
||||
this.appearanceProvider = appearanceProvider;
|
||||
this.trayIcon = new TrayIcon(imageFactory.loadImage(), "Cryptomator", trayMenuController.getMenu());
|
||||
this.macFunctions = macFunctions;
|
||||
}
|
||||
|
||||
public void initializeTrayIcon() {
|
||||
macFunctions.map(MacFunctions::uiAppearance).ifPresent(uiAppearance -> uiAppearance.addListener(this::macInterfaceThemeChanged));
|
||||
appearanceProvider.ifPresent(appearanceProvider -> {
|
||||
try {
|
||||
appearanceProvider.addListener(this::systemInterfaceThemeChanged);
|
||||
} catch (UiAppearanceException e) {
|
||||
LOG.error("Failed to enable automatic tray icon theme switching.");
|
||||
}
|
||||
});
|
||||
|
||||
trayIcon.setImageAutoSize(true);
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
@@ -47,8 +56,8 @@ public class TrayIconController {
|
||||
trayMenuController.initTrayMenu();
|
||||
}
|
||||
|
||||
private void macInterfaceThemeChanged() {
|
||||
trayIcon.setImage(imageFactory.loadImage());
|
||||
private void systemInterfaceThemeChanged(Theme theme) {
|
||||
trayIcon.setImage(imageFactory.loadImage()); // TODO refactor "theme" is re-queried in loadImage()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package org.cryptomator.ui.traymenu;
|
||||
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.jni.MacApplicationUiAppearance;
|
||||
import org.cryptomator.jni.MacApplicationUiInterfaceStyle;
|
||||
import org.cryptomator.jni.MacFunctions;
|
||||
import org.cryptomator.integrations.uiappearance.Theme;
|
||||
import org.cryptomator.integrations.uiappearance.UiAppearanceProvider;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.awt.Image;
|
||||
@@ -13,11 +12,11 @@ import java.util.Optional;
|
||||
@TrayMenuScoped
|
||||
class TrayImageFactory {
|
||||
|
||||
private final Optional<MacFunctions> macFunctions;
|
||||
private final Optional<UiAppearanceProvider> appearanceProvider;
|
||||
|
||||
@Inject
|
||||
TrayImageFactory(Optional<MacFunctions> macFunctions) {
|
||||
this.macFunctions = macFunctions;
|
||||
TrayImageFactory(Optional<UiAppearanceProvider> appearanceProvider) {
|
||||
this.appearanceProvider = appearanceProvider;
|
||||
}
|
||||
|
||||
public Image loadImage() {
|
||||
@@ -26,10 +25,8 @@ class TrayImageFactory {
|
||||
}
|
||||
|
||||
private String getMacResourceName() {
|
||||
MacApplicationUiInterfaceStyle interfaceStyle = macFunctions.map(MacFunctions::uiAppearance) //
|
||||
.map(MacApplicationUiAppearance::getCurrentInterfaceStyle) //
|
||||
.orElse(MacApplicationUiInterfaceStyle.LIGHT);
|
||||
return switch (interfaceStyle) {
|
||||
var theme = appearanceProvider.map(UiAppearanceProvider::getSystemTheme).orElse(Theme.LIGHT);
|
||||
return switch (theme) {
|
||||
case DARK -> "/img/tray_icon_mac_white.png";
|
||||
case LIGHT -> "/img/tray_icon_mac_black.png";
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user