Sfoglia il codice sorgente

Merge pull request #1761 from cryptomator/feature/#1733-window-position

Persist last known window position and improve resizing
Armin Schrenk 3 anni fa
parent
commit
af4603f022

+ 34 - 1
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<VaultSettings> 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<String> displayConfiguration = new SimpleObjectProperty<>(DEFAULT_DISPLAY_CONFIGURATION);
+
 
 	private Consumer<Settings> 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<Settings> saveCmd) {
@@ -141,7 +154,7 @@ public class Settings {
 		return theme;
 	}
 
-	public ObjectProperty<String> keychainProvider() { return keychainProvider; }
+	public ObjectProperty<String> keychainProvider() {return keychainProvider;}
 
 	public ObjectProperty<NodeOrientation> 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<String> displayConfigurationProperty() {
+		return displayConfiguration;
+	}
 }

+ 12 - 0
src/main/java/org/cryptomator/common/settings/SettingsJsonAdapter.java

@@ -52,6 +52,12 @@ public class SettingsJsonAdapter extends TypeAdapter<Settings> {
 		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<Settings> {
 				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();

+ 1 - 3
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);

+ 2 - 5
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;
 	}

+ 27 - 1
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) {

+ 97 - 11
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<Screen> 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();
+	}
+
+}

+ 1 - 1
src/main/resources/fxml/main_window.fxml

@@ -12,7 +12,7 @@
 		   fx:id="root"
 		   fx:controller="org.cryptomator.ui.mainwindow.MainWindowController"
 		   styleClass="main-window">
-	<VBox>
+	<VBox minWidth="650">
 		<fx:include source="main_window_title.fxml" VBox.vgrow="NEVER"/>
 		<StackPane VBox.vgrow="ALWAYS">
 			<SplitPane dividerPositions="0.33" orientation="HORIZONTAL">

+ 17 - 4
src/main/resources/fxml/main_window_resize.fxml

@@ -9,9 +9,22 @@
 	<fx:define>
 		<Cursor fx:id="nwResize" fx:constant="NW_RESIZE"/>
 		<Cursor fx:id="neResize" fx:constant="NE_RESIZE"/>
+		<Cursor fx:id="nsResize" fx:constant="N_RESIZE"/>
+		<Cursor fx:id="ewResize" fx:constant="E_RESIZE"/>
+		<Cursor fx:id="default" fx:constant="DEFAULT"/>
 	</fx:define>
-	<Region fx:id="tlResizer" cursor="${nwResize}" prefWidth="10" prefHeight="10" maxWidth="-Infinity" maxHeight="-Infinity" AnchorPane.topAnchor="0" AnchorPane.leftAnchor="0"/>
-	<Region fx:id="trResizer" cursor="${neResize}" prefWidth="10" prefHeight="10" maxWidth="-Infinity" maxHeight="-Infinity" AnchorPane.topAnchor="0" AnchorPane.rightAnchor="0"/>
-	<Region fx:id="blResizer" cursor="${neResize}" prefWidth="10" prefHeight="10" maxWidth="-Infinity" maxHeight="-Infinity" AnchorPane.bottomAnchor="0" AnchorPane.leftAnchor="0"/>
-	<Region fx:id="brResizer" cursor="${nwResize}" prefWidth="10" prefHeight="10" maxWidth="-Infinity" maxHeight="-Infinity" AnchorPane.bottomAnchor="0" AnchorPane.rightAnchor="0"/>
+
+	<Region fx:id="tlResizer" cursor="${nwResize}" prefWidth="10" prefHeight="10" maxWidth="-Infinity" maxHeight="-Infinity" visible="${controller.showResizingArrows}" managed="${controller.showResizingArrows}" onMouseDragged="#resizeTopLeft" onMouseReleased="#savePositionalSettings" AnchorPane.topAnchor="0" AnchorPane.leftAnchor="0"/>
+	<Region fx:id="trResizer" cursor="${neResize}" prefWidth="10" prefHeight="10" maxWidth="-Infinity" maxHeight="-Infinity" visible="${controller.showResizingArrows}" managed="${controller.showResizingArrows}" onMouseDragged="#resizeTopRight" onMouseReleased="#savePositionalSettings" AnchorPane.topAnchor="0" AnchorPane.rightAnchor="0"/>
+	<Region fx:id="blResizer" cursor="${neResize}" prefWidth="10" prefHeight="10" maxWidth="-Infinity" maxHeight="-Infinity" visible="${controller.showResizingArrows}" managed="${controller.showResizingArrows}" onMouseDragged="#resizeBottomLeft" onMouseReleased="#savePositionalSettings" AnchorPane.bottomAnchor="0" AnchorPane.leftAnchor="0"/>
+	<Region fx:id="brResizer" cursor="${nwResize}" prefWidth="10" prefHeight="10" maxWidth="-Infinity" maxHeight="-Infinity" visible="${controller.showResizingArrows}" managed="${controller.showResizingArrows}" onMouseDragged="#resizeBottomRight" onMouseReleased="#savePositionalSettings" AnchorPane.bottomAnchor="0" AnchorPane.rightAnchor="0"/>
+	<Region fx:id="tResizer" cursor="${nsResize}" prefWidth="0" prefHeight="6" maxWidth="-Infinity" maxHeight="-Infinity" visible="${controller.showResizingArrows}" managed="${controller.showResizingArrows}" onMouseDragged="#resizeTop" onMouseReleased="#savePositionalSettings" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="0.0"/>
+	<Region fx:id="rResizer" cursor="${ewResize}" prefWidth="6" prefHeight="0" maxWidth="-Infinity" maxHeight="-Infinity" visible="${controller.showResizingArrows}" managed="${controller.showResizingArrows}" onMouseDragged="#resizeRight" onMouseReleased="#savePositionalSettings" AnchorPane.bottomAnchor="10.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="10.0"/>
+	<Region fx:id="bResizer" cursor="${nsResize}" prefWidth="6" prefHeight="6" maxWidth="-Infinity" maxHeight="-Infinity" visible="${controller.showResizingArrows}" managed="${controller.showResizingArrows}" onMouseDragged="#resizeBottom" onMouseReleased="#savePositionalSettings" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0"/>
+	<Region fx:id="lResizer" cursor="${ewResize}" prefWidth="6" prefHeight="6" maxWidth="-Infinity" maxHeight="-Infinity" visible="${controller.showResizingArrows}" managed="${controller.showResizingArrows}" onMouseDragged="#resizeLeft" onMouseReleased="#savePositionalSettings" AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="10.0"/>
+	<Region fx:id="lDefaultRegion" cursor="${default}" prefWidth="1" prefHeight="1" maxWidth="-Infinity" maxHeight="-Infinity" AnchorPane.bottomAnchor="-1" AnchorPane.leftAnchor="-1" AnchorPane.topAnchor="-1"/>
+	<Region fx:id="tDefaultRegion" cursor="${default}" prefWidth="1" prefHeight="1" maxWidth="-Infinity" maxHeight="-Infinity" AnchorPane.leftAnchor="-1" AnchorPane.topAnchor="-1" AnchorPane.rightAnchor="-1"/>
+	<Region fx:id="rDefaultRegion" cursor="${default}" prefWidth="1" prefHeight="1" maxWidth="-Infinity" maxHeight="-Infinity" AnchorPane.topAnchor="-1" AnchorPane.rightAnchor="-1" AnchorPane.bottomAnchor="-1"/>
+	<Region fx:id="bDefaultRegion" cursor="${default}" prefWidth="1" prefHeight="1" maxWidth="-Infinity" maxHeight="-Infinity" AnchorPane.rightAnchor="-1" AnchorPane.bottomAnchor="-1" AnchorPane.leftAnchor="-1"/>
+
 </AnchorPane>