diff --git a/src/main/java/org/cryptomator/common/settings/Settings.java b/src/main/java/org/cryptomator/common/settings/Settings.java index e4cb9b8f7..82f2fb794 100644 --- a/src/main/java/org/cryptomator/common/settings/Settings.java +++ b/src/main/java/org/cryptomator/common/settings/Settings.java @@ -43,6 +43,8 @@ public class Settings { public static final NodeOrientation DEFAULT_USER_INTERFACE_ORIENTATION = NodeOrientation.LEFT_TO_RIGHT; public static final String DEFAULT_LICENSE_KEY = ""; public static final boolean DEFAULT_SHOW_MINIMIZE_BUTTON = false; + public static final String DEFAULT_DISPLAY_CONFIGURATION = ""; + private final ObservableList directories = FXCollections.observableArrayList(VaultSettings::observables); private final BooleanProperty askedForUpdateCheck = new SimpleBooleanProperty(DEFAULT_ASKED_FOR_UPDATE_CHECK); @@ -59,6 +61,12 @@ public class Settings { private final StringProperty licenseKey = new SimpleStringProperty(DEFAULT_LICENSE_KEY); private final BooleanProperty showMinimizeButton = new SimpleBooleanProperty(DEFAULT_SHOW_MINIMIZE_BUTTON); private final BooleanProperty showTrayIcon; + private final IntegerProperty windowXPosition = new SimpleIntegerProperty(); + private final IntegerProperty windowYPosition = new SimpleIntegerProperty(); + private final IntegerProperty windowWidth = new SimpleIntegerProperty(); + private final IntegerProperty windowHeight = new SimpleIntegerProperty(); + private final ObjectProperty displayConfiguration = new SimpleObjectProperty<>(DEFAULT_DISPLAY_CONFIGURATION); + private Consumer saveCmd; @@ -83,6 +91,11 @@ public class Settings { licenseKey.addListener(this::somethingChanged); showMinimizeButton.addListener(this::somethingChanged); showTrayIcon.addListener(this::somethingChanged); + windowXPosition.addListener(this::somethingChanged); + windowYPosition.addListener(this::somethingChanged); + windowWidth.addListener(this::somethingChanged); + windowHeight.addListener(this::somethingChanged); + displayConfiguration.addListener(this::somethingChanged); } void setSaveCmd(Consumer saveCmd) { @@ -141,7 +154,7 @@ public class Settings { return theme; } - public ObjectProperty keychainProvider() { return keychainProvider; } + public ObjectProperty keychainProvider() {return keychainProvider;} public ObjectProperty userInterfaceOrientation() { return userInterfaceOrientation; @@ -158,4 +171,24 @@ public class Settings { public BooleanProperty showTrayIcon() { return showTrayIcon; } + + public IntegerProperty windowXPositionProperty() { + return windowXPosition; + } + + public IntegerProperty windowYPositionProperty() { + return windowYPosition; + } + + public IntegerProperty windowWidthProperty() { + return windowWidth; + } + + public IntegerProperty windowHeightProperty() { + return windowHeight; + } + + public ObjectProperty displayConfigurationProperty() { + return displayConfiguration; + } } diff --git a/src/main/java/org/cryptomator/common/settings/SettingsJsonAdapter.java b/src/main/java/org/cryptomator/common/settings/SettingsJsonAdapter.java index 5bcb5f3d7..6d8d880e6 100644 --- a/src/main/java/org/cryptomator/common/settings/SettingsJsonAdapter.java +++ b/src/main/java/org/cryptomator/common/settings/SettingsJsonAdapter.java @@ -52,6 +52,12 @@ public class SettingsJsonAdapter extends TypeAdapter { out.name("licenseKey").value(value.licenseKey().get()); out.name("showMinimizeButton").value(value.showMinimizeButton().get()); out.name("showTrayIcon").value(value.showTrayIcon().get()); + out.name("windowXPosition").value((value.windowXPositionProperty().get())); + out.name("windowYPosition").value((value.windowYPositionProperty().get())); + out.name("windowWidth").value((value.windowWidthProperty().get())); + out.name("windowHeight").value((value.windowHeightProperty().get())); + out.name("displayConfiguration").value((value.displayConfigurationProperty().get())); + out.endObject(); } @@ -86,6 +92,12 @@ public class SettingsJsonAdapter extends TypeAdapter { case "licenseKey" -> settings.licenseKey().set(in.nextString()); case "showMinimizeButton" -> settings.showMinimizeButton().set(in.nextBoolean()); case "showTrayIcon" -> settings.showTrayIcon().set(in.nextBoolean()); + case "windowXPosition" -> settings.windowXPositionProperty().set(in.nextInt()); + case "windowYPosition" -> settings.windowYPositionProperty().set(in.nextInt()); + case "windowWidth" -> settings.windowWidthProperty().set(in.nextInt()); + case "windowHeight" -> settings.windowHeightProperty().set(in.nextInt()); + case "displayConfiguration" -> settings.displayConfigurationProperty().set(in.nextString()); + default -> { LOG.warn("Unsupported vault setting found in JSON: " + name); in.skipValue(); diff --git a/src/main/java/org/cryptomator/ui/mainwindow/MainWindowController.java b/src/main/java/org/cryptomator/ui/mainwindow/MainWindowController.java index 392671246..5d1781e19 100644 --- a/src/main/java/org/cryptomator/ui/mainwindow/MainWindowController.java +++ b/src/main/java/org/cryptomator/ui/mainwindow/MainWindowController.java @@ -23,8 +23,6 @@ import javafx.scene.layout.StackPane; import javafx.stage.Stage; import java.io.File; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.util.Set; import java.util.stream.Collectors; @@ -55,7 +53,7 @@ public class MainWindowController implements FxController { @FXML public void initialize() { - LOG.debug("init MainWindowController"); + LOG.trace("init MainWindowController"); root.setOnDragEntered(this::handleDragEvent); root.setOnDragOver(this::handleDragEvent); root.setOnDragDropped(this::handleDragEvent); diff --git a/src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java b/src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java index 90311bd5b..545a45c04 100644 --- a/src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java +++ b/src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java @@ -6,17 +6,17 @@ import dagger.Provides; import dagger.multibindings.IntoMap; import org.cryptomator.common.vaults.Vault; import org.cryptomator.ui.addvaultwizard.AddVaultWizardComponent; -import org.cryptomator.ui.common.FxmlLoaderFactory; import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.common.FxControllerKey; import org.cryptomator.ui.common.FxmlFile; +import org.cryptomator.ui.common.FxmlLoaderFactory; import org.cryptomator.ui.common.FxmlScene; import org.cryptomator.ui.common.StageFactory; import org.cryptomator.ui.health.HealthCheckComponent; import org.cryptomator.ui.migration.MigrationComponent; import org.cryptomator.ui.removevault.RemoveVaultComponent; -import org.cryptomator.ui.vaultoptions.VaultOptionsComponent; import org.cryptomator.ui.stats.VaultStatisticsComponent; +import org.cryptomator.ui.vaultoptions.VaultOptionsComponent; import org.cryptomator.ui.wrongfilealert.WrongFileAlertComponent; import javax.inject.Provider; @@ -49,11 +49,8 @@ abstract class MainWindowModule { @MainWindowScoped 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"); return stage; } diff --git a/src/main/java/org/cryptomator/ui/mainwindow/MainWindowTitleController.java b/src/main/java/org/cryptomator/ui/mainwindow/MainWindowTitleController.java index ef050e799..b33494158 100644 --- a/src/main/java/org/cryptomator/ui/mainwindow/MainWindowTitleController.java +++ b/src/main/java/org/cryptomator/ui/mainwindow/MainWindowTitleController.java @@ -16,6 +16,7 @@ import javafx.beans.binding.Bindings; import javafx.beans.binding.BooleanBinding; import javafx.beans.property.ReadOnlyBooleanProperty; import javafx.fxml.FXML; +import javafx.scene.input.MouseButton; import javafx.scene.layout.HBox; import javafx.stage.Stage; @@ -53,22 +54,47 @@ public class MainWindowTitleController implements FxController { @FXML public void initialize() { - LOG.debug("init MainWindowTitleController"); + LOG.trace("init MainWindowTitleController"); updateChecker.automaticallyCheckForUpdatesIfEnabled(); titleBar.setOnMousePressed(event -> { xOffset = event.getSceneX(); yOffset = event.getSceneY(); + + }); + titleBar.setOnMouseClicked(event -> { + if (event.getButton().equals(MouseButton.PRIMARY) && event.getClickCount() == 2) { + if (window.isFullScreen()) { + window.setFullScreen(false); + } else { + window.setFullScreen(true); + } + } }); titleBar.setOnMouseDragged(event -> { + if (window.isFullScreen()) return; window.setX(event.getScreenX() - xOffset); window.setY(event.getScreenY() - yOffset); }); + titleBar.setOnDragDetected(mouseDragEvent -> { + titleBar.startFullDrag(); + }); + titleBar.setOnMouseDragReleased(mouseDragEvent -> { + saveWindowSettings(); + }); + window.setOnCloseRequest(event -> { close(); event.consume(); }); } + private void saveWindowSettings() { + settings.windowYPositionProperty().setValue(window.getY()); + settings.windowXPositionProperty().setValue(window.getX()); + settings.windowWidthProperty().setValue(window.getWidth()); + settings.windowHeightProperty().setValue(window.getHeight()); + } + @FXML public void close() { if (trayMenuInitialized) { diff --git a/src/main/java/org/cryptomator/ui/mainwindow/ResizeController.java b/src/main/java/org/cryptomator/ui/mainwindow/ResizeController.java index 908944d68..448d54d91 100644 --- a/src/main/java/org/cryptomator/ui/mainwindow/ResizeController.java +++ b/src/main/java/org/cryptomator/ui/mainwindow/ResizeController.java @@ -1,41 +1,100 @@ package org.cryptomator.ui.mainwindow; +import org.cryptomator.common.settings.Settings; import org.cryptomator.ui.common.FxController; +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; +import javafx.geometry.Rectangle2D; import javafx.scene.input.MouseEvent; import javafx.scene.layout.Region; +import javafx.stage.Screen; import javafx.stage.Stage; @MainWindow public class ResizeController implements FxController { + private static final Logger LOG = LoggerFactory.getLogger(ResizeController.class); + private final Stage window; public Region tlResizer; public Region trResizer; public Region blResizer; public Region brResizer; + public Region tResizer; + public Region rResizer; + public Region bResizer; + public Region lResizer; + public Region lDefaultRegion; + public Region tDefaultRegion; + public Region rDefaultRegion; + public Region bDefaultRegion; private double origX, origY, origW, origH; + private final Settings settings; + + private final BooleanBinding showResizingArrows; + @Inject - ResizeController(@MainWindow Stage window) { + ResizeController(@MainWindow Stage window, Settings settings) { this.window = window; - // TODO inject settings and save current position and size + this.settings = settings; + this.showResizingArrows = Bindings.createBooleanBinding(this::isShowResizingArrows, window.fullScreenProperty()); } @FXML public void initialize() { - tlResizer.setOnMousePressed(this::startResize); - trResizer.setOnMousePressed(this::startResize); - blResizer.setOnMousePressed(this::startResize); - brResizer.setOnMousePressed(this::startResize); - tlResizer.setOnMouseDragged(this::resizeTopLeft); - trResizer.setOnMouseDragged(this::resizeTopRight); - blResizer.setOnMouseDragged(this::resizeBottomLeft); - brResizer.setOnMouseDragged(this::resizeBottomRight); + LOG.trace("init ResizeController"); + + if (neverTouched()) { + settings.displayConfigurationProperty().setValue(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.windowHeightProperty().get() > window.getMinHeight() ? settings.windowHeightProperty().get() : window.getMinHeight()); + window.setWidth(settings.windowWidthProperty().get() > window.getMinWidth() ? settings.windowWidthProperty().get() : window.getMinWidth()); + window.setX(settings.windowXPositionProperty().get()); + window.setY(settings.windowYPositionProperty().get()); + } + } + savePositionalSettings(); + } + + private boolean neverTouched() { + return (settings.windowHeightProperty().get() == 0) && (settings.windowWidthProperty().get() == 0) && (settings.windowXPositionProperty().get() == 0) && (settings.windowYPositionProperty().get() == 0); + } + + private boolean didDisplayConfigurationChange() { + String currentDisplayConfiguration = getMonitorSizes(); + String settingsDisplayConfiguration = settings.displayConfigurationProperty().get(); + boolean configurationHasChanged = !settingsDisplayConfiguration.equals(currentDisplayConfiguration); + if (configurationHasChanged) settings.displayConfigurationProperty().setValue(currentDisplayConfiguration); + return configurationHasChanged; + } + + 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() + ";"); + } + return sb.toString(); } private void startResize(MouseEvent evt) { @@ -45,27 +104,33 @@ public class ResizeController implements FxController { origH = window.getHeight(); } + @FXML private void resizeTopLeft(MouseEvent evt) { resizeTop(evt); resizeLeft(evt); } + @FXML private void resizeTopRight(MouseEvent evt) { resizeTop(evt); resizeRight(evt); } + @FXML private void resizeBottomLeft(MouseEvent evt) { resizeBottom(evt); resizeLeft(evt); } + @FXML private void resizeBottomRight(MouseEvent evt) { resizeBottom(evt); resizeRight(evt); } + @FXML private void resizeTop(MouseEvent evt) { + startResize(evt); double newY = evt.getScreenY(); double dy = newY - origY; double newH = origH - dy; @@ -75,7 +140,9 @@ public class ResizeController implements FxController { } } + @FXML private void resizeLeft(MouseEvent evt) { + startResize(evt); double newX = evt.getScreenX(); double dx = newX - origX; double newW = origW - dx; @@ -85,6 +152,7 @@ public class ResizeController implements FxController { } } + @FXML private void resizeBottom(MouseEvent evt) { double newH = evt.getSceneY(); if (newH < window.getMaxHeight() && newH > window.getMinHeight()) { @@ -92,6 +160,7 @@ public class ResizeController implements FxController { } } + @FXML private void resizeRight(MouseEvent evt) { double newW = evt.getSceneX(); if (newW < window.getMaxWidth() && newW > window.getMinWidth()) { @@ -99,4 +168,21 @@ public class ResizeController implements FxController { } } -} + @FXML + public void savePositionalSettings() { + settings.windowHeightProperty().setValue(window.getHeight()); + settings.windowWidthProperty().setValue(window.getWidth()); + settings.windowYPositionProperty().setValue(window.getY()); + settings.windowXPositionProperty().setValue(window.getX()); + } + + public BooleanBinding showResizingArrowsProperty() { + return showResizingArrows; + } + + public boolean isShowResizingArrows() { + //If in fullscreen resizing is not be possible; + return !window.isFullScreen(); + } + +} \ No newline at end of file diff --git a/src/main/resources/fxml/main_window.fxml b/src/main/resources/fxml/main_window.fxml index ff8e65292..91e7512a4 100644 --- a/src/main/resources/fxml/main_window.fxml +++ b/src/main/resources/fxml/main_window.fxml @@ -12,7 +12,7 @@ fx:id="root" fx:controller="org.cryptomator.ui.mainwindow.MainWindowController" styleClass="main-window"> - + diff --git a/src/main/resources/fxml/main_window_resize.fxml b/src/main/resources/fxml/main_window_resize.fxml index b4eb46916..7d5fb9437 100644 --- a/src/main/resources/fxml/main_window_resize.fxml +++ b/src/main/resources/fxml/main_window_resize.fxml @@ -9,9 +9,22 @@ + + + - - - - + + + + + + + + + + + + + + \ No newline at end of file