diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 357b2e3e4..e15900880 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -8,7 +8,7 @@ updates: time: "06:00" timezone: "UTC" groups: - all: # one PR for all dependencies + maven-dependencies: patterns: - "*" @@ -17,7 +17,7 @@ updates: schedule: interval: "monthly" groups: - all: # one PR for all actions + github-actions: patterns: - "*" labels: diff --git a/dist/mac/resources/Cryptomator.icns b/dist/mac/resources/Cryptomator.icns index 25da5b5be..79f5fdb39 100644 Binary files a/dist/mac/resources/Cryptomator.icns and b/dist/mac/resources/Cryptomator.icns differ diff --git a/dist/win/contrib/patchWebDAV.bat b/dist/win/contrib/patchWebDAV.bat index cc9f667dd..735cfb823 100644 --- a/dist/win/contrib/patchWebDAV.bat +++ b/dist/win/contrib/patchWebDAV.bat @@ -3,5 +3,5 @@ ::REPLACE ME cd %~dp0 -powershell -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command .\patchWebDAV.ps1^ +powershell -NoLogo -NoProfile -NonInteractive -ExecutionPolicy RemoteSigned -Command .\patchWebDAV.ps1^ -LoopbackAlias %LOOPBACK_ALIAS% \ No newline at end of file diff --git a/dist/win/contrib/version170-migrate-settings.bat b/dist/win/contrib/version170-migrate-settings.bat index 345b01ad9..d94e062a1 100644 --- a/dist/win/contrib/version170-migrate-settings.bat +++ b/dist/win/contrib/version170-migrate-settings.bat @@ -2,4 +2,4 @@ :: see comments in file ./version170-migrate-settings.ps1 cd %~dp0 -powershell -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command .\version170-migrate-settings.ps1 \ No newline at end of file +powershell -NoLogo -NoProfile -NonInteractive -ExecutionPolicy RemoteSigned -Command .\version170-migrate-settings.ps1 diff --git a/pom.xml b/pom.xml index 24238b8bb..2592b8814 100644 --- a/pom.xml +++ b/pom.xml @@ -36,35 +36,42 @@ 2.6.7 1.3.0 1.2.2 - 1.2.0 + 1.2.1 1.3.0-beta6 3.0.0 2.0.0 2.0.3 - 3.12.0 - 2.45 + 3.13.0 + 2.47 2.2 - 32.0.1-jre + 32.1.2-jre 2.15.2 20.0.2 4.4.0 9.31 - 1.4.7 + 1.4.11 2.0.7 - 0.5.1 - 1.7.0 + 0.6.0 + 1.8.2 - 5.9.3 - 5.3.1 + 5.10.0 + 5.5.0 2.2 - 23.0.0 - 8.1.2 - 0.8.9 + 24.0.1 + 8.4.0 + 0.8.10 + 2.2.0 + 1.2.1 + 3.11.0 + 3.3.1 + 3.6.0 + 3.1.2 + 3.3.0 @@ -240,7 +247,7 @@ com.google.jimfs jimfs - 1.2 + 1.3.0 test @@ -258,32 +265,32 @@ org.apache.maven.plugins maven-compiler-plugin - 3.10.1 + ${mvn-compiler.version} org.apache.maven.plugins maven-resources-plugin - 3.3.0 + ${mvn-resources.version} org.apache.maven.plugins maven-dependency-plugin - 3.3.0 + ${mvn-dependency.version} org.apache.maven.plugins maven-surefire-plugin - 3.0.0-M7 + ${mvn-surefire.version} org.codehaus.mojo license-maven-plugin - 2.0.0 + ${license-generator.version} org.apache.maven.plugins maven-jar-plugin - 3.3.0 + ${mvn-jar.version} org.jacoco @@ -332,8 +339,22 @@ org.apache.maven.plugins maven-surefire-plugin + + + me.fabriciorby + maven-surefire-junit5-tree-reporter + ${junit-tree-reporter.version} + + --enable-preview + plain + + true + + + diff --git a/src/main/java/org/cryptomator/common/settings/Settings.java b/src/main/java/org/cryptomator/common/settings/Settings.java index fd9f01904..4e0e0df97 100644 --- a/src/main/java/org/cryptomator/common/settings/Settings.java +++ b/src/main/java/org/cryptomator/common/settings/Settings.java @@ -65,7 +65,6 @@ public class Settings { public final IntegerProperty windowYPosition; public final IntegerProperty windowWidth; public final IntegerProperty windowHeight; - public final StringProperty displayConfiguration; public final StringProperty language; public final StringProperty mountService; public final StringProperty lastUpdateCheck; @@ -103,7 +102,6 @@ public class Settings { this.windowYPosition = new SimpleIntegerProperty(this, "windowYPosition", json.windowYPosition); this.windowWidth = new SimpleIntegerProperty(this, "windowWidth", json.windowWidth); this.windowHeight = new SimpleIntegerProperty(this, "windowHeight", json.windowHeight); - this.displayConfiguration = new SimpleStringProperty(this, "displayConfiguration", json.displayConfiguration); this.language = new SimpleStringProperty(this, "language", json.language); this.mountService = new SimpleStringProperty(this, "mountService", json.mountService); this.lastUpdateCheck = new SimpleStringProperty(this, "lastUpdateCheck", json.lastUpdateCheck); @@ -131,7 +129,6 @@ public class Settings { windowYPosition.addListener(this::somethingChanged); windowWidth.addListener(this::somethingChanged); windowHeight.addListener(this::somethingChanged); - displayConfiguration.addListener(this::somethingChanged); language.addListener(this::somethingChanged); mountService.addListener(this::somethingChanged); lastUpdateCheck.addListener(this::somethingChanged); @@ -186,7 +183,6 @@ public class Settings { json.windowYPosition = windowYPosition.get(); json.windowWidth = windowWidth.get(); json.windowHeight = windowHeight.get(); - json.displayConfiguration = displayConfiguration.get(); json.language = language.get(); json.mountService = mountService.get(); json.lastUpdateCheck = lastUpdateCheck.get(); diff --git a/src/main/java/org/cryptomator/common/settings/SettingsJson.java b/src/main/java/org/cryptomator/common/settings/SettingsJson.java index 977e1d3cd..2c7c963da 100644 --- a/src/main/java/org/cryptomator/common/settings/SettingsJson.java +++ b/src/main/java/org/cryptomator/common/settings/SettingsJson.java @@ -31,9 +31,6 @@ class SettingsJson { @JsonProperty("theme") UiTheme theme = Settings.DEFAULT_THEME; - @JsonProperty("displayConfiguration") - String displayConfiguration; - @JsonProperty("keychainProvider") String keychainProvider = Settings.DEFAULT_KEYCHAIN_PROVIDER; diff --git a/src/main/java/org/cryptomator/ui/addvaultwizard/AddVaultModule.java b/src/main/java/org/cryptomator/ui/addvaultwizard/AddVaultModule.java index 4a9dba7ad..62321277c 100644 --- a/src/main/java/org/cryptomator/ui/addvaultwizard/AddVaultModule.java +++ b/src/main/java/org/cryptomator/ui/addvaultwizard/AddVaultModule.java @@ -45,9 +45,8 @@ public abstract class AddVaultModule { @Provides @AddVaultWizardWindow @AddVaultWizardScoped - static Stage provideStage(StageFactory factory, @PrimaryStage Stage primaryStage, ResourceBundle resourceBundle) { + static Stage provideStage(StageFactory factory, @PrimaryStage Stage primaryStage) { Stage stage = factory.create(); - stage.setTitle(resourceBundle.getString("addvaultwizard.title")); stage.setResizable(false); stage.initModality(Modality.WINDOW_MODAL); stage.initOwner(primaryStage); @@ -90,13 +89,6 @@ public abstract class AddVaultModule { // ------------------ - @Provides - @FxmlScene(FxmlFile.ADDVAULT_WELCOME) - @AddVaultWizardScoped - static Scene provideWelcomeScene(@AddVaultWizardWindow FxmlLoaderFactory fxmlLoaders) { - return fxmlLoaders.createScene(FxmlFile.ADDVAULT_WELCOME); - } - @Provides @FxmlScene(FxmlFile.ADDVAULT_EXISTING) @AddVaultWizardScoped @@ -148,11 +140,6 @@ public abstract class AddVaultModule { // ------------------ - @Binds - @IntoMap - @FxControllerKey(AddVaultWelcomeController.class) - abstract FxController bindWelcomeController(AddVaultWelcomeController controller); - @Binds @IntoMap @FxControllerKey(ChooseExistingVaultController.class) diff --git a/src/main/java/org/cryptomator/ui/addvaultwizard/AddVaultWelcomeController.java b/src/main/java/org/cryptomator/ui/addvaultwizard/AddVaultWelcomeController.java deleted file mode 100644 index 3c13aeb75..000000000 --- a/src/main/java/org/cryptomator/ui/addvaultwizard/AddVaultWelcomeController.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.cryptomator.ui.addvaultwizard; - -import dagger.Lazy; -import org.cryptomator.ui.common.FxController; -import org.cryptomator.ui.common.FxmlFile; -import org.cryptomator.ui.common.FxmlScene; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.inject.Inject; -import javafx.scene.Scene; -import javafx.stage.Stage; - -@AddVaultWizardScoped -public class AddVaultWelcomeController implements FxController { - - private static final Logger LOG = LoggerFactory.getLogger(AddVaultWelcomeController.class); - private final Stage window; - private final Lazy chooseExistingVaultScene; - private final Lazy createNewVaultScene; - - @Inject - AddVaultWelcomeController(@AddVaultWizardWindow Stage window, @FxmlScene(FxmlFile.ADDVAULT_EXISTING) Lazy chooseExistingVaultScene, @FxmlScene(FxmlFile.ADDVAULT_NEW_NAME) Lazy createNewVaultScene) { - this.window = window; - this.chooseExistingVaultScene = chooseExistingVaultScene; - this.createNewVaultScene = createNewVaultScene; - } - - public void createNewVault() { - LOG.debug("AddVaultWelcomeController.createNewVault()"); - window.setScene(createNewVaultScene.get()); - } - - public void chooseExistingVault() { - LOG.debug("AddVaultWelcomeController.chooseExistingVault()"); - window.setScene(chooseExistingVaultScene.get()); - } -} diff --git a/src/main/java/org/cryptomator/ui/addvaultwizard/AddVaultWizardComponent.java b/src/main/java/org/cryptomator/ui/addvaultwizard/AddVaultWizardComponent.java index 1253d8347..c67f999e8 100644 --- a/src/main/java/org/cryptomator/ui/addvaultwizard/AddVaultWizardComponent.java +++ b/src/main/java/org/cryptomator/ui/addvaultwizard/AddVaultWizardComponent.java @@ -12,6 +12,7 @@ import org.cryptomator.ui.common.FxmlScene; import javafx.scene.Scene; import javafx.stage.Stage; +import java.util.ResourceBundle; @AddVaultWizardScoped @Subcomponent(modules = {AddVaultModule.class}) @@ -20,12 +21,23 @@ public interface AddVaultWizardComponent { @AddVaultWizardWindow Stage window(); - @FxmlScene(FxmlFile.ADDVAULT_WELCOME) - Lazy scene(); + @FxmlScene(FxmlFile.ADDVAULT_NEW_NAME) + Lazy sceneNew(); + @FxmlScene(FxmlFile.ADDVAULT_EXISTING) + Lazy sceneExisting(); - default void showAddVaultWizard() { + default void showAddNewVaultWizard(ResourceBundle resourceBundle) { Stage stage = window(); - stage.setScene(scene().get()); + stage.setScene(sceneNew().get()); + stage.setTitle(resourceBundle.getString("addvaultwizard.new.title")); + stage.sizeToScene(); + stage.show(); + } + + default void showAddExistingVaultWizard(ResourceBundle resourceBundle) { + Stage stage = window(); + stage.setScene(sceneExisting().get()); + stage.setTitle(resourceBundle.getString("addvaultwizard.existing.title")); stage.sizeToScene(); stage.show(); } diff --git a/src/main/java/org/cryptomator/ui/addvaultwizard/ChooseExistingVaultController.java b/src/main/java/org/cryptomator/ui/addvaultwizard/ChooseExistingVaultController.java index fe4ac3bd1..be9ea15c7 100644 --- a/src/main/java/org/cryptomator/ui/addvaultwizard/ChooseExistingVaultController.java +++ b/src/main/java/org/cryptomator/ui/addvaultwizard/ChooseExistingVaultController.java @@ -35,7 +35,6 @@ public class ChooseExistingVaultController implements FxController { private static final Logger LOG = LoggerFactory.getLogger(ChooseExistingVaultController.class); private final Stage window; - private final Lazy welcomeScene; private final Lazy successScene; private final FxApplicationWindows appWindows; private final ObjectProperty vaultPath; @@ -45,9 +44,15 @@ public class ChooseExistingVaultController implements FxController { private final ObservableValue screenshot; @Inject - ChooseExistingVaultController(@AddVaultWizardWindow Stage window, @FxmlScene(FxmlFile.ADDVAULT_WELCOME) Lazy welcomeScene, @FxmlScene(FxmlFile.ADDVAULT_SUCCESS) Lazy successScene, FxApplicationWindows appWindows, ObjectProperty vaultPath, @AddVaultWizardWindow ObjectProperty vault, VaultListManager vaultListManager, ResourceBundle resourceBundle, FxApplicationStyle applicationStyle) { + ChooseExistingVaultController(@AddVaultWizardWindow Stage window, // + @FxmlScene(FxmlFile.ADDVAULT_SUCCESS) Lazy successScene, // + FxApplicationWindows appWindows, // + ObjectProperty vaultPath, // + @AddVaultWizardWindow ObjectProperty vault, // + VaultListManager vaultListManager, // + ResourceBundle resourceBundle, // + FxApplicationStyle applicationStyle) { this.window = window; - this.welcomeScene = welcomeScene; this.successScene = successScene; this.appWindows = appWindows; this.vaultPath = vaultPath; @@ -70,11 +75,6 @@ public class ChooseExistingVaultController implements FxController { return new Image((Objects.requireNonNull(getClass().getResource(imageResourcePath)).toString())); } - @FXML - public void back() { - window.setScene(welcomeScene.get()); - } - @FXML public void chooseFileAndNext() { FileChooser fileChooser = new FileChooser(); diff --git a/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultNameController.java b/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultNameController.java index 2ca73e172..a80baef50 100644 --- a/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultNameController.java +++ b/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultNameController.java @@ -17,7 +17,6 @@ import javafx.scene.Scene; import javafx.scene.control.TextField; import javafx.stage.Stage; import java.nio.file.Path; -import java.util.ResourceBundle; import java.util.regex.Pattern; @AddVaultWizardScoped @@ -27,16 +26,17 @@ public class CreateNewVaultNameController implements FxController { public TextField textField; private final Stage window; - private final Lazy welcomeScene; private final Lazy chooseLocationScene; private final ObjectProperty vaultPath; private final StringProperty vaultName; private final BooleanBinding validVaultName; @Inject - CreateNewVaultNameController(@AddVaultWizardWindow Stage window, @FxmlScene(FxmlFile.ADDVAULT_WELCOME) Lazy welcomeScene, @FxmlScene(FxmlFile.ADDVAULT_NEW_LOCATION) Lazy chooseLocationScene, ObjectProperty vaultPath, @Named("vaultName") StringProperty vaultName, ResourceBundle resourceBundle) { + CreateNewVaultNameController(@AddVaultWizardWindow Stage window, // + @FxmlScene(FxmlFile.ADDVAULT_NEW_LOCATION) Lazy chooseLocationScene, // + ObjectProperty vaultPath, // + @Named("vaultName") StringProperty vaultName) { this.window = window; - this.welcomeScene = welcomeScene; this.chooseLocationScene = chooseLocationScene; this.vaultPath = vaultPath; this.vaultName = vaultName; @@ -58,11 +58,6 @@ public class CreateNewVaultNameController implements FxController { } } - @FXML - public void back() { - window.setScene(welcomeScene.get()); - } - @FXML public void next() { window.setScene(chooseLocationScene.get()); diff --git a/src/main/java/org/cryptomator/ui/common/FxmlFile.java b/src/main/java/org/cryptomator/ui/common/FxmlFile.java index cefd424ff..678795662 100644 --- a/src/main/java/org/cryptomator/ui/common/FxmlFile.java +++ b/src/main/java/org/cryptomator/ui/common/FxmlFile.java @@ -8,7 +8,6 @@ public enum FxmlFile { ADDVAULT_NEW_PASSWORD("/fxml/addvault_new_password.fxml"), // ADDVAULT_NEW_RECOVERYKEY("/fxml/addvault_new_recoverykey.fxml"), // ADDVAULT_SUCCESS("/fxml/addvault_success.fxml"), // - ADDVAULT_WELCOME("/fxml/addvault_welcome.fxml"), // CHANGEPASSWORD("/fxml/changepassword.fxml"), // CONVERTVAULT_HUBTOPASSWORD_START("/fxml/convertvault_hubtopassword_start.fxml"), // CONVERTVAULT_HUBTOPASSWORD_CONVERT("/fxml/convertvault_hubtopassword_convert.fxml"), // diff --git a/src/main/java/org/cryptomator/ui/error/ErrorController.java b/src/main/java/org/cryptomator/ui/error/ErrorController.java index b25de6d84..3feb3ff44 100644 --- a/src/main/java/org/cryptomator/ui/error/ErrorController.java +++ b/src/main/java/org/cryptomator/ui/error/ErrorController.java @@ -47,14 +47,15 @@ public class ErrorController implements FxController { private static final String REPORT_URL_FORMAT = "https://github.com/cryptomator/cryptomator/discussions/new?category=Errors&title=Error+%s&body=%s"; private static final String SEARCH_ERRORCODE_DELIM = " OR "; private static final String REPORT_BODY_TEMPLATE = """ + OS: %s / %s App: %s / %s - - - - + Description: + + + Details: """; diff --git a/src/main/java/org/cryptomator/ui/mainwindow/MainWindowSceneFactory.java b/src/main/java/org/cryptomator/ui/mainwindow/MainWindowSceneFactory.java index f93f4109d..d78192186 100644 --- a/src/main/java/org/cryptomator/ui/mainwindow/MainWindowSceneFactory.java +++ b/src/main/java/org/cryptomator/ui/mainwindow/MainWindowSceneFactory.java @@ -16,6 +16,7 @@ import javafx.stage.Stage; public class MainWindowSceneFactory extends DefaultSceneFactory { protected static final KeyCodeCombination SHORTCUT_N = new KeyCodeCombination(KeyCode.N, KeyCombination.SHORTCUT_DOWN); + protected static final KeyCodeCombination SHORTCUT_O = new KeyCodeCombination(KeyCode.O, KeyCombination.SHORTCUT_DOWN); private final Lazy mainWindowTitleController; private final Lazy vaultListController; @@ -34,6 +35,7 @@ public class MainWindowSceneFactory extends DefaultSceneFactory { } else { scene.getAccelerators().put(SHORTCUT_W, mainWindowTitleController.get()::close); } - scene.getAccelerators().put(SHORTCUT_N, vaultListController.get()::didClickAddVault); + scene.getAccelerators().put(SHORTCUT_N, vaultListController.get()::didClickAddNewVault); + scene.getAccelerators().put(SHORTCUT_O, vaultListController.get()::didClickAddExistingVault); } } diff --git a/src/main/java/org/cryptomator/ui/mainwindow/ResizeController.java b/src/main/java/org/cryptomator/ui/mainwindow/ResizeController.java index 1b3f1b69f..b136fa55c 100644 --- a/src/main/java/org/cryptomator/ui/mainwindow/ResizeController.java +++ b/src/main/java/org/cryptomator/ui/mainwindow/ResizeController.java @@ -6,7 +6,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.inject.Inject; -import javafx.beans.binding.Bindings; import javafx.beans.binding.BooleanBinding; import javafx.collections.ObservableList; import javafx.fxml.FXML; @@ -15,6 +14,7 @@ import javafx.scene.input.MouseEvent; import javafx.scene.layout.Region; import javafx.stage.Screen; import javafx.stage.Stage; +import javafx.stage.WindowEvent; @MainWindow public class ResizeController implements FxController { @@ -53,48 +53,70 @@ public class ResizeController implements FxController { public void initialize() { LOG.trace("init ResizeController"); - if (neverTouched()) { - settings.displayConfiguration.set(getMonitorSizes()); - return; - } else { - if (didDisplayConfigurationChange()) { - //If the position is illegal, then the window appears on the main screen in the middle of the window. - Rectangle2D primaryScreenBounds = Screen.getPrimary().getBounds(); - window.setX((primaryScreenBounds.getWidth() - window.getMinWidth()) / 2); - window.setY((primaryScreenBounds.getHeight() - window.getMinHeight()) / 2); - window.setWidth(window.getMinWidth()); - window.setHeight(window.getMinHeight()); - } else { - window.setHeight(settings.windowHeight.get() > window.getMinHeight() ? settings.windowHeight.get() : window.getMinHeight()); - window.setWidth(settings.windowWidth.get() > window.getMinWidth() ? settings.windowWidth.get() : window.getMinWidth()); - window.setX(settings.windowXPosition.get()); - window.setY(settings.windowYPosition.get()); - } + if (!neverTouched()) { + window.setHeight(settings.windowHeight.get() > window.getMinHeight() ? settings.windowHeight.get() : window.getMinHeight()); + window.setWidth(settings.windowWidth.get() > window.getMinWidth() ? settings.windowWidth.get() : window.getMinWidth()); + window.setX(settings.windowXPosition.get()); + window.setY(settings.windowYPosition.get()); } - savePositionalSettings(); + + window.setOnShowing(this::checkDisplayBounds); } private boolean neverTouched() { return (settings.windowHeight.get() == 0) && (settings.windowWidth.get() == 0) && (settings.windowXPosition.get() == 0) && (settings.windowYPosition.get() == 0); } - private boolean didDisplayConfigurationChange() { - String currentDisplayConfiguration = getMonitorSizes(); - String settingsDisplayConfiguration = settings.displayConfiguration.get(); - boolean configurationHasChanged = !settingsDisplayConfiguration.equals(currentDisplayConfiguration); - if (configurationHasChanged) settings.displayConfiguration.set(currentDisplayConfiguration); - return configurationHasChanged; + private boolean isWithinDisplayBounds() { + // (x1, y1) is the top left corner of the window, (x2, y2) is the bottom right corner + final double slack = 10; + final double width = window.getWidth() - 2 * slack; + final double height = window.getHeight() - 2 * slack; + final double x1 = window.getX() + slack; + final double y1 = window.getY() + slack; + final double x2 = x1 + width; + final double y2 = y1 + height; + + final ObservableList screens = Screen.getScreensForRectangle(x1, y1, width, height); + + // Find the total visible area of the window + double visibleArea = 0; + for (Screen screen : screens) { + Rectangle2D bounds = screen.getVisualBounds(); + + double xOverlap = Math.min(x2, bounds.getMaxX()) - Math.max(x1, bounds.getMinX()); + double yOverlap = Math.min(y2, bounds.getMaxY()) - Math.max(y1, bounds.getMinY()); + + visibleArea += xOverlap * yOverlap; + } + + final double windowArea = width * height; + + // Within bounds if the visible area matches the window area + return visibleArea == windowArea; } - private String getMonitorSizes() { - ObservableList screens = Screen.getScreens(); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < screens.size(); i++) { - Rectangle2D screenBounds = screens.get(i).getBounds(); - if (!sb.isEmpty()) sb.append(" "); - sb.append("displayId: " + i + ", " + screenBounds.getWidth() + "x" + screenBounds.getHeight() + ";"); + private void checkDisplayBounds(WindowEvent evt) { + + // Minimizing a window in Windows and closing it could result in an out of bounds position at (x, y) = (-32000, -32000) + // See https://devblogs.microsoft.com/oldnewthing/20041028-00/?p=37453 + // If the position is (-32000, -32000), restore to the last saved position + if (window.getX() == -32000 && window.getY() == -32000) { + window.setX(settings.windowXPosition.get()); + window.setY(settings.windowYPosition.get()); + window.setWidth(settings.windowWidth.get()); + window.setHeight(settings.windowHeight.get()); + } + + if (!isWithinDisplayBounds()) { + // If the position is illegal, then the window appears on the main screen in the middle of the window. + Rectangle2D primaryScreenBounds = Screen.getPrimary().getBounds(); + window.setX((primaryScreenBounds.getWidth() - window.getMinWidth()) / 2); + window.setY((primaryScreenBounds.getHeight() - window.getMinHeight()) / 2); + window.setWidth(window.getMinWidth()); + window.setHeight(window.getMinHeight()); + savePositionalSettings(); } - return sb.toString(); } private void startResize(MouseEvent evt) { @@ -183,5 +205,4 @@ public class ResizeController implements FxController { public boolean isShowResizingArrows() { return showResizingArrows.get(); } - } \ No newline at end of file diff --git a/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java b/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java index f0aadfdfc..357222b33 100644 --- a/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java +++ b/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java @@ -20,7 +20,9 @@ import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.value.ObservableValue; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; +import javafx.event.Event; import javafx.fxml.FXML; +import javafx.scene.control.Button; import javafx.scene.control.ListView; import javafx.scene.input.ContextMenuEvent; import javafx.scene.input.DragEvent; @@ -34,6 +36,7 @@ import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.util.EnumSet; +import java.util.ResourceBundle; import java.util.Set; import java.util.stream.Collectors; @@ -59,12 +62,21 @@ public class VaultListController implements FxController { private final RemoveVaultComponent.Builder removeVaultDialogue; private final VaultListManager vaultListManager; private final BooleanProperty draggingVaultOver = new SimpleBooleanProperty(); + private final ResourceBundle resourceBundle; public ListView vaultList; public StackPane root; + public Button addVaultBtn; @Inject - VaultListController(@MainWindow Stage mainWindow, ObservableList vaults, ObjectProperty selectedVault, VaultListCellFactory cellFactory, AddVaultWizardComponent.Builder addVaultWizard, RemoveVaultComponent.Builder removeVaultDialogue, VaultListManager vaultListManager) { + VaultListController(@MainWindow Stage mainWindow, // + ObservableList vaults, // + ObjectProperty selectedVault, // + VaultListCellFactory cellFactory, // + AddVaultWizardComponent.Builder addVaultWizard, // + RemoveVaultComponent.Builder removeVaultDialogue, // + VaultListManager vaultListManager, // + ResourceBundle resourceBundle) { this.mainWindow = mainWindow; this.vaults = vaults; this.selectedVault = selectedVault; @@ -72,6 +84,7 @@ public class VaultListController implements FxController { this.addVaultWizard = addVaultWizard; this.removeVaultDialogue = removeVaultDialogue; this.vaultListManager = vaultListManager; + this.resourceBundle = resourceBundle; this.emptyVaultList = Bindings.isEmpty(vaults); @@ -127,6 +140,15 @@ public class VaultListController implements FxController { root.setOnDragOver(this::handleDragEvent); root.setOnDragDropped(this::handleDragEvent); root.setOnDragExited(this::handleDragEvent); + + addVaultBtn.addEventFilter(ContextMenuEvent.CONTEXT_MENU_REQUESTED, Event::consume); + } + + @FXML + private void showMenu() { + double screenX = addVaultBtn.localToScreen(addVaultBtn.getBoundsInLocal()).getMinX(); + double screenY = addVaultBtn.localToScreen(addVaultBtn.getBoundsInLocal()).getMaxY(); + addVaultBtn.getContextMenu().show(addVaultBtn, screenX, screenY); } private void deselect(MouseEvent released) { @@ -144,8 +166,13 @@ public class VaultListController implements FxController { } @FXML - public void didClickAddVault() { - addVaultWizard.build().showAddVaultWizard(); + public void didClickAddNewVault() { + addVaultWizard.build().showAddNewVaultWizard(resourceBundle); + } + + @FXML + public void didClickAddExistingVault() { + addVaultWizard.build().showAddExistingVaultWizard(resourceBundle); } private void pressedShortcutToRemoveVault() { diff --git a/src/main/resources/css/dark_theme.css b/src/main/resources/css/dark_theme.css index 45cadba93..beb50f6bc 100644 --- a/src/main/resources/css/dark_theme.css +++ b/src/main/resources/css/dark_theme.css @@ -795,6 +795,16 @@ -fx-scale-shape: false; } +/******************************************************************************* + * * + * Add Vault - MenuItem * + * * + ******************************************************************************/ + +.add-vault-menu-item { + -fx-padding: 4px 8px; +} + /******************************************************************************* * * * ProgressBar * diff --git a/src/main/resources/css/light_theme.css b/src/main/resources/css/light_theme.css index c3c0faaa9..a494269b7 100644 --- a/src/main/resources/css/light_theme.css +++ b/src/main/resources/css/light_theme.css @@ -794,6 +794,16 @@ -fx-scale-shape: false; } +/******************************************************************************* + * * + * Add Vault - MenuItem * + * * + ******************************************************************************/ + +.add-vault-menu-item { + -fx-padding: 4px 8px; +} + /******************************************************************************* * * * ProgressBar * diff --git a/src/main/resources/fxml/addvault_existing.fxml b/src/main/resources/fxml/addvault_existing.fxml index c46ad6355..200eae4f9 100644 --- a/src/main/resources/fxml/addvault_existing.fxml +++ b/src/main/resources/fxml/addvault_existing.fxml @@ -24,9 +24,8 @@ - + - - - - - - - diff --git a/src/main/resources/fxml/vault_list.fxml b/src/main/resources/fxml/vault_list.fxml index 80f29f2f7..146fa877c 100644 --- a/src/main/resources/fxml/vault_list.fxml +++ b/src/main/resources/fxml/vault_list.fxml @@ -8,6 +8,8 @@ + + - diff --git a/src/main/resources/i18n/strings.properties b/src/main/resources/i18n/strings.properties index 1f36c0e07..bba386cee 100644 --- a/src/main/resources/i18n/strings.properties +++ b/src/main/resources/i18n/strings.properties @@ -41,10 +41,8 @@ traymenu.vault.reveal=Reveal # Add Vault Wizard addvaultwizard.title=Add Vault -## Welcome -addvaultwizard.welcome.newButton=Create New Vault -addvaultwizard.welcome.existingButton=Open Existing Vault ## New +addvaultwizard.new.title=Add New Vault ### Name addvaultwizard.new.nameInstruction=Choose a name for the vault addvaultwizard.new.namePrompt=Vault Name @@ -94,6 +92,7 @@ addvault.new.readme.accessLocation.2=This is your vault's access location. addvault.new.readme.accessLocation.3=Any files added to this volume will be encrypted by Cryptomator. You can work on it like on any other drive/folder. This is only a decrypted view of its content, your files stay encrypted on your hard drive all the time. addvault.new.readme.accessLocation.4=Feel free to remove this file. ## Existing +addvaultwizard.existing.title=Add Existing Vault addvaultwizard.existing.instruction=Choose the "vault.cryptomator" file of your existing vault. If only a file named "masterkey.cryptomator" exists, select that instead. addvaultwizard.existing.chooseBtn=Choose… addvaultwizard.existing.filePickerTitle=Select Vault File @@ -139,7 +138,7 @@ unlock.error.customPath.message=Unable to mount vault to custom path unlock.error.customPath.description.notSupported=If you wish to keep using the custom path, please go to the preferences and select a volume type that supports it. Otherwise, go to the vault options and choose a supported mount point. unlock.error.customPath.description.notExists=The custom mount path does not exist. Either create it in your local filesystem or change it in the vault options. unlock.error.customPath.description.inUse=The drive letter or custom mount path "%s" is already in use. -unlock.error.customPath.description.hideawayNotDir=The temporary, hidden file "%3$s" used for unlock could not be removed. Please check the file and then delete it manually. +unlock.error.customPath.description.hideawayNotDir=The temporary, hidden file "%3$s" used for unlocking could not be removed. Please check the file and then delete it manually. unlock.error.customPath.description.couldNotBeCleaned=Your vault could not be mounted to the path "%s". Please try again or choose a different path. unlock.error.customPath.description.notEmptyDir=The custom mount path "%s" is not an empty folder. Please choose an empty folder and try again. unlock.error.customPath.description.generic=You have selected a custom mount path for this vault, but using it failed with the message: %2$s @@ -367,7 +366,9 @@ main.vaultlist.contextMenu.unlock=Unlock… main.vaultlist.contextMenu.unlockNow=Unlock Now main.vaultlist.contextMenu.vaultoptions=Show Vault Options main.vaultlist.contextMenu.reveal=Reveal Drive -main.vaultlist.addVaultBtn=Add Vault +main.vaultlist.addVaultBtn=Add +main.vaultlist.addVaultBtn.menuItemNew=New Vault... +main.vaultlist.addVaultBtn.menuItemExisting=Existing Vault... ## Vault Detail ### Welcome main.vaultDetail.welcomeOnboarding=Thanks for choosing Cryptomator to protect your files. If you need any assistance, check out our getting started guides: