diff --git a/src/main/java/org/cryptomator/ui/addvaultwizard/AddVaultWizardComponent.java b/src/main/java/org/cryptomator/ui/addvaultwizard/AddVaultWizardComponent.java index c67f999e8..cd68bf254 100644 --- a/src/main/java/org/cryptomator/ui/addvaultwizard/AddVaultWizardComponent.java +++ b/src/main/java/org/cryptomator/ui/addvaultwizard/AddVaultWizardComponent.java @@ -7,13 +7,28 @@ package org.cryptomator.ui.addvaultwizard; import dagger.Lazy; import dagger.Subcomponent; +import org.cryptomator.common.recovery.RecoveryActionType; +import org.cryptomator.common.vaults.Vault; +import org.cryptomator.common.vaults.VaultComponent; +import org.cryptomator.common.vaults.VaultListManager; +import org.cryptomator.common.vaults.VaultState; +import org.cryptomator.integrations.mount.MountService; import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlScene; +import org.cryptomator.ui.dialogs.Dialogs; +import org.cryptomator.ui.recoverykey.RecoveryKeyComponent; +import javafx.beans.property.SimpleObjectProperty; import javafx.scene.Scene; +import javafx.stage.DirectoryChooser; import javafx.stage.Stage; +import javafx.stage.Window; +import java.io.File; +import java.util.List; import java.util.ResourceBundle; +import static org.cryptomator.ui.addvaultwizard.ChooseExistingVaultController.prepareVault; + @AddVaultWizardScoped @Subcomponent(modules = {AddVaultModule.class}) public interface AddVaultWizardComponent { @@ -23,9 +38,13 @@ public interface AddVaultWizardComponent { @FxmlScene(FxmlFile.ADDVAULT_NEW_NAME) Lazy sceneNew(); + @FxmlScene(FxmlFile.ADDVAULT_EXISTING) Lazy sceneExisting(); + @FxmlScene(FxmlFile.ADDVAULT_SUCCESS) + Lazy sceneSuccess(); + default void showAddNewVaultWizard(ResourceBundle resourceBundle) { Stage stage = window(); stage.setScene(sceneNew().get()); @@ -42,6 +61,50 @@ public interface AddVaultWizardComponent { stage.show(); } + default void showRecoverExistingVaultWizard(Window mainWindow, // + Dialogs dialogs, // + VaultComponent.Factory vaultComponentFactory, // + List mountServices, // + VaultListManager vaultListManager, // + RecoveryKeyComponent.Factory recoveryKeyWindow) { + Stage stage = window(); + DirectoryChooser directoryChooser = new DirectoryChooser(); + + while (true) { + File selectedDirectory = directoryChooser.showDialog(mainWindow); + if (selectedDirectory == null) { + return; + } + + boolean hasSubfolderD = new File(selectedDirectory, "d").isDirectory(); + if (!hasSubfolderD) { + dialogs.prepareNoDDirectorySelectedDialog(stage).build().showAndWait(); + continue; + } + + Vault preparedVault = prepareVault(selectedDirectory, vaultComponentFactory, mountServices); + + if (!vaultListManager.containsVault(preparedVault.getPath())) { + vaultListManager.addVault(preparedVault); + dialogs.prepareRecoveryVaultAdded(stage).setOkAction(Stage::close).build().showAndWait(); + } + + VaultListManager.redetermineVaultState(preparedVault); + VaultState.Value state = preparedVault.getState(); + + switch (state) { + case VAULT_CONFIG_MISSING -> recoveryKeyWindow.create(preparedVault, stage, new SimpleObjectProperty<>(RecoveryActionType.RESTORE_VAULT_CONFIG)) // + .showOnboardingDialogWindow(); + case ALL_MISSING -> recoveryKeyWindow.create(preparedVault, stage, new SimpleObjectProperty<>(RecoveryActionType.RESTORE_ALL)) // + .showOnboardingDialogWindow(); + default -> dialogs.prepareRecoveryVaultAlreadyExists(stage)// + .setOkAction(Stage::close)// + .build().showAndWait(); + } + break; + } + } + @Subcomponent.Builder interface Builder { diff --git a/src/main/java/org/cryptomator/ui/addvaultwizard/ChooseExistingVaultController.java b/src/main/java/org/cryptomator/ui/addvaultwizard/ChooseExistingVaultController.java index 490b08303..e89184510 100644 --- a/src/main/java/org/cryptomator/ui/addvaultwizard/ChooseExistingVaultController.java +++ b/src/main/java/org/cryptomator/ui/addvaultwizard/ChooseExistingVaultController.java @@ -1,16 +1,30 @@ package org.cryptomator.ui.addvaultwizard; +import dagger.Lazy; +import org.apache.commons.lang3.SystemUtils; +import org.cryptomator.common.settings.VaultSettings; +import org.cryptomator.common.vaults.Vault; +import org.cryptomator.common.vaults.VaultComponent; +import org.cryptomator.common.vaults.VaultConfigCache; +import org.cryptomator.common.vaults.VaultListManager; +import org.cryptomator.integrations.mount.MountService; +import org.cryptomator.integrations.uiappearance.Theme; +import org.cryptomator.ui.common.FxController; +import org.cryptomator.ui.common.FxmlFile; +import org.cryptomator.ui.common.FxmlScene; +import org.cryptomator.ui.fxapp.FxApplicationStyle; +import org.cryptomator.ui.fxapp.FxApplicationWindows; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import javax.inject.Inject; import javafx.beans.property.BooleanProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ObservableValue; import javafx.fxml.FXML; import javafx.scene.Scene; -import javafx.scene.control.CheckBox; import javafx.scene.image.Image; -import javafx.stage.DirectoryChooser; import javafx.stage.FileChooser; import javafx.stage.Stage; import java.io.File; @@ -23,27 +37,6 @@ import java.util.ResourceBundle; import static org.cryptomator.common.Constants.CRYPTOMATOR_FILENAME_GLOB; import static org.cryptomator.common.vaults.VaultState.Value.LOCKED; -import dagger.Lazy; -import org.apache.commons.lang3.SystemUtils; -import org.cryptomator.common.recovery.RecoveryActionType; -import org.cryptomator.common.settings.VaultSettings; -import org.cryptomator.common.vaults.Vault; -import org.cryptomator.common.vaults.VaultComponent; -import org.cryptomator.common.vaults.VaultConfigCache; -import org.cryptomator.common.vaults.VaultListManager; -import org.cryptomator.common.vaults.VaultState; -import org.cryptomator.integrations.mount.MountService; -import org.cryptomator.integrations.uiappearance.Theme; -import org.cryptomator.ui.common.FxController; -import org.cryptomator.ui.common.FxmlFile; -import org.cryptomator.ui.common.FxmlScene; -import org.cryptomator.ui.dialogs.Dialogs; -import org.cryptomator.ui.fxapp.FxApplicationStyle; -import org.cryptomator.ui.fxapp.FxApplicationWindows; -import org.cryptomator.ui.recoverykey.RecoveryKeyComponent; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - @AddVaultWizardScoped public class ChooseExistingVaultController implements FxController { @@ -57,13 +50,6 @@ public class ChooseExistingVaultController implements FxController { private final VaultListManager vaultListManager; private final ResourceBundle resourceBundle; private final ObservableValue screenshot; - private final Dialogs dialogs; - private final VaultComponent.Factory vaultComponentFactory; - private final RecoveryKeyComponent.Factory recoveryKeyWindow; - private final List mountServices; - - @FXML - private CheckBox restoreCheckBox; private final BooleanProperty restoreButtonVisible = new SimpleBooleanProperty(false); @@ -76,11 +62,7 @@ public class ChooseExistingVaultController implements FxController { @AddVaultWizardWindow ObjectProperty vault, // VaultListManager vaultListManager, // ResourceBundle resourceBundle, // - FxApplicationStyle applicationStyle, // - RecoveryKeyComponent.Factory recoveryKeyWindow, // - VaultComponent.Factory vaultComponentFactory, // - List mountServices, // - Dialogs dialogs) { + FxApplicationStyle applicationStyle) { this.window = window; this.successScene = successScene; this.appWindows = appWindows; @@ -89,14 +71,6 @@ public class ChooseExistingVaultController implements FxController { this.vaultListManager = vaultListManager; this.resourceBundle = resourceBundle; this.screenshot = applicationStyle.appliedThemeProperty().map(this::selectScreenshot); - this.recoveryKeyWindow = recoveryKeyWindow; - this.vaultComponentFactory = vaultComponentFactory; - this.mountServices = mountServices; - this.dialogs = dialogs; - } - - public void initialize() { - restoreButtonVisible.bind(restoreCheckBox.selectedProperty()); } private Image selectScreenshot(Theme theme) { @@ -131,35 +105,6 @@ public class ChooseExistingVaultController implements FxController { } } - @FXML - public void restoreVaultConfigWithRecoveryKey() { - DirectoryChooser directoryChooser = new DirectoryChooser(); - - File selectedDirectory = directoryChooser.showDialog(window); - if (selectedDirectory == null) { - return; - } - - boolean hasSubfolderD = new File(selectedDirectory, "d").isDirectory(); - if (!hasSubfolderD) { - dialogs.prepareNoDDirectorySelectedDialog(window).build().showAndWait(); - return; - } - - Vault preparedVault = prepareVault(selectedDirectory, vaultComponentFactory, mountServices); - VaultListManager.redetermineVaultState(preparedVault); - VaultState.Value state = preparedVault.getState(); - switch (state) { - case VAULT_CONFIG_MISSING -> recoveryKeyWindow.create(preparedVault, window, new SimpleObjectProperty<>(RecoveryActionType.RESTORE_VAULT_CONFIG)).showOnboardingDialogWindow(); - case ALL_MISSING -> recoveryKeyWindow.create(preparedVault, window, new SimpleObjectProperty<>(RecoveryActionType.RESTORE_ALL)).showOnboardingDialogWindow(); - default -> { - vaultListManager.addVault(preparedVault); - vault.set(preparedVault); - window.setScene(successScene.get()); - } - } - } - public static Vault prepareVault(File selectedDirectory, VaultComponent.Factory vaultComponentFactory, List mountServices) { Path selectedPath = selectedDirectory.toPath(); VaultSettings vaultSettings = VaultSettings.withRandomId(); diff --git a/src/main/java/org/cryptomator/ui/controls/FontAwesome5Icon.java b/src/main/java/org/cryptomator/ui/controls/FontAwesome5Icon.java index 348b3a26b..2c7f385fd 100644 --- a/src/main/java/org/cryptomator/ui/controls/FontAwesome5Icon.java +++ b/src/main/java/org/cryptomator/ui/controls/FontAwesome5Icon.java @@ -6,6 +6,7 @@ package org.cryptomator.ui.controls; public enum FontAwesome5Icon { ANCHOR("\uF13D"), // ARROW_UP("\uF062"), // + ARROWS_ROTATE("\uF021"), BAN("\uF05E"), // BELL("\uF0F3"), // BUG("\uF188"), // diff --git a/src/main/java/org/cryptomator/ui/dialogs/Dialogs.java b/src/main/java/org/cryptomator/ui/dialogs/Dialogs.java index a22a81a09..6e5d91ecd 100644 --- a/src/main/java/org/cryptomator/ui/dialogs/Dialogs.java +++ b/src/main/java/org/cryptomator/ui/dialogs/Dialogs.java @@ -58,6 +58,23 @@ public class Dialogs { .setOkButtonKey(BUTTON_KEY_CLOSE); } + public SimpleDialog.Builder prepareRecoveryVaultAdded(Stage window) { + return createDialogBuilder().setOwner(window) // + .setTitleKey("recoveryKey.recoverExisting.title") // + .setMessageKey("recoveryKey.recoverExisting.message") // + .setDescriptionKey("recoveryKey.recoverExisting.description") // + .setIcon(FontAwesome5Icon.EXCLAMATION)// + .setOkButtonKey(BUTTON_KEY_CLOSE); + } + public SimpleDialog.Builder prepareRecoveryVaultAlreadyExists(Stage window) { + return createDialogBuilder().setOwner(window) // + .setTitleKey("recoveryKey.alreadyExists.title") // + .setMessageKey("recoveryKey.alreadyExists.message") // + .setDescriptionKey("recoveryKey.alreadyExists.description") // + .setIcon(FontAwesome5Icon.EXCLAMATION)// + .setOkButtonKey(BUTTON_KEY_CLOSE); + } + public SimpleDialog.Builder prepareRecoverPasswordSuccess(Stage window, Stage owner, ResourceBundle resourceBundle) { return createDialogBuilder() .setOwner(window) // @@ -67,7 +84,8 @@ public class Dialogs { .setIcon(FontAwesome5Icon.CHECK) .setOkAction(stage -> { stage.close(); - if (owner.getTitle().equals(resourceBundle.getString("addvaultwizard.existing.title"))) { + String ownerTitle = owner.getTitle(); + if (ownerTitle != null && ownerTitle.equals(resourceBundle.getString("addvaultwizard.existing.title"))) { owner.close(); } }) diff --git a/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java b/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java index a457ade3f..2c95da688 100644 --- a/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java +++ b/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java @@ -3,9 +3,11 @@ 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.VaultComponent; import org.cryptomator.common.vaults.VaultListManager; import org.cryptomator.cryptofs.CryptoFileSystemProvider; import org.cryptomator.cryptofs.DirStructure; +import org.cryptomator.integrations.mount.MountService; import org.cryptomator.ui.addvaultwizard.AddVaultWizardComponent; import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.common.VaultService; @@ -13,6 +15,7 @@ import org.cryptomator.ui.dialogs.Dialogs; import org.cryptomator.ui.fxapp.FxFSEventList; import org.cryptomator.ui.fxapp.FxApplicationWindows; import org.cryptomator.ui.preferences.SelectedPreferencesTab; +import org.cryptomator.ui.recoverykey.RecoveryKeyComponent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,6 +45,7 @@ import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.util.EnumSet; +import java.util.List; import java.util.Optional; import java.util.ResourceBundle; import java.util.Set; @@ -75,6 +79,10 @@ public class VaultListController implements FxController { private final ObservableValue cellSize; private final Dialogs dialogs; + private final VaultComponent.Factory vaultComponentFactory; + private final RecoveryKeyComponent.Factory recoveryKeyWindow; + private final List mountServices; + public ListView vaultList; public StackPane root; @FXML @@ -94,6 +102,9 @@ public class VaultListController implements FxController { FxApplicationWindows appWindows, // Settings settings, // Dialogs dialogs, // + RecoveryKeyComponent.Factory recoveryKeyWindow, // + VaultComponent.Factory vaultComponentFactory, // + List mountServices, // FxFSEventList fxFSEventList) { this.mainWindow = mainWindow; this.vaults = vaults; @@ -105,6 +116,9 @@ public class VaultListController implements FxController { this.resourceBundle = resourceBundle; this.appWindows = appWindows; this.dialogs = dialogs; + this.recoveryKeyWindow = recoveryKeyWindow; + this.vaultComponentFactory = vaultComponentFactory; + this.mountServices = mountServices; this.emptyVaultList = Bindings.isEmpty(vaults); this.unreadEvents = fxFSEventList.unreadEventsProperty(); @@ -214,6 +228,11 @@ public class VaultListController implements FxController { addVaultWizard.build().showAddExistingVaultWizard(resourceBundle); } + @FXML + public void didClickRecoverExistingVault() { + addVaultWizard.build().showRecoverExistingVaultWizard(mainWindow, dialogs, vaultComponentFactory,mountServices,vaultListManager,recoveryKeyWindow); + } + private void pressedShortcutToRemoveVault() { final var vault = selectedVault.get(); if (vault != null && EnumSet.of(LOCKED, MISSING, ERROR, NEEDS_MIGRATION).contains(vault.getState())) { diff --git a/src/main/resources/fxml/addvault_existing.fxml b/src/main/resources/fxml/addvault_existing.fxml index 5cc7fc4b6..cfbeb2018 100644 --- a/src/main/resources/fxml/addvault_existing.fxml +++ b/src/main/resources/fxml/addvault_existing.fxml @@ -3,7 +3,6 @@ - @@ -12,25 +11,21 @@ xmlns="http://javafx.com/javafx" fx:controller="org.cryptomator.ui.addvaultwizard.ChooseExistingVaultController" prefWidth="450" - prefHeight="480"> + prefHeight="450" + spacing="24" + alignment="CENTER"> - +