瀏覽代碼

Merge pull request #3467 from cryptomator/feature/redesign-mainwindow

Feature: Redesigned MainWindow
mindmonk 11 月之前
父節點
當前提交
8d7bf3a370

+ 4 - 4
src/main/java/org/cryptomator/common/settings/Settings.java

@@ -67,8 +67,8 @@ public class Settings {
 	public final StringProperty quickAccessService;
 	public final ObjectProperty<NodeOrientation> userInterfaceOrientation;
 	public final StringProperty licenseKey;
-	public final BooleanProperty showMinimizeButton;
 	public final BooleanProperty showTrayIcon;
+	public final BooleanProperty compactMode;
 	public final IntegerProperty windowXPosition;
 	public final IntegerProperty windowYPosition;
 	public final IntegerProperty windowWidth;
@@ -105,8 +105,8 @@ public class Settings {
 		this.keychainProvider = new SimpleStringProperty(this, "keychainProvider", json.keychainProvider);
 		this.userInterfaceOrientation = new SimpleObjectProperty<>(this, "userInterfaceOrientation", parseEnum(json.uiOrientation, NodeOrientation.class, NodeOrientation.LEFT_TO_RIGHT));
 		this.licenseKey = new SimpleStringProperty(this, "licenseKey", json.licenseKey);
-		this.showMinimizeButton = new SimpleBooleanProperty(this, "showMinimizeButton", json.showMinimizeButton);
 		this.showTrayIcon = new SimpleBooleanProperty(this, "showTrayIcon", json.showTrayIcon);
+		this.compactMode = new SimpleBooleanProperty(this, "compactMode", json.compactMode);
 		this.windowXPosition = new SimpleIntegerProperty(this, "windowXPosition", json.windowXPosition);
 		this.windowYPosition = new SimpleIntegerProperty(this, "windowYPosition", json.windowYPosition);
 		this.windowWidth = new SimpleIntegerProperty(this, "windowWidth", json.windowWidth);
@@ -134,8 +134,8 @@ public class Settings {
 		keychainProvider.addListener(this::somethingChanged);
 		userInterfaceOrientation.addListener(this::somethingChanged);
 		licenseKey.addListener(this::somethingChanged);
-		showMinimizeButton.addListener(this::somethingChanged);
 		showTrayIcon.addListener(this::somethingChanged);
+		compactMode.addListener(this::somethingChanged);
 		windowXPosition.addListener(this::somethingChanged);
 		windowYPosition.addListener(this::somethingChanged);
 		windowWidth.addListener(this::somethingChanged);
@@ -190,8 +190,8 @@ public class Settings {
 		json.keychainProvider = keychainProvider.get();
 		json.uiOrientation = userInterfaceOrientation.get().name();
 		json.licenseKey = licenseKey.get();
-		json.showMinimizeButton = showMinimizeButton.get();
 		json.showTrayIcon = showTrayIcon.get();
+		json.compactMode = compactMode.get();
 		json.windowXPosition = windowXPosition.get();
 		json.windowYPosition = windowYPosition.get();
 		json.windowWidth = windowWidth.get();

+ 3 - 3
src/main/java/org/cryptomator/common/settings/SettingsJson.java

@@ -51,12 +51,12 @@ class SettingsJson {
 	@JsonProperty("port")
 	int port = Settings.DEFAULT_PORT;
 
-	@JsonProperty("showMinimizeButton")
-	boolean showMinimizeButton = Settings.DEFAULT_SHOW_MINIMIZE_BUTTON;
-
 	@JsonProperty("showTrayIcon")
 	boolean showTrayIcon;
 
+	@JsonProperty("compactMode")
+	boolean compactMode;
+
 	@JsonProperty("startHidden")
 	boolean startHidden = Settings.DEFAULT_START_HIDDEN;
 

+ 96 - 0
src/main/java/org/cryptomator/ui/controls/NotificationBar.java

@@ -0,0 +1,96 @@
+package org.cryptomator.ui.controls;
+
+import javafx.beans.property.BooleanProperty;
+import javafx.beans.property.SimpleBooleanProperty;
+import javafx.fxml.FXML;
+import javafx.geometry.Pos;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Region;
+import javafx.scene.layout.VBox;
+
+public class NotificationBar extends HBox {
+
+	@FXML
+	private Label notificationLabel;
+
+	private final BooleanProperty dismissable = new SimpleBooleanProperty();
+	private final BooleanProperty notify = new SimpleBooleanProperty();
+
+
+	public NotificationBar() {
+		setAlignment(Pos.CENTER);
+		setStyle("-fx-alignment: center;");
+
+		Region spacer = new Region();
+		spacer.setMinWidth(40);
+
+		Region leftRegion = new Region();
+		HBox.setHgrow(leftRegion, javafx.scene.layout.Priority.ALWAYS);
+
+		Region rightRegion = new Region();
+		HBox.setHgrow(rightRegion, javafx.scene.layout.Priority.ALWAYS);
+
+		VBox vbox = new VBox();
+		vbox.setAlignment(Pos.CENTER);
+		HBox.setHgrow(vbox, javafx.scene.layout.Priority.ALWAYS);
+
+		notificationLabel = new Label();
+		notificationLabel.getStyleClass().add("notification-label");
+		notificationLabel.setStyle("-fx-alignment: center;");
+		vbox.getChildren().add(notificationLabel);
+
+		Button closeButton = new Button("X");
+		closeButton.setMinWidth(40);
+		closeButton.setStyle("-fx-background-color: transparent; -fx-text-fill: white; -fx-font-weight: bold;");
+		closeButton.visibleProperty().bind(dismissable);
+
+		closeButton.setOnAction(_ -> {
+			visibleProperty().unbind();
+			managedProperty().unbind();
+			visibleProperty().set(false);
+			managedProperty().set(false);
+		});
+		closeButton.visibleProperty().bind(dismissable);
+
+		getChildren().addAll(spacer, leftRegion, vbox, rightRegion, closeButton);
+
+		visibleProperty().bind(notifyProperty());
+		managedProperty().bind(notifyProperty());
+	}
+
+	public String getText() {
+		return notificationLabel.getText();
+	}
+
+	public void setText(String text) {
+		notificationLabel.setText(text);
+	}
+
+	public void setStyleClass(String styleClass) {
+		getStyleClass().clear();
+		getStyleClass().add(styleClass);
+	}
+
+	public boolean isDismissable() {
+		return dismissable.get();
+	}
+
+	public void setDismissable(boolean value) {
+		dismissable.set(value);
+	}
+
+	public boolean getNotify() {
+		return notify.get();
+	}
+
+	public void setNotify(boolean value) {
+		notify.set(value);
+	}
+
+	public BooleanProperty notifyProperty() {
+		return notify;
+	}
+
+}

+ 93 - 8
src/main/java/org/cryptomator/ui/mainwindow/MainWindowController.java

@@ -1,19 +1,26 @@
 package org.cryptomator.ui.mainwindow;
 
+import javafx.beans.Observable;
+import javafx.beans.binding.BooleanBinding;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.ReadOnlyBooleanProperty;
+import javafx.beans.property.ReadOnlyObjectProperty;
+import javafx.fxml.FXML;
+import javafx.scene.layout.StackPane;
+import javafx.stage.Stage;
 import org.apache.commons.lang3.SystemUtils;
+import org.cryptomator.common.LicenseHolder;
+import org.cryptomator.common.settings.Settings;
 import org.cryptomator.common.vaults.Vault;
 import org.cryptomator.common.vaults.VaultListManager;
 import org.cryptomator.ui.common.FxController;
+import org.cryptomator.ui.fxapp.FxApplicationWindows;
+import org.cryptomator.ui.fxapp.UpdateChecker;
+import org.cryptomator.ui.preferences.SelectedPreferencesTab;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import javax.inject.Inject;
-import javafx.beans.Observable;
-import javafx.beans.property.ObjectProperty;
-import javafx.beans.property.ReadOnlyObjectProperty;
-import javafx.fxml.FXML;
-import javafx.scene.layout.StackPane;
-import javafx.stage.Stage;
 
 @MainWindowScoped
 public class MainWindowController implements FxController {
@@ -22,22 +29,61 @@ public class MainWindowController implements FxController {
 
 	private final Stage window;
 	private final ReadOnlyObjectProperty<Vault> selectedVault;
+	private final Settings settings;
+	private final FxApplicationWindows appWindows;
+	private final BooleanBinding updateAvailable;
+	private final LicenseHolder licenseHolder;
 
-	public StackPane root;
+	@FXML
+	private StackPane root;
 
 	@Inject
-	public MainWindowController(@MainWindow Stage window, ObjectProperty<Vault> selectedVault) {
+	public MainWindowController(@MainWindow Stage window, //
+								ObjectProperty<Vault> selectedVault, //
+								Settings settings, //
+								FxApplicationWindows appWindows, //
+								UpdateChecker updateChecker, //
+								LicenseHolder licenseHolder) {
 		this.window = window;
 		this.selectedVault = selectedVault;
+		this.settings = settings;
+		this.appWindows = appWindows;
+		this.updateAvailable = updateChecker.updateAvailableProperty();
+		this.licenseHolder = licenseHolder;
+		updateChecker.automaticallyCheckForUpdatesIfEnabled();
+
 	}
 
 	@FXML
 	public void initialize() {
 		LOG.trace("init MainWindowController");
+
 		if (SystemUtils.IS_OS_WINDOWS) {
 			root.getStyleClass().add("os-windows");
 		}
 		window.focusedProperty().addListener(this::mainWindowFocusChanged);
+
+		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());
+		}
+		window.widthProperty().addListener((_, _, _) -> savePositionalSettings());
+		window.heightProperty().addListener((_, _, _) -> savePositionalSettings());
+		window.xProperty().addListener((_, _, _) -> savePositionalSettings());
+		window.yProperty().addListener((_, _, _) -> savePositionalSettings());
+	}
+
+	private boolean neverTouched() {
+		return (settings.windowHeight.get() == 0) && (settings.windowWidth.get() == 0) && (settings.windowXPosition.get() == 0) && (settings.windowYPosition.get() == 0);
+	}
+
+	public void savePositionalSettings() {
+		settings.windowWidth.setValue(window.getWidth());
+		settings.windowHeight.setValue(window.getHeight());
+		settings.windowXPosition.setValue(window.getX());
+		settings.windowYPosition.setValue(window.getY());
 	}
 
 	private void mainWindowFocusChanged(Observable observable) {
@@ -47,4 +93,43 @@ public class MainWindowController implements FxController {
 		}
 	}
 
+	@FXML
+	public void showGeneralPreferences() {
+		appWindows.showPreferencesWindow(SelectedPreferencesTab.GENERAL);
+	}
+
+	@FXML
+	public void showContributePreferences() {
+		appWindows.showPreferencesWindow(SelectedPreferencesTab.CONTRIBUTE);
+	}
+
+	@FXML
+	public void showUpdatePreferences() {
+		appWindows.showPreferencesWindow(SelectedPreferencesTab.UPDATES);
+	}
+
+	public ReadOnlyBooleanProperty debugModeEnabledProperty() {
+		return settings.debugMode;
+	}
+
+	public boolean getDebugModeEnabled() {
+		return debugModeEnabledProperty().get();
+	}
+
+	public BooleanBinding updateAvailableProperty() {
+		return updateAvailable;
+	}
+
+	public boolean getUpdateAvailable() {
+		return updateAvailable.get();
+	}
+
+	public BooleanBinding licenseValidProperty(){
+		return licenseHolder.validLicenseProperty();
+	}
+
+	public boolean getLicenseValid() {
+		return licenseHolder.isValidLicense();
+	}
+
 }

+ 2 - 15
src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java

@@ -6,7 +6,6 @@ import dagger.Provides;
 import dagger.multibindings.IntoMap;
 import org.cryptomator.common.vaults.Vault;
 import org.cryptomator.ui.addvaultwizard.AddVaultWizardComponent;
-import org.cryptomator.ui.error.ErrorComponent;
 import org.cryptomator.ui.common.FxController;
 import org.cryptomator.ui.common.FxControllerKey;
 import org.cryptomator.ui.common.FxmlFile;
@@ -14,8 +13,8 @@ import org.cryptomator.ui.common.FxmlLoaderFactory;
 import org.cryptomator.ui.common.FxmlScene;
 import org.cryptomator.ui.common.StageFactory;
 import org.cryptomator.ui.common.StageInitializer;
+import org.cryptomator.ui.error.ErrorComponent;
 import org.cryptomator.ui.fxapp.PrimaryStage;
-import org.cryptomator.ui.health.HealthCheckComponent;
 import org.cryptomator.ui.migration.MigrationComponent;
 import org.cryptomator.ui.removevault.RemoveVaultComponent;
 import org.cryptomator.ui.stats.VaultStatisticsComponent;
@@ -28,7 +27,6 @@ import javafx.beans.property.SimpleObjectProperty;
 import javafx.scene.Scene;
 import javafx.stage.Modality;
 import javafx.stage.Stage;
-import javafx.stage.StageStyle;
 import java.util.Map;
 import java.util.ResourceBundle;
 
@@ -41,9 +39,8 @@ abstract class MainWindowModule {
 	static Stage provideMainWindow(@PrimaryStage Stage stage, StageInitializer initializer) {
 		initializer.accept(stage);
 		stage.setTitle("Cryptomator");
-		stage.initStyle(StageStyle.UNDECORATED);
 		stage.setMinWidth(650);
-		stage.setMinHeight(440);
+		stage.setMinHeight(498);
 		return stage;
 	}
 
@@ -85,16 +82,6 @@ abstract class MainWindowModule {
 	@FxControllerKey(MainWindowController.class)
 	abstract FxController bindMainWindowController(MainWindowController controller);
 
-	@Binds
-	@IntoMap
-	@FxControllerKey(MainWindowTitleController.class)
-	abstract FxController bindMainWindowTitleController(MainWindowTitleController controller);
-
-	@Binds
-	@IntoMap
-	@FxControllerKey(ResizeController.class)
-	abstract FxController bindResizeController(ResizeController controller);
-
 	@Binds
 	@IntoMap
 	@FxControllerKey(VaultListController.class)

+ 5 - 7
src/main/java/org/cryptomator/ui/mainwindow/MainWindowSceneFactory.java

@@ -18,22 +18,20 @@ 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> mainWindowTitleController;
+	private final Stage window;
 	private final Lazy<VaultListController> vaultListController;
 
 	@Inject
-	public MainWindowSceneFactory(Settings settings, Lazy<MainWindowTitleController> mainWindowTitleController, Lazy<VaultListController> vaultListController) {
+	public MainWindowSceneFactory(Settings settings, @MainWindow Stage window, Lazy<VaultListController> vaultListController) {
 		super(settings);
-		this.mainWindowTitleController = mainWindowTitleController;
+		this.window = window;
 		this.vaultListController = vaultListController;
 	}
 
 	@Override
 	protected void setupDefaultAccelerators(Scene scene, Stage stage) {
-		if (SystemUtils.IS_OS_WINDOWS) {
-			scene.getAccelerators().put(ALT_F4, mainWindowTitleController.get()::close);
-		} else {
-			scene.getAccelerators().put(SHORTCUT_W, mainWindowTitleController.get()::close);
+		if (!SystemUtils.IS_OS_WINDOWS) {
+			scene.getAccelerators().put(SHORTCUT_W, window::close);
 		}
 		scene.getAccelerators().put(SHORTCUT_N, vaultListController.get()::didClickAddNewVault);
 		scene.getAccelerators().put(SHORTCUT_O, vaultListController.get()::didClickAddExistingVault);

+ 0 - 157
src/main/java/org/cryptomator/ui/mainwindow/MainWindowTitleController.java

@@ -1,157 +0,0 @@
-package org.cryptomator.ui.mainwindow;
-
-import org.cryptomator.common.LicenseHolder;
-import org.cryptomator.common.settings.Settings;
-import org.cryptomator.ui.common.FxController;
-import org.cryptomator.ui.fxapp.FxApplicationTerminator;
-import org.cryptomator.ui.fxapp.FxApplicationWindows;
-import org.cryptomator.ui.fxapp.UpdateChecker;
-import org.cryptomator.ui.preferences.SelectedPreferencesTab;
-import org.cryptomator.ui.traymenu.TrayMenuComponent;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.inject.Inject;
-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;
-
-@MainWindowScoped
-public class MainWindowTitleController implements FxController {
-
-	private static final Logger LOG = LoggerFactory.getLogger(MainWindowTitleController.class);
-
-	private final Stage window;
-	private final FxApplicationTerminator terminator;
-	private final FxApplicationWindows appWindows;
-	private final boolean trayMenuInitialized;
-	private final UpdateChecker updateChecker;
-	private final BooleanBinding updateAvailable;
-	private final LicenseHolder licenseHolder;
-	private final Settings settings;
-	private final BooleanBinding showMinimizeButton;
-
-	public HBox titleBar;
-	private double xOffset;
-	private double yOffset;
-
-	@Inject
-	MainWindowTitleController(@MainWindow Stage window, FxApplicationTerminator terminator, FxApplicationWindows appWindows, TrayMenuComponent trayMenu, UpdateChecker updateChecker, LicenseHolder licenseHolder, Settings settings) {
-		this.window = window;
-		this.terminator = terminator;
-		this.appWindows = appWindows;
-		this.trayMenuInitialized = trayMenu.isInitialized();
-		this.updateChecker = updateChecker;
-		this.updateAvailable = updateChecker.updateAvailableProperty();
-		this.licenseHolder = licenseHolder;
-		this.settings = settings;
-		this.showMinimizeButton = Bindings.createBooleanBinding(this::isShowMinimizeButton, settings.showMinimizeButton, settings.showTrayIcon);
-	}
-
-	@FXML
-	public void initialize() {
-		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) {
-				window.setFullScreen(!window.isFullScreen());
-			}
-		});
-		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.windowXPosition.setValue(window.getX());
-		settings.windowYPosition.setValue(window.getY());
-		settings.windowWidth.setValue(window.getWidth());
-		settings.windowHeight.setValue(window.getHeight());
-	}
-
-	@FXML
-	public void close() {
-		if (trayMenuInitialized) {
-			window.close();
-		} else {
-			terminator.terminate();
-		}
-	}
-
-	@FXML
-	public void minimize() {
-		window.setIconified(true);
-	}
-
-	@FXML
-	public void showPreferences() {
-		appWindows.showPreferencesWindow(SelectedPreferencesTab.ANY);
-	}
-
-	@FXML
-	public void showGeneralPreferences() {
-		appWindows.showPreferencesWindow(SelectedPreferencesTab.GENERAL);
-	}
-
-	@FXML
-	public void showContributePreferences() {
-		appWindows.showPreferencesWindow(SelectedPreferencesTab.CONTRIBUTE);
-	}
-
-	/* Getter/Setter */
-
-	public LicenseHolder getLicenseHolder() {
-		return licenseHolder;
-	}
-
-	public BooleanBinding updateAvailableProperty() {
-		return updateAvailable;
-	}
-
-	public boolean isUpdateAvailable() {
-		return updateAvailable.get();
-	}
-
-	public boolean isTrayIconPresent() {
-		return trayMenuInitialized;
-	}
-
-	public ReadOnlyBooleanProperty debugModeEnabledProperty() {
-		return settings.debugMode;
-	}
-
-	public boolean isDebugModeEnabled() {
-		return debugModeEnabledProperty().get();
-	}
-
-	public BooleanBinding showMinimizeButtonProperty() {
-		return showMinimizeButton;
-	}
-
-	public boolean isShowMinimizeButton() {
-		// always show the minimize button if no tray icon is present OR it is explicitly enabled
-		return !trayMenuInitialized || settings.showMinimizeButton.get();
-	}
-}

+ 0 - 194
src/main/java/org/cryptomator/ui/mainwindow/ResizeController.java

@@ -1,194 +0,0 @@
-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.BooleanBinding;
-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;
-import javafx.stage.WindowEvent;
-
-@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, Settings settings) {
-		this.window = window;
-		this.settings = settings;
-		this.showResizingArrows = window.fullScreenProperty().not();
-	}
-
-	@FXML
-	public void initialize() {
-		LOG.trace("init ResizeController");
-
-		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());
-		}
-
-		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 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 (isOutOfDisplayBounds()) {
-			// If the position is illegal, then the window appears on the main screen in the middle of the window.
-			LOG.debug("Resetting window position due to insufficient screen overlap");
-			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();
-		}
-	}
-
-	private boolean isOutOfDisplayBounds() {
-		// define a rect which is inset on all sides from the window's rect:
-		final double x = window.getX() + 20; // 20px left
-		final double y = window.getY() + 5; // 5px top
-		final double w = window.getWidth() - 40; // 20px left + 20px right
-		final double h = window.getHeight() - 25; // 5px top + 20px bottom
-		return isRectangleOutOfScreen(x, y, 0, h) // Left pixel column
-				|| isRectangleOutOfScreen(x + w, y, 0, h) // Right pixel column
-				|| isRectangleOutOfScreen(x, y, w, 0) // Top pixel row
-				|| isRectangleOutOfScreen(x, y + h, w, 0); // Bottom pixel row
-	}
-
-	private boolean isRectangleOutOfScreen(double x, double y, double width, double height) {
-		return Screen.getScreensForRectangle(x, y, width, height).isEmpty();
-	}
-
-	private void startResize(MouseEvent evt) {
-		origX = window.getX();
-		origY = window.getY();
-		origW = window.getWidth();
-		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;
-		if (newH < window.getMaxHeight() && newH > window.getMinHeight()) {
-			window.setY(newY);
-			window.setHeight(newH);
-		}
-	}
-
-	@FXML
-	private void resizeLeft(MouseEvent evt) {
-		startResize(evt);
-		double newX = evt.getScreenX();
-		double dx = newX - origX;
-		double newW = origW - dx;
-		if (newW < window.getMaxWidth() && newW > window.getMinWidth()) {
-			window.setX(newX);
-			window.setWidth(newW);
-		}
-	}
-
-	@FXML
-	private void resizeBottom(MouseEvent evt) {
-		double newH = evt.getSceneY();
-		if (newH < window.getMaxHeight() && newH > window.getMinHeight()) {
-			window.setHeight(newH);
-		}
-	}
-
-	@FXML
-	private void resizeRight(MouseEvent evt) {
-		double newW = evt.getSceneX();
-		if (newW < window.getMaxWidth() && newW > window.getMinWidth()) {
-			window.setWidth(newW);
-		}
-	}
-
-	@FXML
-	public void savePositionalSettings() {
-		settings.windowWidth.setValue(window.getWidth());
-		settings.windowHeight.setValue(window.getHeight());
-		settings.windowXPosition.setValue(window.getX());
-		settings.windowYPosition.setValue(window.getY());
-	}
-
-	public BooleanBinding showResizingArrowsProperty() {
-		return showResizingArrows;
-	}
-
-	public boolean isShowResizingArrows() {
-		return showResizingArrows.get();
-	}
-}

+ 12 - 1
src/main/java/org/cryptomator/ui/mainwindow/VaultListCellController.java

@@ -1,5 +1,6 @@
 package org.cryptomator.ui.mainwindow;
 
+import org.cryptomator.common.settings.Settings;
 import org.cryptomator.common.vaults.Vault;
 import org.cryptomator.common.vaults.VaultState;
 import org.cryptomator.ui.common.Animations;
@@ -18,6 +19,7 @@ public class VaultListCellController implements FxController {
 
 	private final ObjectProperty<Vault> vault = new SimpleObjectProperty<>();
 	private final ObservableValue<FontAwesome5Icon> glyph;
+	private final ObservableValue<Boolean> compactMode;
 
 	private AutoAnimator spinAnimation;
 
@@ -25,8 +27,9 @@ public class VaultListCellController implements FxController {
 	public FontAwesome5IconView vaultStateView;
 
 	@Inject
-	VaultListCellController() {
+	VaultListCellController(Settings settings) {
 		this.glyph = vault.flatMap(Vault::stateProperty).map(this::getGlyphForVaultState);
+		this.compactMode = settings.compactMode;
 	}
 
 	public void initialize() {
@@ -68,6 +71,14 @@ public class VaultListCellController implements FxController {
 		return vault.get();
 	}
 
+	public ObservableValue<Boolean> compactModeProperty() {
+		return compactMode;
+	}
+
+	public boolean getCompactMode() {
+		return compactMode.getValue();
+	}
+
 	public void setVault(Vault value) {
 		vault.set(value);
 	}

+ 23 - 5
src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java

@@ -1,6 +1,7 @@
 package org.cryptomator.ui.mainwindow;
 
 import org.apache.commons.lang3.SystemUtils;
+import org.cryptomator.common.settings.Settings;
 import org.cryptomator.common.vaults.Vault;
 import org.cryptomator.common.vaults.VaultListManager;
 import org.cryptomator.cryptofs.CryptoFileSystemProvider;
@@ -9,6 +10,7 @@ import org.cryptomator.ui.addvaultwizard.AddVaultWizardComponent;
 import org.cryptomator.ui.common.FxController;
 import org.cryptomator.ui.common.VaultService;
 import org.cryptomator.ui.fxapp.FxApplicationWindows;
+import org.cryptomator.ui.preferences.SelectedPreferencesTab;
 import org.cryptomator.ui.removevault.RemoveVaultComponent;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -24,7 +26,6 @@ import javafx.collections.ListChangeListener;
 import javafx.collections.ObservableList;
 import javafx.fxml.FXML;
 import javafx.geometry.Side;
-import javafx.scene.control.Button;
 import javafx.scene.control.ContextMenu;
 import javafx.scene.control.ListView;
 import javafx.scene.input.ContextMenuEvent;
@@ -33,6 +34,7 @@ import javafx.scene.input.KeyCode;
 import javafx.scene.input.KeyEvent;
 import javafx.scene.input.MouseEvent;
 import javafx.scene.input.TransferMode;
+import javafx.scene.layout.HBox;
 import javafx.scene.layout.StackPane;
 import javafx.stage.Stage;
 import java.io.File;
@@ -69,10 +71,11 @@ public class VaultListController implements FxController {
 	private final BooleanProperty draggingVaultOver = new SimpleBooleanProperty();
 	private final ResourceBundle resourceBundle;
 	private final FxApplicationWindows appWindows;
-
+	private final ObservableValue<Double> cellSize;
 	public ListView<Vault> vaultList;
 	public StackPane root;
-	public Button addVaultBtn;
+	@FXML
+	private HBox addVaultButton;
 	@FXML
 	private ContextMenu addVaultContextMenu;
 
@@ -86,7 +89,8 @@ public class VaultListController implements FxController {
 						RemoveVaultComponent.Builder removeVaultDialogue, //
 						VaultListManager vaultListManager, //
 						ResourceBundle resourceBundle, //
-						FxApplicationWindows appWindows) {
+						FxApplicationWindows appWindows, //
+						Settings settings) {
 		this.mainWindow = mainWindow;
 		this.vaults = vaults;
 		this.selectedVault = selectedVault;
@@ -101,11 +105,13 @@ public class VaultListController implements FxController {
 		this.emptyVaultList = Bindings.isEmpty(vaults);
 
 		selectedVault.addListener(this::selectedVaultDidChange);
+		cellSize = settings.compactMode.map(compact -> compact ? 30.0 : 60.0);
 	}
 
 	public void initialize() {
 		vaultList.setItems(vaults);
 		vaultList.setCellFactory(cellFactory);
+
 		selectedVault.bind(vaultList.getSelectionModel().selectedItemProperty());
 		vaults.addListener((ListChangeListener.Change<? extends Vault> c) -> {
 			while (c.next()) {
@@ -171,7 +177,7 @@ public class VaultListController implements FxController {
 		if (addVaultContextMenu.isShowing()) {
 			addVaultContextMenu.hide();
 		} else {
-			addVaultContextMenu.show(addVaultBtn, Side.BOTTOM, 0.0, 0.0);
+			addVaultContextMenu.show(addVaultButton, Side.BOTTOM, 0.0, 0.0);
 		}
 	}
 
@@ -247,6 +253,11 @@ public class VaultListController implements FxController {
 		}
 	}
 
+	@FXML
+	public void showPreferences() {
+		appWindows.showPreferencesWindow(SelectedPreferencesTab.ANY);
+	}
+
 	// Getter and Setter
 
 	public BooleanBinding emptyVaultListProperty() {
@@ -265,5 +276,12 @@ public class VaultListController implements FxController {
 		return draggingVaultOver.get();
 	}
 
+	public ObservableValue<Double> cellSizeProperty() {
+		return cellSize;
+	}
+
+	public Double getCellSize() {
+		return cellSize.getValue();
+	}
 
 }

+ 2 - 3
src/main/java/org/cryptomator/ui/preferences/InterfacePreferencesController.java

@@ -36,8 +36,8 @@ public class InterfacePreferencesController implements FxController {
 	private final ResourceBundle resourceBundle;
 	private final SupportedLanguages supportedLanguages;
 	public ChoiceBox<UiTheme> themeChoiceBox;
-	public CheckBox showMinimizeButtonCheckbox;
 	public CheckBox showTrayIconCheckbox;
+	public CheckBox compactModeCheckbox;
 	public ChoiceBox<String> preferredLanguageChoiceBox;
 	public ToggleGroup nodeOrientation;
 	public RadioButton nodeOrientationLtr;
@@ -63,9 +63,8 @@ public class InterfacePreferencesController implements FxController {
 		themeChoiceBox.valueProperty().bindBidirectional(settings.theme);
 		themeChoiceBox.setConverter(new UiThemeConverter(resourceBundle));
 
-		showMinimizeButtonCheckbox.selectedProperty().bindBidirectional(settings.showMinimizeButton);
-
 		showTrayIconCheckbox.selectedProperty().bindBidirectional(settings.showTrayIcon);
+		compactModeCheckbox.selectedProperty().bindBidirectional(settings.compactMode);
 
 		preferredLanguageChoiceBox.getItems().addAll(supportedLanguages.getLanguageTags());
 		preferredLanguageChoiceBox.valueProperty().bindBidirectional(settings.language);

+ 33 - 44
src/main/resources/css/dark_theme.css

@@ -181,31 +181,20 @@
 	-fx-border-width: 1px;
 }
 
-.main-window .title {
-	-fx-background-color: CONTROL_BORDER_NORMAL, TITLE_BG;
-	-fx-background-insets: 0, 0 0 1px 0;
-}
-
-.main-window .title .button {
-	-fx-pref-height: 30px;
-	-fx-pref-width: 30px;
-	-fx-background-color: none;
-	-fx-padding: 0;
-}
-
-.main-window .title .button .glyph-icon {
-	-fx-fill: white;
+.main-window .button-bar {
+	-fx-background-color: MAIN_BG;
+	-fx-border-color: CONTROL_BORDER_NORMAL transparent transparent transparent;
+	-fx-border-width: 1px 0 0 0;
 }
 
-.main-window .title .button:armed .glyph-icon {
-	-fx-fill: GRAY_8;
+.main-window .button-left {
+	-fx-border-color: CONTROL_BORDER_NORMAL;
+	-fx-border-width: 0 1px 0 0;
 }
 
-.main-window .update-indicator {
-	-fx-background-color: white, RED_5;
-	-fx-background-insets: 1px, 2px;
-	-fx-background-radius: 6px, 5px;
-	-fx-effect: dropshadow(three-pass-box, rgba(0, 0, 0, 0.8), 2, 0, 0, 0);
+.main-window .button-right {
+	-fx-border-color: CONTROL_BORDER_NORMAL;
+	-fx-border-width: 0 0 0 1px;
 }
 
 /*******************************************************************************
@@ -322,23 +311,33 @@
 	-fx-fill: transparent;
 }
 
-.button.toolbar-button {
-	-fx-min-height: 40px;
-	-fx-background-color: transparent;
-	-fx-background-insets: 0;
-	-fx-background-radius: 0;
-	-fx-border-color: CONTROL_BORDER_NORMAL transparent transparent transparent;
-	-fx-border-width: 1px 0 0 0;
-	-fx-padding: 0;
+/*******************************************************************************
+ *                                                                             *
+ * NotificationBar                                                             *
+ *                                                                             *
+ ******************************************************************************/
+
+.notification-label {
+	-fx-text-fill: white;
+	-fx-font-weight: bold;
 }
 
-.button.toolbar-button:focused {
-	-fx-background-color: CONTROL_BORDER_FOCUSED, MAIN_BG;
-	-fx-background-insets: 0, 2px 1px 1px 1px;
+.notification-debug {
+	-fx-min-height:24px;
+	-fx-max-height:24px;
+	-fx-background-color: RED_5;
 }
 
-.button.toolbar-button:armed {
-	-fx-background-color: CONTROL_BG_ARMED;
+.notification-update {
+	-fx-min-height:24px;
+	-fx-max-height:24px;
+	-fx-background-color: YELLOW_5;
+}
+
+.notification-support {
+	-fx-min-height:24px;
+	-fx-max-height:24px;
+	-fx-background-color: PRIMARY;
 }
 
 /*******************************************************************************
@@ -394,16 +393,6 @@
 	-fx-background-color: MUTED_BG;
 }
 
-/* Note: These values below are kinda random such that it looks ok. I'm pretty sure there is room for improvement. Additionally, fx-text-fill does not work*/
-.badge-debug {
-	-fx-font-family: 'Open Sans Bold';
-	-fx-font-size: 1.0em;
-	-fx-background-radius: 8px;
-	-fx-padding: 0.3em 0.55em 0.3em 0.55em;
-	-fx-background-color: RED_5;
-	-fx-background-radius: 2em;
-}
-
 /*******************************************************************************
  *                                                                             *
  * Password Strength Indicator                                                 *

+ 35 - 45
src/main/resources/css/light_theme.css

@@ -177,34 +177,24 @@
 
 /* windows needs an explicit border: */
 .main-window.os-windows {
-	-fx-border-color: TITLE_BG;
-	-fx-border-width: 1px;
-}
-
-.main-window .title {
-	-fx-background-color: TITLE_BG;
-}
-
-.main-window .title .button {
-	-fx-pref-height: 30px;
-	-fx-pref-width: 30px;
-	-fx-background-color: none;
-	-fx-padding: 0;
+	-fx-border-color: CONTROL_BORDER_NORMAL;
+	-fx-border-width: 1px 0 0 0;
 }
 
-.main-window .title .button .glyph-icon {
-	-fx-fill: white;
+.main-window .button-bar {
+	-fx-background-color: MAIN_BG;
+	-fx-border-color: CONTROL_BORDER_NORMAL transparent transparent transparent;
+	-fx-border-width: 1px 0 0 0;
 }
 
-.main-window .title .button:armed .glyph-icon {
-	-fx-fill: GRAY_8;
+.main-window .button-bar .button-left {
+	-fx-border-color: CONTROL_BORDER_NORMAL;
+	-fx-border-width: 0 1px 0 0;
 }
 
-.main-window .update-indicator {
-	-fx-background-color: white, RED_5;
-	-fx-background-insets: 1px, 2px;
-	-fx-background-radius: 6px, 5px;
-	-fx-effect: dropshadow(three-pass-box, rgba(0, 0, 0, 0.8), 2, 0, 0, 0);
+.main-window .button-bar .button-right {
+	-fx-border-color: CONTROL_BORDER_NORMAL;
+	-fx-border-width: 0 0 0 1px;
 }
 
 /*******************************************************************************
@@ -321,23 +311,33 @@
 	-fx-fill: transparent;
 }
 
-.button.toolbar-button {
-	-fx-min-height: 40px;
-	-fx-background-color: transparent;
-	-fx-background-insets: 0;
-	-fx-background-radius: 0;
-	-fx-border-color: CONTROL_BORDER_NORMAL transparent transparent transparent;
-	-fx-border-width: 1px 0 0 0;
-	-fx-padding: 0;
+/*******************************************************************************
+ *                                                                             *
+ * NotificationBar                                                             *
+ *                                                                             *
+ ******************************************************************************/
+
+.notification-label {
+	-fx-text-fill: white;
+	-fx-font-weight: bold;
 }
 
-.button.toolbar-button:focused {
-	-fx-background-color: CONTROL_BORDER_FOCUSED, MAIN_BG;
-	-fx-background-insets: 0, 2px 1px 1px 1px;
+.notification-debug {
+	-fx-min-height:24px;
+	-fx-max-height:24px;
+	-fx-background-color: RED_5;
 }
 
-.button.toolbar-button:armed {
-	-fx-background-color: CONTROL_BG_ARMED;
+.notification-update {
+	-fx-min-height:24px;
+	-fx-max-height:24px;
+	-fx-background-color: YELLOW_5;
+}
+
+.notification-support {
+	-fx-min-height:24px;
+	-fx-max-height:24px;
+	-fx-background-color: PRIMARY;
 }
 
 /*******************************************************************************
@@ -393,16 +393,6 @@
 	-fx-background-color: MUTED_BG;
 }
 
-/* Note: These values below are kinda random such that it looks ok. I'm pretty sure there is room for improvement. Additionally, fx-text-fill does not work*/
-.badge-debug {
-	-fx-font-family: 'Open Sans Bold';
-	-fx-font-size: 1.0em;
-	-fx-background-radius: 8px;
-	-fx-padding: 0.3em 0.55em 0.3em 0.55em;
-	-fx-background-color: RED_5;
-	-fx-background-radius: 2em;
-}
-
 /*******************************************************************************
  *                                                                             *
  * Password Strength Indicator                                                 *

+ 17 - 3
src/main/resources/fxml/main_window.fxml

@@ -3,17 +3,31 @@
 <?import javafx.scene.control.SplitPane?>
 <?import javafx.scene.layout.StackPane?>
 <?import javafx.scene.layout.VBox?>
+<?import org.cryptomator.ui.controls.NotificationBar?>
+
 <StackPane xmlns:fx="http://javafx.com/fxml"
 		   xmlns="http://javafx.com/javafx"
 		   fx:id="root"
 		   fx:controller="org.cryptomator.ui.mainwindow.MainWindowController"
 		   styleClass="main-window">
-	<VBox minWidth="650">
-		<fx:include source="main_window_title.fxml" VBox.vgrow="NEVER"/>
+	<VBox minWidth="600">
+		<NotificationBar onMouseClicked="#showUpdatePreferences"
+						 text="%main.notification.updateAvailable"
+						 dismissable="true"
+						 notify="${controller.updateAvailable}"
+						 styleClass="notification-update"/>
+		<NotificationBar onMouseClicked="#showContributePreferences"
+						 text="%main.notification.support"
+						 dismissable="true"
+						 notify="${!controller.licenseValid}"
+						 styleClass="notification-support"/>
 		<SplitPane dividerPositions="0.33" orientation="HORIZONTAL" VBox.vgrow="ALWAYS">
 			<fx:include source="vault_list.fxml" SplitPane.resizableWithParent="false"/>
 			<fx:include source="vault_detail.fxml" SplitPane.resizableWithParent="true"/>
 		</SplitPane>
+		<NotificationBar onMouseClicked="#showGeneralPreferences"
+						 text="DEBUG MODE"
+						 styleClass="notification-debug"
+						 notify="${controller.debugModeEnabled}"/>
 	</VBox>
-	<fx:include source="main_window_resize.fxml"/>
 </StackPane>

+ 0 - 30
src/main/resources/fxml/main_window_resize.fxml

@@ -1,30 +0,0 @@
-<?import javafx.scene.Cursor?>
-<?import javafx.scene.layout.AnchorPane?>
-<?import javafx.scene.layout.Region?>
-<AnchorPane xmlns:fx="http://javafx.com/fxml"
-			xmlns="http://javafx.com/javafx"
-			fx:controller="org.cryptomator.ui.mainwindow.ResizeController"
-			nodeOrientation="LEFT_TO_RIGHT"
-			pickOnBounds="false">
-	<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" 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>

+ 0 - 78
src/main/resources/fxml/main_window_title.fxml

@@ -1,78 +0,0 @@
-<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
-<?import javafx.geometry.Insets?>
-<?import javafx.scene.control.Button?>
-<?import javafx.scene.control.Hyperlink?>
-<?import javafx.scene.control.Label?>
-<?import javafx.scene.control.Tooltip?>
-<?import javafx.scene.layout.HBox?>
-<?import javafx.scene.layout.Region?>
-<?import javafx.scene.layout.StackPane?>
-<?import javafx.scene.image.Image?>
-<?import javafx.scene.image.ImageView?>
-<HBox xmlns:fx="http://javafx.com/fxml"
-	  xmlns="http://javafx.com/javafx"
-	  fx:id="titleBar"
-	  fx:controller="org.cryptomator.ui.mainwindow.MainWindowTitleController"
-	  styleClass="title"
-	  alignment="CENTER"
-	  minHeight="50"
-	  maxHeight="50"
-	  spacing="6">
-	<padding>
-		<Insets bottom="6" left="12" right="12" top="6"/>
-	</padding>
-	<children>
-		<ImageView HBox.hgrow="ALWAYS" fitHeight="14" preserveRatio="true" cache="true">
-			<Image url="@../img/title-logo.png"/>
-		</ImageView>
-
-		<Region HBox.hgrow="ALWAYS"/>
-
-		<Hyperlink onAction="#showGeneralPreferences" focusTraversable="false" visible="${controller.debugModeEnabled}" styleClass="badge-debug" text="DEBUG MODE" textFill="white">
-			<tooltip>
-				<Tooltip text="%main.debugModeEnabled.tooltip"/>
-			</tooltip>
-		</Hyperlink>
-
-		<Region HBox.hgrow="ALWAYS"/>
-
-		<Button contentDisplay="GRAPHIC_ONLY" mnemonicParsing="false" onAction="#showContributePreferences" focusTraversable="false" visible="${!controller.licenseHolder.validLicense}">
-			<graphic>
-				<StackPane>
-					<FontAwesome5IconView glyph="EXCLAMATION_CIRCLE" glyphSize="16"/>
-					<Region styleClass="update-indicator" StackPane.alignment="TOP_RIGHT" prefWidth="12" prefHeight="12" maxWidth="-Infinity" maxHeight="-Infinity"/>
-				</StackPane>
-			</graphic>
-			<tooltip>
-				<Tooltip text="%main.supporterCertificateMissing.tooltip"/>
-			</tooltip>
-		</Button>
-		<Button contentDisplay="GRAPHIC_ONLY" mnemonicParsing="false" onAction="#showPreferences" focusTraversable="false">
-			<graphic>
-				<StackPane>
-					<FontAwesome5IconView glyph="COGS" glyphSize="16"/>
-					<Region styleClass="update-indicator" visible="${controller.updateAvailable}" StackPane.alignment="TOP_RIGHT" prefWidth="12" prefHeight="12" maxWidth="-Infinity" maxHeight="-Infinity"/>
-				</StackPane>
-			</graphic>
-			<tooltip>
-				<Tooltip text="%main.preferencesBtn.tooltip"/>
-			</tooltip>
-		</Button>
-		<Button contentDisplay="GRAPHIC_ONLY" mnemonicParsing="false" onAction="#minimize" focusTraversable="false" visible="${controller.showMinimizeButton}" managed="${controller.showMinimizeButton}">
-			<graphic>
-				<FontAwesome5IconView glyph="WINDOW_MINIMIZE" glyphSize="12"/>
-			</graphic>
-			<tooltip>
-				<Tooltip text="%main.minimizeBtn.tooltip"/>
-			</tooltip>
-		</Button>
-		<Button contentDisplay="GRAPHIC_ONLY" mnemonicParsing="false" onAction="#close" focusTraversable="false">
-			<graphic>
-				<FontAwesome5IconView glyph="TIMES" glyphSize="16"/>
-			</graphic>
-			<tooltip>
-				<Tooltip text="%main.closeBtn.tooltip"/>
-			</tooltip>
-		</Button>
-	</children>
-</HBox>

+ 1 - 3
src/main/resources/fxml/preferences_interface.fxml

@@ -37,9 +37,7 @@
 			<RadioButton fx:id="nodeOrientationRtl" text="%preferences.interface.interfaceOrientation.rtl" alignment="CENTER_RIGHT" toggleGroup="${nodeOrientation}"/>
 		</HBox>
 
-
-		<CheckBox fx:id="showMinimizeButtonCheckbox" text="%preferences.interface.showMinimizeButton" visible="${controller.trayMenuInitialized}" managed="${controller.trayMenuInitialized}"/>
-
 		<CheckBox fx:id="showTrayIconCheckbox" text="%preferences.interface.showTrayIcon" visible="${controller.trayMenuSupported}" managed="${controller.trayMenuSupported}"/>
+		<CheckBox fx:id="compactModeCheckbox" text="%preferences.interface.compactMode"/>
 	</children>
 </VBox>

+ 38 - 25
src/main/resources/fxml/vault_list.fxml

@@ -1,15 +1,16 @@
 <?xml version="1.0" encoding="UTF-8"?>
 
 <?import org.cryptomator.ui.controls.FontAwesome5IconView?>
-<?import javafx.scene.control.Button?>
 <?import javafx.scene.control.Label?>
 <?import javafx.scene.control.ListView?>
 <?import javafx.scene.layout.Region?>
 <?import javafx.scene.layout.StackPane?>
 <?import javafx.scene.layout.VBox?>
-<?import javafx.scene.shape.Arc?>
 <?import javafx.scene.control.ContextMenu?>
 <?import javafx.scene.control.MenuItem?>
+<?import javafx.scene.layout.HBox?>
+<?import javafx.geometry.Insets?>
+<?import javafx.scene.shape.Arc?>
 <StackPane xmlns:fx="http://javafx.com/fxml"
 		   xmlns="http://javafx.com/javafx"
 		   fx:id="root"
@@ -17,7 +18,7 @@
 		   minWidth="206">
 	<VBox>
 		<StackPane VBox.vgrow="ALWAYS">
-			<ListView fx:id="vaultList" editable="true" fixedCellSize="60">
+			<ListView fx:id="vaultList" editable="true" fixedCellSize="${controller.cellSize}">
 				<contextMenu>
 					<fx:include source="vault_list_contextmenu.fxml"/>
 				</contextMenu>
@@ -25,30 +26,42 @@
 			<VBox visible="${controller.emptyVaultList}" spacing="6" alignment="CENTER">
 				<Region VBox.vgrow="ALWAYS"/>
 				<Label VBox.vgrow="NEVER" text="%main.vaultlist.emptyList.onboardingInstruction" textAlignment="CENTER" wrapText="true"/>
-				<Arc VBox.vgrow="NEVER" styleClass="onboarding-overlay-arc" type="OPEN" centerX="50" centerY="0" radiusY="100" radiusX="50" startAngle="0" length="-60" strokeWidth="1"/>
+				<HBox>
+					<Arc styleClass="onboarding-overlay-arc" translateX="20" radiusY="100" radiusX="50" length="-60"/>
+				</HBox>
 			</VBox>
 		</StackPane>
-		<Button fx:id="addVaultBtn" onAction="#toggleMenu" styleClass="toolbar-button" text="%main.vaultlist.addVaultBtn" alignment="BASELINE_CENTER" maxWidth="Infinity" contentDisplay="RIGHT">
-			<graphic>
-				<FontAwesome5IconView glyph="CARET_DOWN"/>
-			</graphic>
-		</Button>
-		<fx:define>
-			<ContextMenu fx:id="addVaultContextMenu">
-				<items>
-					<MenuItem styleClass="add-vault-menu-item" text="%main.vaultlist.addVaultBtn.menuItemNew" onAction="#didClickAddNewVault" >
-						<graphic>
-							<FontAwesome5IconView glyph="PLUS" textAlignment="CENTER" wrappingWidth="14" />
-						</graphic>
-					</MenuItem>
-					<MenuItem styleClass="add-vault-menu-item" text="%main.vaultlist.addVaultBtn.menuItemExisting" onAction="#didClickAddExistingVault" >
-						<graphic>
-							<FontAwesome5IconView glyph="FOLDER_OPEN" textAlignment="CENTER" wrappingWidth="14" />
-						</graphic>
-					</MenuItem>
-				</items>
-			</ContextMenu>
-		</fx:define>
+		<HBox styleClass="button-bar">
+			<HBox fx:id="addVaultButton" onMouseClicked="#toggleMenu" styleClass="button-left" alignment="CENTER" minWidth="20">
+				<padding>
+					<Insets topRightBottomLeft="12"/>
+				</padding>
+				<FontAwesome5IconView glyph="PLUS" HBox.hgrow="NEVER" glyphSize="16"/>
+			</HBox>
+			<Region HBox.hgrow="ALWAYS"/>
+			<HBox onMouseClicked="#showPreferences" styleClass="button-right" alignment="CENTER" minWidth="20">
+				<padding>
+					<Insets topRightBottomLeft="12"/>
+				</padding>
+				<FontAwesome5IconView glyph="COG" HBox.hgrow="NEVER" glyphSize="16"/>
+			</HBox>
+		</HBox>
 	</VBox>
 	<Region styleClass="drag-n-drop-border" visible="${controller.draggingVaultOver}"/>
+	<fx:define>
+		<ContextMenu fx:id="addVaultContextMenu">
+			<items>
+				<MenuItem styleClass="add-vault-menu-item" text="%main.vaultlist.addVaultBtn.menuItemNew" onAction="#didClickAddNewVault" >
+					<graphic>
+						<FontAwesome5IconView glyph="PLUS" textAlignment="CENTER" wrappingWidth="14" />
+					</graphic>
+				</MenuItem>
+				<MenuItem styleClass="add-vault-menu-item" text="%main.vaultlist.addVaultBtn.menuItemExisting" onAction="#didClickAddExistingVault" >
+					<graphic>
+						<FontAwesome5IconView glyph="FOLDER_OPEN" textAlignment="CENTER" wrappingWidth="14" />
+					</graphic>
+				</MenuItem>
+			</items>
+		</ContextMenu>
+	</fx:define>
 </StackPane>

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

@@ -23,7 +23,7 @@
 		</VBox>
 		<VBox spacing="4" HBox.hgrow="ALWAYS">
 			<Label styleClass="header-label" text="${controller.vault.displayName}"/>
-			<Label styleClass="detail-label" text="${controller.vault.displayablePath}" textOverrun="CENTER_ELLIPSIS">
+			<Label styleClass="detail-label" text="${controller.vault.displayablePath}" textOverrun="CENTER_ELLIPSIS" visible="${!controller.compactMode}" managed="${!controller.compactMode}">
 				<tooltip>
 					<Tooltip text="${controller.vault.displayablePath}"/>
 				</tooltip>

+ 6 - 9
src/main/resources/i18n/strings.properties

@@ -301,8 +301,8 @@ preferences.interface.language.auto=System Default
 preferences.interface.interfaceOrientation=Interface Orientation
 preferences.interface.interfaceOrientation.ltr=Left to Right
 preferences.interface.interfaceOrientation.rtl=Right to Left
-preferences.interface.showMinimizeButton=Show minimize button
 preferences.interface.showTrayIcon=Show tray icon (requires restart)
+preferences.interface.compactMode=Enable compact vault list
 ## Volume
 preferences.volume=Virtual Drive
 preferences.volume.type=Default Volume Type
@@ -377,11 +377,6 @@ stats.access.total=Total accesses: %d
 
 
 # Main Window
-main.closeBtn.tooltip=Close
-main.minimizeBtn.tooltip=Minimize
-main.preferencesBtn.tooltip=Preferences
-main.debugModeEnabled.tooltip=Debug mode is enabled
-main.supporterCertificateMissing.tooltip=Please consider donating
 ## Vault List
 main.vaultlist.emptyList.onboardingInstruction=Click here to add a vault
 main.vaultlist.contextMenu.remove=Remove…
@@ -390,9 +385,11 @@ 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
-main.vaultlist.addVaultBtn.menuItemNew=New Vault...
-main.vaultlist.addVaultBtn.menuItemExisting=Existing Vault...
+main.vaultlist.addVaultBtn.menuItemNew=Create New Vault...
+main.vaultlist.addVaultBtn.menuItemExisting=Open Existing Vault...
+##Notificaition
+main.notification.updateAvailable=Update is available.
+main.notification.support=Support Cryptomator.
 ## 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: