瀏覽代碼

Refactored adding vaults

Sebastian Stenzel 5 年之前
父節點
當前提交
2bbc3e5834

+ 3 - 12
main/commons/src/main/java/org/cryptomator/common/CommonsModule.java

@@ -10,16 +10,13 @@ import dagger.Module;
 import dagger.Provides;
 import javafx.beans.binding.Binding;
 import javafx.beans.binding.Bindings;
-import javafx.collections.FXCollections;
 import javafx.collections.ObservableList;
 import org.apache.commons.lang3.SystemUtils;
 import org.cryptomator.common.settings.Settings;
 import org.cryptomator.common.settings.SettingsProvider;
-import org.cryptomator.common.settings.VaultSettings;
 import org.cryptomator.common.vaults.Vault;
 import org.cryptomator.common.vaults.VaultComponent;
-import org.cryptomator.common.vaults.VaultFactory;
-import org.cryptomator.common.vaults.VaultListChangeListener;
+import org.cryptomator.common.vaults.VaultListManager;
 import org.cryptomator.frontend.webdav.WebDavServer;
 import org.fxmisc.easybind.EasyBind;
 
@@ -53,14 +50,8 @@ public abstract class CommonsModule {
 
 	@Provides
 	@Singleton
-	static ObservableList<Vault> provideVaultList(Settings settings, VaultFactory vaultFactory) {
-		ObservableList<Vault> list = FXCollections.observableArrayList(Vault::observables);
-		for (VaultSettings s : settings.getDirectories()) {
-			Vault v = vaultFactory.get(s);
-			list.add(v);
-		}
-		list.addListener(new VaultListChangeListener(settings.getDirectories()));
-		return list;
+	static ObservableList<Vault> provideVaultList(VaultListManager vaultListManager) {
+		return vaultListManager.getVaultList();
 	}
 
 	@Provides

+ 1 - 1
main/commons/src/main/java/org/cryptomator/common/vaults/VaultListChangeListener.java

@@ -10,7 +10,7 @@ import java.util.stream.Collectors;
 /**
  * This listener makes sure to reflect any changes to the vault list back to the settings.
  */
-public class VaultListChangeListener implements ListChangeListener<Vault> {
+class VaultListChangeListener implements ListChangeListener<Vault> {
 
 	private final ObservableList<VaultSettings> vaultSettingsList;
 

+ 41 - 7
main/commons/src/main/java/org/cryptomator/common/vaults/VaultFactory.java

@@ -8,6 +8,9 @@
  *******************************************************************************/
 package org.cryptomator.common.vaults;
 
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import org.cryptomator.common.settings.Settings;
 import org.cryptomator.common.settings.VaultSettings;
 import org.cryptomator.cryptofs.CryptoFileSystemProvider;
 import org.cryptomator.cryptofs.migration.Migrators;
@@ -15,25 +18,56 @@ import org.cryptomator.cryptofs.migration.Migrators;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 import java.io.IOException;
+import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
+import java.util.Collection;
+import java.util.Optional;
+import java.util.stream.Collectors;
 
 @Singleton
-public class VaultFactory {
+public class VaultListManager {
 	
 	private static final String MASTERKEY_FILENAME = "masterkey.cryptomator"; // TODO: deduplicate constant declared in multiple classes
 
 	private final VaultComponent.Builder vaultComponentBuilder;
-	private final ConcurrentMap<VaultSettings, Vault> vaults = new ConcurrentHashMap<>();
+	private final ObservableList<Vault> vaultList;
 
 	@Inject
-	public VaultFactory(VaultComponent.Builder vaultComponentBuilder) {
+	public VaultListManager(VaultComponent.Builder vaultComponentBuilder, Settings settings) {
 		this.vaultComponentBuilder = vaultComponentBuilder;
+		this.vaultList = FXCollections.observableArrayList(Vault::observables);
+		
+		addAll(settings.getDirectories());
+		vaultList.addListener(new VaultListChangeListener(settings.getDirectories()));
 	}
 
-	public Vault get(VaultSettings vaultSettings) {
-		return vaults.computeIfAbsent(vaultSettings, this::create);
+	public ObservableList<Vault> getVaultList() {
+		return vaultList;
+	}
+
+	public Vault add(Path pathToVault) throws NoSuchFileException {
+		if (!CryptoFileSystemProvider.containsVault(pathToVault, MASTERKEY_FILENAME)) {
+			throw new NoSuchFileException(pathToVault.toString(), null, "Not a vault directory");
+		}
+		Optional<Vault> alreadyExistingVault = get(pathToVault);
+		if (alreadyExistingVault.isPresent()) {
+			return alreadyExistingVault.get();
+		} else {
+			VaultSettings vaultSettings = VaultSettings.withRandomId();
+			vaultSettings.path().set(pathToVault);
+			Vault newVault = create(vaultSettings);
+			vaultList.add(newVault);
+			return newVault;
+		}
+	}
+	
+	private void addAll(Collection<VaultSettings> vaultSettings) {
+		Collection<Vault> vaults = vaultSettings.stream().map(this::create).collect(Collectors.toList());
+		vaultList.addAll(vaults);
+	}
+	
+	private Optional<Vault> get(Path vaultPath) {
+		return vaultList.stream().filter(v -> v.getPath().equals(vaultPath)).findAny();
 	}
 
 	private Vault create(VaultSettings vaultSettings) {

+ 18 - 16
main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/ChooseExistingVaultController.java

@@ -2,44 +2,45 @@ package org.cryptomator.ui.addvaultwizard;
 
 import dagger.Lazy;
 import javafx.beans.property.ObjectProperty;
-import javafx.collections.ObservableList;
 import javafx.fxml.FXML;
 import javafx.scene.Scene;
 import javafx.stage.FileChooser;
 import javafx.stage.Stage;
-import org.cryptomator.common.settings.VaultSettings;
 import org.cryptomator.common.vaults.Vault;
-import org.cryptomator.common.vaults.VaultFactory;
+import org.cryptomator.common.vaults.VaultListManager;
 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 java.io.File;
+import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.util.ResourceBundle;
 
 @AddVaultWizardScoped
 public class ChooseExistingVaultController implements FxController {
 
+	private static final Logger LOG = LoggerFactory.getLogger(ChooseExistingVaultController.class);
+
 	private final Stage window;
 	private final Lazy<Scene> welcomeScene;
 	private final Lazy<Scene> successScene;
 	private final ObjectProperty<Path> vaultPath;
-	private final ObservableList<Vault> vaults;
 	private final ObjectProperty<Vault> vault;
-	private final VaultFactory vaultFactory;
+	private final VaultListManager vaultListManager;
 	private final ResourceBundle resourceBundle;
 
 	@Inject
-	ChooseExistingVaultController(@AddVaultWizard Stage window, @FxmlScene(FxmlFile.ADDVAULT_WELCOME) Lazy<Scene> welcomeScene, @FxmlScene(FxmlFile.ADDVAULT_SUCCESS) Lazy<Scene> successScene, ObjectProperty<Path> vaultPath, ObservableList<Vault> vaults, @AddVaultWizard ObjectProperty<Vault> vault, VaultFactory vaultFactory, ResourceBundle resourceBundle) {
+	ChooseExistingVaultController(@AddVaultWizard Stage window, @FxmlScene(FxmlFile.ADDVAULT_WELCOME) Lazy<Scene> welcomeScene, @FxmlScene(FxmlFile.ADDVAULT_SUCCESS) Lazy<Scene> successScene, ObjectProperty<Path> vaultPath, @AddVaultWizard ObjectProperty<Vault> vault, VaultListManager vaultListManager, ResourceBundle resourceBundle) {
 		this.window = window;
 		this.welcomeScene = welcomeScene;
 		this.successScene = successScene;
 		this.vaultPath = vaultPath;
-		this.vaults = vaults;
 		this.vault = vault;
-		this.vaultFactory = vaultFactory;
+		this.vaultListManager = vaultListManager;
 		this.resourceBundle = resourceBundle;
 	}
 
@@ -54,16 +55,17 @@ public class ChooseExistingVaultController implements FxController {
 		FileChooser fileChooser = new FileChooser();
 		fileChooser.setTitle(resourceBundle.getString("addvaultwizard.existing.filePickerTitle"));
 		fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Cryptomator Masterkey", "*.cryptomator"));
-		final File file = fileChooser.showOpenDialog(window);
+		File file = fileChooser.showOpenDialog(window);
 		if (file != null) {
 			vaultPath.setValue(file.toPath().toAbsolutePath().getParent());
-			VaultSettings vaultSettings = VaultSettings.withRandomId();
-			vaultSettings.path().setValue(vaultPath.get());
-			Vault newVault = vaultFactory.get(vaultSettings);
-			vaults.add(newVault);
-			vault.set(newVault);
-			//TODO: error handling?
-			window.setScene(successScene.get());
+			try {
+				Vault newVault = vaultListManager.add(vaultPath.get());
+				vault.set(newVault);
+				window.setScene(successScene.get());
+			} catch (NoSuchFileException e) {
+				LOG.error("Nope", e);
+				// TODO
+			}
 		}
 	}
 

+ 21 - 16
main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultPasswordController.java

@@ -10,7 +10,6 @@ import javafx.beans.property.ObjectProperty;
 import javafx.beans.property.SimpleBooleanProperty;
 import javafx.beans.property.SimpleIntegerProperty;
 import javafx.beans.property.StringProperty;
-import javafx.collections.ObservableList;
 import javafx.fxml.FXML;
 import javafx.scene.Scene;
 import javafx.scene.control.CheckBox;
@@ -18,9 +17,8 @@ import javafx.scene.control.ContentDisplay;
 import javafx.scene.control.Label;
 import javafx.scene.layout.HBox;
 import javafx.stage.Stage;
-import org.cryptomator.common.settings.VaultSettings;
 import org.cryptomator.common.vaults.Vault;
-import org.cryptomator.common.vaults.VaultFactory;
+import org.cryptomator.common.vaults.VaultListManager;
 import org.cryptomator.cryptofs.CryptoFileSystemProperties;
 import org.cryptomator.cryptofs.CryptoFileSystemProvider;
 import org.cryptomator.ui.common.FxController;
@@ -36,10 +34,12 @@ import org.slf4j.LoggerFactory;
 
 import javax.inject.Inject;
 import java.io.IOException;
+import java.io.UncheckedIOException;
 import java.nio.channels.WritableByteChannel;
 import java.nio.file.FileAlreadyExistsException;
 import java.nio.file.FileSystem;
 import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.nio.file.StandardOpenOption;
 import java.util.Collections;
@@ -60,9 +60,8 @@ public class CreateNewVaultPasswordController implements FxController {
 	private final ExecutorService executor;
 	private final StringProperty vaultName;
 	private final ObjectProperty<Path> vaultPath;
-	private final ObservableList<Vault> vaults;
 	private final ObjectProperty<Vault> vault;
-	private final VaultFactory vaultFactory;
+	private final VaultListManager vaultListManager;
 	private final ResourceBundle resourceBundle;
 	private final PasswordStrengthUtil strengthRater;
 	private final ReadmeGenerator readmeGenerator;
@@ -81,16 +80,15 @@ public class CreateNewVaultPasswordController implements FxController {
 	public CheckBox finalConfirmationCheckbox;
 
 	@Inject
-	CreateNewVaultPasswordController(@AddVaultWizard Stage window, @FxmlScene(FxmlFile.ADDVAULT_NEW_LOCATION) Lazy<Scene> chooseLocationScene, @FxmlScene(FxmlFile.ADDVAULT_SUCCESS) Lazy<Scene> successScene, ExecutorService executor, StringProperty vaultName, ObjectProperty<Path> vaultPath, ObservableList<Vault> vaults, @AddVaultWizard ObjectProperty<Vault> vault, VaultFactory vaultFactory, ResourceBundle resourceBundle, PasswordStrengthUtil strengthRater, ReadmeGenerator readmeGenerator) {
+	CreateNewVaultPasswordController(@AddVaultWizard Stage window, @FxmlScene(FxmlFile.ADDVAULT_NEW_LOCATION) Lazy<Scene> chooseLocationScene, @FxmlScene(FxmlFile.ADDVAULT_SUCCESS) Lazy<Scene> successScene, ExecutorService executor, StringProperty vaultName, ObjectProperty<Path> vaultPath, @AddVaultWizard ObjectProperty<Vault> vault, VaultListManager vaultListManager, ResourceBundle resourceBundle, PasswordStrengthUtil strengthRater, ReadmeGenerator readmeGenerator) {
 		this.window = window;
 		this.chooseLocationScene = chooseLocationScene;
 		this.successScene = successScene;
 		this.executor = executor;
 		this.vaultName = vaultName;
 		this.vaultPath = vaultPath;
-		this.vaults = vaults;
 		this.vault = vault;
-		this.vaultFactory = vaultFactory;
+		this.vaultListManager = vaultListManager;
 		this.resourceBundle = resourceBundle;
 		this.strengthRater = strengthRater;
 		this.readmeGenerator = readmeGenerator;
@@ -127,8 +125,10 @@ public class CreateNewVaultPasswordController implements FxController {
 
 	@FXML
 	public void next() {
+		Path pathToVault = vaultPath.get();
+		
 		try {
-			Files.createDirectory(vaultPath.get());
+			Files.createDirectory(pathToVault);
 		} catch (FileAlreadyExistsException e) {
 			LOG.error("Vault dir already exists.", e);
 			window.setScene(chooseLocationScene.get());
@@ -139,14 +139,9 @@ public class CreateNewVaultPasswordController implements FxController {
 
 		processing.set(true);
 		Tasks.create(() -> {
-			initializeVault(vaultPath.get(), passwordField.getCharacters());
+			initializeVault(pathToVault, passwordField.getCharacters());
 		}).onSuccess(() -> {
-			VaultSettings vaultSettings = VaultSettings.withRandomId();
-			vaultSettings.path().setValue(vaultPath.get());
-			Vault newVault = vaultFactory.get(vaultSettings);
-			vault.set(newVault);
-			vaults.add(newVault);
-			window.setScene(successScene.get());
+			initializationSucceeded(pathToVault);
 		}).onError(IOException.class, e -> {
 			// TODO show generic error screen
 			LOG.error("", e);
@@ -175,6 +170,16 @@ public class CreateNewVaultPasswordController implements FxController {
 		}
 		LOG.info("Created vault at {}", path);
 	}
+	
+	private void initializationSucceeded(Path pathToVault) {
+		try {
+			Vault newVault = vaultListManager.add(pathToVault);
+			vault.set(newVault);
+			window.setScene(successScene.get());
+		} catch (NoSuchFileException e) {
+			throw new UncheckedIOException(e);
+		}
+	}
 
 	/* Getter/Setter */
 

+ 10 - 7
main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java

@@ -46,14 +46,13 @@ import javafx.util.Duration;
 import org.apache.commons.lang3.SystemUtils;
 import org.cryptomator.common.vaults.VaultState;
 import org.cryptomator.ui.fxapp.FxApplicationScoped;
-import org.cryptomator.common.settings.VaultSettings;
 import org.cryptomator.ui.ExitUtil;
 import org.cryptomator.ui.controls.DirectoryListCell;
 import org.cryptomator.ui.l10n.Localization;
 import org.cryptomator.ui.launcher.AppLaunchEvent;
 import org.cryptomator.ui.model.AutoUnlocker;
 import org.cryptomator.common.vaults.Vault;
-import org.cryptomator.common.vaults.VaultFactory;
+import org.cryptomator.common.vaults.VaultListManager;
 import org.cryptomator.ui.model.upgrade.UpgradeStrategies;
 import org.cryptomator.ui.model.upgrade.UpgradeStrategy;
 import org.cryptomator.ui.util.DialogBuilderUtil;
@@ -70,7 +69,9 @@ import java.awt.Desktop;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.UncheckedIOException;
 import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.util.HashMap;
 import java.util.List;
@@ -94,7 +95,7 @@ public class MainController implements ViewController {
 	private final Localization localization;
 	private final ExecutorService executorService;
 	private final BlockingQueue<AppLaunchEvent> launchEventQueue;
-	private final VaultFactory vaultFactoy;
+	private final VaultListManager vaultFactoy;
 	private final ViewControllerLoader viewControllerLoader;
 	private final ObjectProperty<ViewController> activeController = new SimpleObjectProperty<>();
 	private final ObservableList<Vault> vaults;
@@ -111,7 +112,7 @@ public class MainController implements ViewController {
 
 	@Inject
 	public MainController(@Named("mainWindow") Stage mainWindow, ExecutorService executorService, @Named("launchEventQueue") BlockingQueue<AppLaunchEvent> launchEventQueue, ExitUtil exitUtil, Localization localization,
-						  VaultFactory vaultFactoy, ViewControllerLoader viewControllerLoader, UpgradeStrategies upgradeStrategies, ObservableList<Vault> vaults, AutoUnlocker autoUnlocker) {
+						  VaultListManager vaultFactoy, ViewControllerLoader viewControllerLoader, UpgradeStrategies upgradeStrategies, ObservableList<Vault> vaults, AutoUnlocker autoUnlocker) {
 		this.mainWindow = mainWindow;
 		this.executorService = executorService;
 		this.launchEventQueue = launchEventQueue;
@@ -344,9 +345,11 @@ public class MainController implements ViewController {
 		}
 
 		final Vault vault = vaults.stream().filter(v -> v.getPath().equals(vaultPath)).findAny().orElseGet(() -> {
-			VaultSettings vaultSettings = VaultSettings.withRandomId();
-			vaultSettings.path().set(vaultPath);
-			return vaultFactoy.get(vaultSettings);
+			try {
+				return vaultFactoy.add(vaultPath);
+			} catch (NoSuchFileException e) {
+				throw new UncheckedIOException(e);
+			}
 		});
 
 		if (!vaults.contains(vault)) {

+ 16 - 15
main/ui/src/main/java/org/cryptomator/ui/launcher/AppLaunchEventHandler.java

@@ -1,10 +1,7 @@
 package org.cryptomator.ui.launcher;
 
 import javafx.application.Platform;
-import javafx.collections.ObservableList;
-import org.cryptomator.common.settings.VaultSettings;
-import org.cryptomator.common.vaults.Vault;
-import org.cryptomator.common.vaults.VaultFactory;
+import org.cryptomator.common.vaults.VaultListManager;
 import org.cryptomator.ui.fxapp.FxApplication;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -12,6 +9,7 @@ import org.slf4j.LoggerFactory;
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
+import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.ExecutorService;
@@ -20,20 +18,19 @@ import java.util.concurrent.ExecutorService;
 class AppLaunchEventHandler {
 
 	private static final Logger LOG = LoggerFactory.getLogger(AppLaunchEventHandler.class);
+	private static final String MASTERKEY_FILENAME = "masterkey.cryptomator"; // TODO: deduplicate constant declared in multiple classes
 
 	private final BlockingQueue<AppLaunchEvent> launchEventQueue;
 	private final ExecutorService executorService;
 	private final FxApplicationStarter fxApplicationStarter;
-	private final VaultFactory vaultFactory;
-	private final ObservableList<Vault> vaults;
+	private final VaultListManager vaultListManager;
 
 	@Inject
-	public AppLaunchEventHandler(@Named("launchEventQueue") BlockingQueue<AppLaunchEvent> launchEventQueue, ExecutorService executorService, FxApplicationStarter fxApplicationStarter, VaultFactory vaultFactory, ObservableList<Vault> vaults) {
+	public AppLaunchEventHandler(@Named("launchEventQueue") BlockingQueue<AppLaunchEvent> launchEventQueue, ExecutorService executorService, FxApplicationStarter fxApplicationStarter, VaultListManager vaultListManager) {
 		this.launchEventQueue = launchEventQueue;
 		this.executorService = executorService;
 		this.fxApplicationStarter = fxApplicationStarter;
-		this.vaultFactory = vaultFactory;
-		this.vaults = vaults;
+		this.vaultListManager = vaultListManager;
 	}
 
 	public void startHandlingLaunchEvents(boolean hasTrayIcon) {
@@ -73,12 +70,16 @@ class AppLaunchEventHandler {
 	// TODO dedup MainWindowController...
 	private void addVault(Path potentialVaultPath) {
 		assert Platform.isFxApplicationThread();
-		// TODO CryptoFileSystemProvider.containsVault(potentialVaultPath, "masterkey.cryptomator");
-		VaultSettings settings = VaultSettings.withRandomId();
-		settings.path().set(potentialVaultPath);
-		Vault vault = vaultFactory.get(settings);
-		vaults.add(vault);
-		LOG.debug("Added vault {}", potentialVaultPath);
+		try {
+			if (potentialVaultPath.getFileName().toString().equals(MASTERKEY_FILENAME)) {
+				vaultListManager.add(potentialVaultPath.getParent());
+			} else {
+				vaultListManager.add(potentialVaultPath);
+			}
+			LOG.debug("Added vault {}", potentialVaultPath);
+		} catch (NoSuchFileException e) {
+			LOG.error("Failed to add vault " + potentialVaultPath, e);
+		}
 	}
 
 }

+ 19 - 26
main/ui/src/main/java/org/cryptomator/ui/mainwindow/MainWindowController.java

@@ -1,7 +1,6 @@
 package org.cryptomator.ui.mainwindow;
 
 import javafx.beans.binding.BooleanBinding;
-import javafx.collections.ObservableList;
 import javafx.fxml.FXML;
 import javafx.scene.input.TransferMode;
 import javafx.scene.layout.HBox;
@@ -9,9 +8,8 @@ import javafx.scene.layout.Pane;
 import javafx.scene.layout.Region;
 import javafx.scene.layout.VBox;
 import javafx.stage.Stage;
-import org.cryptomator.common.settings.VaultSettings;
 import org.cryptomator.common.vaults.Vault;
-import org.cryptomator.common.vaults.VaultFactory;
+import org.cryptomator.common.vaults.VaultListManager;
 import org.cryptomator.ui.common.FontLoader;
 import org.cryptomator.ui.common.FxController;
 import org.cryptomator.ui.fxapp.FxApplication;
@@ -24,23 +22,26 @@ import javax.inject.Inject;
 import javax.inject.Named;
 import java.io.File;
 import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.util.Collection;
+import java.util.Optional;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 @MainWindowScoped
 public class MainWindowController implements FxController {
 
 	private static final String TITLE_FONT = "/css/dosis-bold.ttf";
 	private static final Logger LOG = LoggerFactory.getLogger(MainWindowController.class);
+	private static final String MASTERKEY_FILENAME = "masterkey.cryptomator"; // TODO: deduplicate constant declared in multiple classes
 
 	private final Stage window;
 	private final FxApplication application;
 	private final boolean minimizeToSysTray;
 	private final UpdateChecker updateChecker;
 	private final BooleanBinding updateAvailable;
-	private final ObservableList<Vault> vaults;
-	private final VaultFactory vaultFactory;
+	private final VaultListManager vaultListManager;
 	private final WrongFileAlertComponent.Builder wrongFileAlert;
 	public HBox titleBar;
 	public VBox root;
@@ -50,14 +51,13 @@ public class MainWindowController implements FxController {
 	private double yOffset;
 
 	@Inject
-	public MainWindowController(@MainWindow Stage window, FxApplication application, @Named("trayMenuSupported") boolean minimizeToSysTray, UpdateChecker updateChecker, ObservableList<Vault> vaults, VaultFactory vaultFactory, WrongFileAlertComponent.Builder wrongFileAlert) {
+	public MainWindowController(@MainWindow Stage window, FxApplication application, @Named("trayMenuSupported") boolean minimizeToSysTray, UpdateChecker updateChecker, VaultListManager vaultListManager, WrongFileAlertComponent.Builder wrongFileAlert) {
 		this.window = window;
 		this.application = application;
 		this.minimizeToSysTray = minimizeToSysTray;
 		this.updateChecker = updateChecker;
 		this.updateAvailable = updateChecker.latestVersionProperty().isNotNull();
-		this.vaults = vaults;
-		this.vaultFactory = vaultFactory;
+		this.vaultListManager = vaultListManager;
 		this.wrongFileAlert = wrongFileAlert;
 	}
 
@@ -93,33 +93,26 @@ public class MainWindowController implements FxController {
 			if (event.getGestureSource() != root && event.getDragboard().hasFiles()) {
 				/* allow for both copying and moving, whatever user chooses */
 				event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
-				Collection<Path> vaultPaths = event.getDragboard().getFiles().stream().map(File::toPath).filter(this::isVaultPath).collect(Collectors.toSet());
+				Collection<Vault> vaultPaths = event.getDragboard().getFiles().stream().map(File::toPath).flatMap(this::addVault).collect(Collectors.toSet());
 				if (vaultPaths.isEmpty()) {
 					wrongFileAlert.build().showWrongFileAlertWindow();
-				} else {
-					vaultPaths.forEach(this::addVault);
 				}
 			}
 			event.consume();
 		});
 	}
 
-	private boolean isVaultPath(Path path) {
-		if (path.getFileName().toString().endsWith(".cryptomator")) {
-			return true;
-		} else if (Files.exists(path.resolve("masterkey.cryptomator"))) {
-			return true;
-		} else {
-			return false;
+	private Stream<Vault> addVault(Path pathToVault) {
+		try {
+			if (pathToVault.getFileName().toString().equals(MASTERKEY_FILENAME)) {
+				return Stream.of(vaultListManager.add(pathToVault.getParent()));
+			} else {
+				return Stream.of(vaultListManager.add(pathToVault));
+			}
+		} catch (NoSuchFileException e) {
+			LOG.debug("Not a vault: {}", pathToVault);
 		}
-	}
-
-	private void addVault(Path pathToVault) {
-		VaultSettings vaultSettings = VaultSettings.withRandomId();
-		vaultSettings.path().setValue(pathToVault);
-		Vault newVault = vaultFactory.get(vaultSettings);
-		vaults.add(newVault);
-		//TODO: error handling?
+		return Stream.empty();
 	}
 
 	private void loadFont(String resourcePath) {

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

@@ -56,7 +56,7 @@ public class VaultListController implements FxController {
 					window.setIconified(false);
 					window.show();
 					window.toFront();
-					window.requestFocus();
+					window.requestFocus(); // TODO: this beeps on macOS if there is a modal child window...
 				}
 			}
 		});