diff --git a/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/AddVaultModule.java b/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/AddVaultModule.java index 08f499c92..d3e97e8d7 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/AddVaultModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/AddVaultModule.java @@ -21,6 +21,7 @@ import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlScene; import org.cryptomator.ui.common.NewPasswordController; import org.cryptomator.ui.common.PasswordStrengthUtil; +import org.cryptomator.ui.common.StageFactory; import org.cryptomator.ui.mainwindow.MainWindow; import org.cryptomator.ui.recoverykey.RecoveryKeyDisplayController; @@ -51,13 +52,12 @@ public abstract class AddVaultModule { @Provides @AddVaultWizardWindow @AddVaultWizardScoped - static Stage provideStage(@MainWindow Stage owner, ResourceBundle resourceBundle, @Named("windowIcons") List windowIcons) { - Stage stage = new Stage(); + static Stage provideStage(StageFactory factory, @MainWindow Stage owner, ResourceBundle resourceBundle) { + Stage stage = factory.create(); stage.setTitle(resourceBundle.getString("addvaultwizard.title")); stage.setResizable(false); stage.initModality(Modality.WINDOW_MODAL); stage.initOwner(owner); - stage.getIcons().addAll(windowIcons); return stage; } diff --git a/main/ui/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordModule.java b/main/ui/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordModule.java index 41e0ede1d..c6367d124 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordModule.java @@ -18,6 +18,7 @@ import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlScene; import org.cryptomator.ui.common.NewPasswordController; import org.cryptomator.ui.common.PasswordStrengthUtil; +import org.cryptomator.ui.common.StageFactory; import javax.inject.Named; import javax.inject.Provider; @@ -46,13 +47,12 @@ abstract class ChangePasswordModule { @Provides @ChangePasswordWindow @ChangePasswordScoped - static Stage provideStage(@Named("changePasswordOwner") Stage owner, ResourceBundle resourceBundle, @Named("windowIcons") List windowIcons) { - Stage stage = new Stage(); + static Stage provideStage(StageFactory factory, @Named("changePasswordOwner") Stage owner, ResourceBundle resourceBundle) { + Stage stage = factory.create(); stage.setTitle(resourceBundle.getString("changepassword.title")); stage.setResizable(false); stage.initModality(Modality.WINDOW_MODAL); stage.initOwner(owner); - stage.getIcons().addAll(windowIcons); return stage; } diff --git a/main/ui/src/main/java/org/cryptomator/ui/common/StageFactory.java b/main/ui/src/main/java/org/cryptomator/ui/common/StageFactory.java new file mode 100644 index 000000000..cb980d523 --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/common/StageFactory.java @@ -0,0 +1,26 @@ +package org.cryptomator.ui.common; + +import javafx.stage.Stage; +import javafx.stage.StageStyle; + +import java.util.function.Consumer; + +public class StageFactory { + + private final Consumer initializer; + + public StageFactory(Consumer initializer) { + this.initializer = initializer; + } + + public Stage create() { + return create(StageStyle.DECORATED); + } + + public Stage create(StageStyle stageStyle) { + Stage stage = new Stage(stageStyle); + initializer.accept(stage); + return stage; + } + +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordModule.java b/main/ui/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordModule.java index a6d45fa41..930a2638b 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordModule.java @@ -17,6 +17,7 @@ import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.common.FxControllerKey; import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlScene; +import org.cryptomator.ui.common.StageFactory; import javax.inject.Named; import javax.inject.Provider; @@ -37,13 +38,12 @@ abstract class ForgetPasswordModule { @Provides @ForgetPasswordWindow @ForgetPasswordScoped - static Stage provideStage(ResourceBundle resourceBundle, @Named("windowIcons") List windowIcons, @Named("forgetPasswordOwner") Stage owner) { - Stage stage = new Stage(); + static Stage provideStage(StageFactory factory, ResourceBundle resourceBundle, @Named("forgetPasswordOwner") Stage owner) { + Stage stage = factory.create(); stage.setTitle(resourceBundle.getString("forgetPassword.title")); stage.setResizable(false); stage.initModality(Modality.WINDOW_MODAL); stage.initOwner(owner); - stage.getIcons().addAll(windowIcons); return stage; } 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 289497647..291e1a347 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 @@ -43,11 +43,10 @@ public class FxApplication extends Application { private final Optional macFunctions; private final VaultService vaultService; private final LicenseHolder licenseHolder; - private final ObservableSet visibleStages = FXCollections.observableSet(); - private final BooleanBinding hasVisibleStages = Bindings.isNotEmpty(visibleStages); + private final BooleanBinding hasVisibleStages; @Inject - FxApplication(Settings settings, Lazy mainWindow, Lazy preferencesWindow, UnlockComponent.Builder unlockWindowBuilder, QuitComponent.Builder quitWindowBuilder, Optional macFunctions, VaultService vaultService, LicenseHolder licenseHolder) { + FxApplication(Settings settings, Lazy mainWindow, Lazy preferencesWindow, UnlockComponent.Builder unlockWindowBuilder, QuitComponent.Builder quitWindowBuilder, Optional macFunctions, VaultService vaultService, LicenseHolder licenseHolder, ObservableSet visibleStages) { this.settings = settings; this.mainWindow = mainWindow; this.preferencesWindow = preferencesWindow; @@ -56,6 +55,7 @@ public class FxApplication extends Application { this.macFunctions = macFunctions; this.vaultService = vaultService; this.licenseHolder = licenseHolder; + this.hasVisibleStages = Bindings.isNotEmpty(visibleStages); } public void start() { @@ -73,11 +73,6 @@ public class FxApplication extends Application { throw new UnsupportedOperationException("Use start() instead."); } - private void addVisibleStage(Stage stage) { - visibleStages.add(stage); - stage.setOnHidden(evt -> visibleStages.remove(stage)); - } - private void hasVisibleStagesChanged(@SuppressWarnings("unused") ObservableValue observableValue, @SuppressWarnings("unused") boolean oldValue, boolean newValue) { if (newValue) { macFunctions.map(MacFunctions::uiState).ifPresent(MacApplicationUiState::transformToForegroundApplication); @@ -88,32 +83,28 @@ public class FxApplication extends Application { public void showPreferencesWindow(SelectedPreferencesTab selectedTab) { Platform.runLater(() -> { - Stage stage = preferencesWindow.get().showPreferencesWindow(selectedTab); - addVisibleStage(stage); + preferencesWindow.get().showPreferencesWindow(selectedTab); LOG.debug("Showing Preferences"); }); } public void showMainWindow() { Platform.runLater(() -> { - Stage stage = mainWindow.get().showMainWindow(); - addVisibleStage(stage); + mainWindow.get().showMainWindow(); LOG.debug("Showing MainWindow"); }); } public void showUnlockWindow(Vault vault) { Platform.runLater(() -> { - Stage stage = unlockWindowBuilder.vault(vault).build().showUnlockWindow(); - addVisibleStage(stage); + unlockWindowBuilder.vault(vault).build().showUnlockWindow(); LOG.debug("Showing UnlockWindow for {}", vault.getDisplayableName()); }); } public void showQuitWindow(QuitResponse response) { Platform.runLater(() -> { - Stage stage = quitWindowBuilder.quitResponse(response).build().showQuitWindow(); - addVisibleStage(stage); + quitWindowBuilder.quitResponse(response).build().showQuitWindow(); LOG.debug("Showing QuitWindow"); }); } diff --git a/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java b/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java index 4fd18202d..65801b1d0 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java @@ -11,10 +11,14 @@ import dagger.Provides; import javafx.application.Application; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; +import javafx.collections.FXCollections; +import javafx.collections.ObservableSet; import javafx.scene.image.Image; +import javafx.stage.Stage; import org.apache.commons.lang3.SystemUtils; import org.cryptomator.common.vaults.Vault; import org.cryptomator.ui.common.ErrorComponent; +import org.cryptomator.ui.common.StageFactory; import org.cryptomator.ui.mainwindow.MainWindowComponent; import org.cryptomator.ui.preferences.PreferencesComponent; import org.cryptomator.ui.quit.QuitComponent; @@ -36,6 +40,12 @@ abstract class FxApplicationModule { return new SimpleObjectProperty<>(); } + @Provides + @FxApplicationScoped + static ObservableSet provideVisibleStages() { + return FXCollections.observableSet(); + } + @Provides @Named("windowIcons") @FxApplicationScoped @@ -43,7 +53,6 @@ abstract class FxApplicationModule { if (SystemUtils.IS_OS_MAC) { return Collections.emptyList(); } - try { return List.of( // createImageFromResource("/window_icon_32.png"), // @@ -53,6 +62,21 @@ abstract class FxApplicationModule { throw new UncheckedIOException("Failed to load embedded resource.", e); } } + + @Provides + @FxApplicationScoped + static StageFactory provideStageFactory(@Named("windowIcons") List windowIcons, ObservableSet visibleStages) { + return new StageFactory(stage -> { + stage.getIcons().addAll(windowIcons); + stage.showingProperty().addListener((observableValue, wasShowing, isShowing) -> { + if (isShowing) { + visibleStages.add(stage); + } else { + visibleStages.remove(stage); + } + }); + }); + } private static Image createImageFromResource(String resourceName) throws IOException { try (InputStream in = FxApplicationModule.class.getResourceAsStream(resourceName)) { diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java index 04a047424..1b9ad08d8 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java @@ -14,6 +14,7 @@ import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.common.FxControllerKey; import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlScene; +import org.cryptomator.ui.common.StageFactory; import org.cryptomator.ui.migration.MigrationComponent; import org.cryptomator.ui.removevault.RemoveVaultComponent; import org.cryptomator.ui.vaultoptions.VaultOptionsComponent; @@ -38,15 +39,14 @@ abstract class MainWindowModule { @Provides @MainWindow @MainWindowScoped - static Stage provideStage(@Named("windowIcons") List windowIcons) { - Stage stage = new Stage(StageStyle.UNDECORATED); + static Stage provideStage(StageFactory factory) { + Stage stage = factory.create(StageStyle.UNDECORATED); // TODO: min/max values chosen arbitrarily. We might wanna take a look at the user's resolution... stage.setMinWidth(650); stage.setMinHeight(440); stage.setMaxWidth(1000); stage.setMaxHeight(700); stage.setTitle("Cryptomator"); - stage.getIcons().addAll(windowIcons); return stage; } diff --git a/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationModule.java b/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationModule.java index 0c36818a2..79803f861 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationModule.java @@ -17,6 +17,7 @@ import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.common.FxControllerKey; import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlScene; +import org.cryptomator.ui.common.StageFactory; import org.cryptomator.ui.mainwindow.MainWindow; import javax.inject.Named; @@ -38,13 +39,12 @@ abstract class MigrationModule { @Provides @MigrationWindow @MigrationScoped - static Stage provideStage(@MainWindow Stage owner, ResourceBundle resourceBundle, @Named("windowIcons") List windowIcons) { - Stage stage = new Stage(); + static Stage provideStage(StageFactory factory, @MainWindow Stage owner, ResourceBundle resourceBundle) { + Stage stage = factory.create(); stage.setTitle(resourceBundle.getString("migration.title")); stage.setResizable(false); stage.initModality(Modality.WINDOW_MODAL); stage.initOwner(owner); - stage.getIcons().addAll(windowIcons); return stage; } diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesModule.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesModule.java index b9438e35c..7a9dc2027 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesModule.java @@ -15,6 +15,7 @@ import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.common.FxControllerKey; import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlScene; +import org.cryptomator.ui.common.StageFactory; import javax.inject.Named; import javax.inject.Provider; @@ -41,11 +42,10 @@ abstract class PreferencesModule { @Provides @PreferencesWindow @PreferencesScoped - static Stage provideStage(ResourceBundle resourceBundle, @Named("windowIcons") List windowIcons) { - Stage stage = new Stage(); + static Stage provideStage(StageFactory factory, ResourceBundle resourceBundle) { + Stage stage = factory.create(); stage.setTitle(resourceBundle.getString("preferences.title")); stage.setResizable(false); - stage.getIcons().addAll(windowIcons); return stage; } diff --git a/main/ui/src/main/java/org/cryptomator/ui/quit/QuitModule.java b/main/ui/src/main/java/org/cryptomator/ui/quit/QuitModule.java index afdcb78a9..d79cabfcb 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/quit/QuitModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/quit/QuitModule.java @@ -17,6 +17,7 @@ import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.common.FxControllerKey; import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlScene; +import org.cryptomator.ui.common.StageFactory; import javax.inject.Named; import javax.inject.Provider; @@ -37,12 +38,11 @@ abstract class QuitModule { @Provides @QuitWindow @QuitScoped - static Stage provideStage(@Named("windowIcons") List windowIcons) { - Stage stage = new Stage(); + static Stage provideStage(StageFactory factory) { + Stage stage = factory.create(); stage.setMinWidth(300); stage.setMinHeight(100); stage.initModality(Modality.APPLICATION_MODAL); - stage.getIcons().addAll(windowIcons); return stage; } diff --git a/main/ui/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyModule.java b/main/ui/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyModule.java index 3926f14ae..48e81f3a5 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyModule.java @@ -21,6 +21,7 @@ import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlScene; import org.cryptomator.ui.common.NewPasswordController; import org.cryptomator.ui.common.PasswordStrengthUtil; +import org.cryptomator.ui.common.StageFactory; import javax.inject.Named; import javax.inject.Provider; @@ -41,13 +42,12 @@ abstract class RecoveryKeyModule { @Provides @RecoveryKeyWindow @RecoveryKeyScoped - static Stage provideStage(ResourceBundle resourceBundle, @Named("windowIcons") List windowIcons, @Named("keyRecoveryOwner") Stage owner) { - Stage stage = new Stage(); + static Stage provideStage(StageFactory factory, ResourceBundle resourceBundle, @Named("keyRecoveryOwner") Stage owner) { + Stage stage = factory.create(); stage.setTitle(resourceBundle.getString("recoveryKey.title")); stage.setResizable(false); stage.initModality(Modality.WINDOW_MODAL); stage.initOwner(owner); - stage.getIcons().addAll(windowIcons); return stage; } diff --git a/main/ui/src/main/java/org/cryptomator/ui/removevault/RemoveVaultModule.java b/main/ui/src/main/java/org/cryptomator/ui/removevault/RemoveVaultModule.java index 2bf44b106..5f61ec7ed 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/removevault/RemoveVaultModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/removevault/RemoveVaultModule.java @@ -17,6 +17,7 @@ import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.common.FxControllerKey; import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlScene; +import org.cryptomator.ui.common.StageFactory; import org.cryptomator.ui.mainwindow.MainWindow; import javax.inject.Named; @@ -38,13 +39,12 @@ abstract class RemoveVaultModule { @Provides @RemoveVaultWindow @RemoveVaultScoped - static Stage provideStage(@MainWindow Stage owner, ResourceBundle resourceBundle, @Named("windowIcons") List windowIcons) { - Stage stage = new Stage(); + static Stage provideStage(StageFactory factory, @MainWindow Stage owner, ResourceBundle resourceBundle) { + Stage stage = factory.create(); stage.setTitle(resourceBundle.getString("removeVault.title")); stage.setResizable(false); stage.initModality(Modality.WINDOW_MODAL); stage.initOwner(owner); - stage.getIcons().addAll(windowIcons); return stage; } diff --git a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java index a6e5202d8..0bc238f22 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java @@ -15,6 +15,7 @@ import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.common.FxControllerKey; import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlScene; +import org.cryptomator.ui.common.StageFactory; import org.cryptomator.ui.forgetPassword.ForgetPasswordComponent; import javax.inject.Named; @@ -36,12 +37,11 @@ abstract class UnlockModule { @Provides @UnlockWindow @UnlockScoped - static Stage provideStage(@UnlockWindow Vault vault, @Named("windowIcons") List windowIcons) { - Stage stage = new Stage(); + static Stage provideStage(StageFactory factory, @UnlockWindow Vault vault) { + Stage stage = factory.create(); stage.setTitle(vault.getDisplayableName()); stage.setResizable(false); stage.initModality(Modality.APPLICATION_MODAL); - stage.getIcons().addAll(windowIcons); return stage; } diff --git a/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/VaultOptionsModule.java b/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/VaultOptionsModule.java index 639f5b36b..d0aa49281 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/VaultOptionsModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/VaultOptionsModule.java @@ -16,6 +16,7 @@ import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.common.FxControllerKey; import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlScene; +import org.cryptomator.ui.common.StageFactory; import org.cryptomator.ui.mainwindow.MainWindow; import org.cryptomator.ui.recoverykey.RecoveryKeyComponent; @@ -38,15 +39,14 @@ abstract class VaultOptionsModule { @Provides @VaultOptionsWindow @VaultOptionsScoped - static Stage provideStage(@MainWindow Stage owner, @VaultOptionsWindow Vault vault, ResourceBundle resourceBundle, @Named("windowIcons") List windowIcons) { - Stage stage = new Stage(); + static Stage provideStage(StageFactory factory, @MainWindow Stage owner, @VaultOptionsWindow Vault vault) { + Stage stage = factory.create(); stage.setTitle(vault.getDisplayableName()); stage.setResizable(true); stage.setMinWidth(400); stage.setMinHeight(300); stage.initModality(Modality.WINDOW_MODAL); stage.initOwner(owner); - stage.getIcons().addAll(windowIcons); return stage; } diff --git a/main/ui/src/main/java/org/cryptomator/ui/wrongfilealert/WrongFileAlertModule.java b/main/ui/src/main/java/org/cryptomator/ui/wrongfilealert/WrongFileAlertModule.java index 7c64a079d..cca3b0269 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/wrongfilealert/WrongFileAlertModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/wrongfilealert/WrongFileAlertModule.java @@ -14,6 +14,7 @@ import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.common.FxControllerKey; import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlScene; +import org.cryptomator.ui.common.StageFactory; import org.cryptomator.ui.mainwindow.MainWindow; import javax.inject.Named; @@ -35,13 +36,12 @@ abstract class WrongFileAlertModule { @Provides @WrongFileAlertWindow @WrongFileAlertScoped - static Stage provideStage(@MainWindow Stage mainWindow, ResourceBundle resourceBundle, @Named("windowIcons") List windowIcons) { - Stage stage = new Stage(); + static Stage provideStage(StageFactory factory, @MainWindow Stage mainWindow, ResourceBundle resourceBundle) { + Stage stage = factory.create(); stage.setTitle(resourceBundle.getString("wrongFileAlert.title")); stage.setResizable(false); stage.initOwner(mainWindow); stage.initModality(Modality.WINDOW_MODAL); - stage.getIcons().addAll(windowIcons); return stage; }