diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java index 16a6de8fb..5db9b8d70 100644 --- a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java +++ b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java @@ -35,6 +35,7 @@ public class VaultSettings { public static final boolean DEFAULT_USES_READONLY_MODE = false; public static final String DEFAULT_MOUNT_FLAGS = ""; public static final int DEFAULT_FILENAME_LENGTH_LIMIT = -1; + public static final WhenUnlocked DEFAULT_ACTION_AFTER_UNLOCK = WhenUnlocked.ASK; private static final Random RNG = new Random(); @@ -49,6 +50,7 @@ public class VaultSettings { private final BooleanProperty usesReadOnlyMode = new SimpleBooleanProperty(DEFAULT_USES_READONLY_MODE); private final StringProperty mountFlags = new SimpleStringProperty(DEFAULT_MOUNT_FLAGS); private final IntegerProperty filenameLengthLimit = new SimpleIntegerProperty(DEFAULT_FILENAME_LENGTH_LIMIT); + private final ObjectProperty actionAfterUnlock = new SimpleObjectProperty<>(DEFAULT_ACTION_AFTER_UNLOCK); public VaultSettings(String id) { this.id = Objects.requireNonNull(id); @@ -57,7 +59,7 @@ public class VaultSettings { } Observable[] observables() { - return new Observable[]{path, mountName, winDriveLetter, unlockAfterStartup, revealAfterMount, usesIndividualMountPath, individualMountPath, usesReadOnlyMode, mountFlags, filenameLengthLimit}; + return new Observable[]{path, mountName, winDriveLetter, unlockAfterStartup, revealAfterMount, useCustomMountPath, customMountPath, usesReadOnlyMode, mountFlags, filenameLengthLimit, actionAfterUnlock}; } private void deriveMountNameFromPath(Path path) { @@ -149,6 +151,14 @@ public class VaultSettings { return filenameLengthLimit; } + public ObjectProperty actionAfterUnlock() { + return actionAfterUnlock; + } + + public WhenUnlocked getActionAfterUnlock() { + return actionAfterUnlock.get(); + } + /* Hashcode/Equals */ @Override diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java index a26781bb9..980bfd355 100644 --- a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java +++ b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java @@ -30,6 +30,7 @@ class VaultSettingsJsonAdapter { out.name("usesReadOnlyMode").value(value.usesReadOnlyMode().get()); out.name("mountFlags").value(value.mountFlags().get()); out.name("filenameLengthLimit").value(value.filenameLengthLimit().get()); + out.name("actionAfterUnlock").value(value.actionAfterUnlock().get().name()); out.endObject(); } @@ -45,6 +46,7 @@ class VaultSettingsJsonAdapter { boolean usesReadOnlyMode = VaultSettings.DEFAULT_USES_READONLY_MODE; String mountFlags = VaultSettings.DEFAULT_MOUNT_FLAGS; int filenameLengthLimit = VaultSettings.DEFAULT_FILENAME_LENGTH_LIMIT; + WhenUnlocked actionAfterUnlock = VaultSettings.DEFAULT_ACTION_AFTER_UNLOCK; in.beginObject(); while (in.hasNext()) { @@ -85,6 +87,9 @@ class VaultSettingsJsonAdapter { case "filenameLengthLimit": filenameLengthLimit = in.nextInt(); break; + case "actionAfterUnlock": + actionAfterUnlock = parseActionAfterUnlock(in.nextString()); + break; default: LOG.warn("Unsupported vault setting found in JSON: " + name); in.skipValue(); @@ -104,7 +109,17 @@ class VaultSettingsJsonAdapter { vaultSettings.usesReadOnlyMode().set(usesReadOnlyMode); vaultSettings.mountFlags().set(mountFlags); vaultSettings.filenameLengthLimit().set(filenameLengthLimit); + vaultSettings.actionAfterUnlock().set(actionAfterUnlock); return vaultSettings; } + private WhenUnlocked parseActionAfterUnlock(String actionAfterUnlockName) { + try { + return WhenUnlocked.valueOf(actionAfterUnlockName.toUpperCase()); + } catch (IllegalArgumentException e) { + LOG.warn("Invalid action after unlock {}. Defaulting to {}.", actionAfterUnlockName, VaultSettings.DEFAULT_ACTION_AFTER_UNLOCK); + return VaultSettings.DEFAULT_ACTION_AFTER_UNLOCK; + } + } + } diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/WhenUnlocked.java b/main/commons/src/main/java/org/cryptomator/common/settings/WhenUnlocked.java new file mode 100644 index 000000000..fe023222c --- /dev/null +++ b/main/commons/src/main/java/org/cryptomator/common/settings/WhenUnlocked.java @@ -0,0 +1,17 @@ +package org.cryptomator.common.settings; + +public enum WhenUnlocked { + IGNORE("vaultOptions.general.actionAfterUnlock.ignore"), + REVEAL("vaultOptions.general.actionAfterUnlock.reveal"), + ASK("vaultOptions.general.actionAfterUnlock.ask"); + + private String displayName; + + WhenUnlocked(String displayName) { + this.displayName = displayName; + } + + public String getDisplayName() { + return displayName; + } +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockSuccessController.java b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockSuccessController.java index cf61ab2e7..bf0d2e3fb 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockSuccessController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockSuccessController.java @@ -7,8 +7,10 @@ import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.concurrent.Task; import javafx.fxml.FXML; +import javafx.scene.control.CheckBox; import javafx.scene.control.ContentDisplay; import javafx.stage.Stage; +import org.cryptomator.common.settings.WhenUnlocked; import org.cryptomator.common.vaults.Vault; import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.common.VaultService; @@ -29,6 +31,8 @@ public class UnlockSuccessController implements FxController { private final VaultService vaultService; private final ObjectProperty revealButtonState; private final BooleanProperty revealButtonDisabled; + + public CheckBox rememberChoiceCheckbox; @Inject public UnlockSuccessController(@UnlockWindow Stage window, @UnlockWindow Vault vault, ExecutorService executor, VaultService vaultService) { @@ -44,6 +48,9 @@ public class UnlockSuccessController implements FxController { public void close() { LOG.trace("UnlockSuccessController.close()"); window.close(); + if (rememberChoiceCheckbox.isSelected()) { + vault.getVaultSettings().actionAfterUnlock().setValue(WhenUnlocked.IGNORE); + } } @FXML @@ -64,6 +71,9 @@ public class UnlockSuccessController implements FxController { revealButtonDisabled.set(false); }); executor.execute(revealTask); + if (rememberChoiceCheckbox.isSelected()) { + vault.getVaultSettings().actionAfterUnlock().setValue(WhenUnlocked.REVEAL); + } } /* Getter/Setter */ diff --git a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java index 3828a1c24..c0642e810 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java +++ b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java @@ -5,6 +5,7 @@ import javafx.application.Platform; import javafx.concurrent.Task; import javafx.scene.Scene; import javafx.stage.Stage; +import org.cryptomator.common.settings.WhenUnlocked; import org.cryptomator.common.vaults.Vault; import org.cryptomator.common.vaults.VaultState; import org.cryptomator.common.vaults.Volume; @@ -121,9 +122,12 @@ public class UnlockWorkflow extends Task { if (savePassword.get()) { savePasswordToSystemkeychain(); } - Platform.runLater(() -> { - window.setScene(successScene.get()); // TODO only if enabled (see issue #1083) - }); + if (vault.getVaultSettings().actionAfterUnlock().get() == WhenUnlocked.ASK) { + Platform.runLater(() -> { + window.setScene(successScene.get()); + window.show(); + }); + } } private void savePasswordToSystemkeychain() { diff --git a/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/GeneralVaultOptionsController.java b/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/GeneralVaultOptionsController.java index 2507997c9..ddb6e0553 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/GeneralVaultOptionsController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/GeneralVaultOptionsController.java @@ -2,24 +2,56 @@ package org.cryptomator.ui.vaultoptions; import javafx.fxml.FXML; import javafx.scene.control.CheckBox; +import javafx.scene.control.ChoiceBox; +import javafx.util.StringConverter; +import org.cryptomator.common.settings.UiTheme; +import org.cryptomator.common.settings.WhenUnlocked; import org.cryptomator.common.vaults.Vault; import org.cryptomator.ui.common.FxController; import javax.inject.Inject; +import java.util.ResourceBundle; @VaultOptionsScoped public class GeneralVaultOptionsController implements FxController { private final Vault vault; + private final ResourceBundle resourceBundle; + public CheckBox unlockOnStartupCheckbox; + public ChoiceBox actionAfterUnlockChoiceBox; @Inject - GeneralVaultOptionsController(@VaultOptionsWindow Vault vault) { + GeneralVaultOptionsController(@VaultOptionsWindow Vault vault, ResourceBundle resourceBundle) { this.vault = vault; + this.resourceBundle = resourceBundle; } @FXML public void initialize() { unlockOnStartupCheckbox.selectedProperty().bindBidirectional(vault.getVaultSettings().unlockAfterStartup()); + actionAfterUnlockChoiceBox.getItems().addAll(WhenUnlocked.values()); + actionAfterUnlockChoiceBox.valueProperty().bindBidirectional(vault.getVaultSettings().actionAfterUnlock()); + actionAfterUnlockChoiceBox.setConverter(new WhenUnlockedConverter(resourceBundle)); } + + private static class WhenUnlockedConverter extends StringConverter { + + private final ResourceBundle resourceBundle; + + public WhenUnlockedConverter(ResourceBundle resourceBundle) { + this.resourceBundle = resourceBundle; + } + + @Override + public String toString(WhenUnlocked obj) { + return resourceBundle.getString(obj.getDisplayName()); + } + + @Override + public WhenUnlocked fromString(String string) { + throw new UnsupportedOperationException(); + } + } + } diff --git a/main/ui/src/main/resources/fxml/unlock_success.fxml b/main/ui/src/main/resources/fxml/unlock_success.fxml index 8b52cbd2e..8fb568d70 100644 --- a/main/ui/src/main/resources/fxml/unlock_success.fxml +++ b/main/ui/src/main/resources/fxml/unlock_success.fxml @@ -10,6 +10,7 @@ + - + + + + diff --git a/main/ui/src/main/resources/fxml/vault_options_general.fxml b/main/ui/src/main/resources/fxml/vault_options_general.fxml index 9628df53d..f6c3c680c 100644 --- a/main/ui/src/main/resources/fxml/vault_options_general.fxml +++ b/main/ui/src/main/resources/fxml/vault_options_general.fxml @@ -3,6 +3,9 @@ + + + + + + diff --git a/main/ui/src/main/resources/i18n/strings.properties b/main/ui/src/main/resources/i18n/strings.properties index 10599e2a2..2fb761cd2 100644 --- a/main/ui/src/main/resources/i18n/strings.properties +++ b/main/ui/src/main/resources/i18n/strings.properties @@ -96,6 +96,7 @@ unlock.savePassword=Save Password unlock.unlockBtn=Unlock ## Success unlock.success.message=Unlocked "%s" successfully! Your vault is now accessible. +unlock.success.rememberChoice=Remember choice, don't show this again unlock.success.revealBtn=Reveal Vault ## Invalid Mount Point unlock.error.invalidMountPoint=Mount point is not an empty directory: %s @@ -206,6 +207,10 @@ wrongFileAlert.link=For further assistance, visit ## General vaultOptions.general=General vaultOptions.general.unlockAfterStartup=Unlock vault when starting Cryptomator +vaultOptions.general.actionAfterUnlock=After successful unlock +vaultOptions.general.actionAfterUnlock.ignore=Do nothing +vaultOptions.general.actionAfterUnlock.reveal=Reveal Drive +vaultOptions.general.actionAfterUnlock.ask=Ask ## Mount vaultOptions.mount=Mounting vaultOptions.mount.readonly=Read-Only