diff --git a/main/ui/src/main/java/org/cryptomator/ui/common/FxmlFile.java b/main/ui/src/main/java/org/cryptomator/ui/common/FxmlFile.java index 2e5cd3bf5..d7c52ee3b 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/common/FxmlFile.java +++ b/main/ui/src/main/java/org/cryptomator/ui/common/FxmlFile.java @@ -6,6 +6,7 @@ public enum FxmlFile { ADDVAULT_EXISTING("/fxml/addvault_existing.fxml"), // PREFERENCES("/fxml/preferences.fxml"), // UNLOCK("/fxml/unlock2.fxml"), // TODO rename + UNLOCK_SUCCESS("/fxml/unlock_success.fxml"), ; private final String filename; diff --git a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java index 8d6ec7fb3..2918981d3 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java @@ -1,21 +1,28 @@ package org.cryptomator.ui.unlock; +import dagger.Lazy; import javafx.beans.binding.Bindings; import javafx.beans.binding.ObjectBinding; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.ReadOnlyBooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; import javafx.fxml.FXML; +import javafx.scene.Scene; import javafx.scene.control.Alert; import javafx.scene.control.ButtonType; import javafx.scene.control.CheckBox; import javafx.scene.control.ContentDisplay; import javafx.stage.Stage; import org.apache.commons.lang3.SystemUtils; +import org.cryptomator.common.vaults.Vault; import org.cryptomator.cryptolib.api.InvalidPassphraseException; import org.cryptomator.cryptolib.api.UnsupportedVaultFormatException; import org.cryptomator.keychain.KeychainAccess; import org.cryptomator.ui.common.FxController; +import org.cryptomator.ui.common.FxmlFile; +import org.cryptomator.ui.common.FxmlScene; import org.cryptomator.ui.common.Tasks; import org.cryptomator.ui.controls.SecPasswordField; -import org.cryptomator.common.vaults.Vault; import org.cryptomator.ui.util.DialogBuilderUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,17 +46,21 @@ public class UnlockController implements FxController { private final ObjectBinding unlockButtonState; private final Optional keychainAccess; private final ResourceBundle resourceBundle; + private final Lazy successScene; + private final BooleanProperty unlockButtonDisabled; public SecPasswordField passwordField; public CheckBox savePassword; @Inject - public UnlockController(@UnlockWindow Stage window, @UnlockWindow Vault vault, ExecutorService executor, Optional keychainAccess, ResourceBundle resourceBundle) { + public UnlockController(@UnlockWindow Stage window, @UnlockWindow Vault vault, ExecutorService executor, Optional keychainAccess, ResourceBundle resourceBundle, @FxmlScene(FxmlFile.UNLOCK_SUCCESS) Lazy successScene) { this.window = window; this.vault = vault; this.executor = executor; this.unlockButtonState = Bindings.createObjectBinding(this::getUnlockButtonState, vault.stateProperty()); this.keychainAccess = keychainAccess; this.resourceBundle = resourceBundle; + this.successScene = successScene; + this.unlockButtonDisabled = new SimpleBooleanProperty(); } public void initialize() { @@ -58,6 +69,7 @@ public class UnlockController implements FxController { } else { savePassword.setDisable(true); } + unlockButtonDisabled.bind(vault.stateProperty().isNotEqualTo(Vault.State.LOCKED).or(passwordField.textProperty().isEmpty())); } @FXML @@ -68,6 +80,7 @@ public class UnlockController implements FxController { @FXML public void unlock() { + LOG.trace("UnlockController.unlock()"); CharSequence password = passwordField.getCharacters(); vault.setState(Vault.State.PROCESSING); Tasks.create(() -> { @@ -79,7 +92,7 @@ public class UnlockController implements FxController { vault.setState(Vault.State.UNLOCKED); passwordField.swipe(); LOG.info("Unlock of '{}' succeeded.", vault.getDisplayableName()); - window.close(); + window.setScene(successScene.get()); }).onError(InvalidPassphraseException.class, e -> { passwordField.selectAll(); passwordField.requestFocus(); @@ -160,4 +173,12 @@ public class UnlockController implements FxController { return ContentDisplay.TEXT_ONLY; } } + + public ReadOnlyBooleanProperty unlockButtonDisabledProperty() { + return unlockButtonDisabled; + } + + public boolean isUnlockButtonDisabled() { + return unlockButtonDisabled.get(); + } } diff --git a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java index 473023940..3521fe054 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java @@ -44,7 +44,15 @@ abstract class UnlockModule { static Scene provideUnlockScene(@UnlockWindow FXMLLoaderFactory fxmlLoaders) { return fxmlLoaders.createScene("/fxml/unlock2.fxml"); // TODO rename fxml file } - + + @Provides + @FxmlScene(FxmlFile.UNLOCK_SUCCESS) + @UnlockScoped + static Scene provideUnlockSuccessScene(@UnlockWindow FXMLLoaderFactory fxmlLoaders) { + return fxmlLoaders.createScene("/fxml/unlock_success.fxml"); + } + + // ------------------ @Binds @@ -52,5 +60,10 @@ abstract class UnlockModule { @FxControllerKey(UnlockController.class) abstract FxController bindUnlockController(UnlockController controller); + @Binds + @IntoMap + @FxControllerKey(UnlockSuccessController.class) + abstract FxController bindUnlockSuccessController(UnlockSuccessController controller); + } 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 new file mode 100644 index 000000000..b2c80dece --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockSuccessController.java @@ -0,0 +1,71 @@ +package org.cryptomator.ui.unlock; + +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.ReadOnlyObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.scene.control.ContentDisplay; +import javafx.stage.Stage; +import org.cryptomator.common.vaults.Vault; +import org.cryptomator.cryptolib.api.InvalidPassphraseException; +import org.cryptomator.ui.common.FxController; +import org.cryptomator.ui.common.Tasks; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; +import java.util.concurrent.ExecutorService; + +@UnlockScoped +public class UnlockSuccessController implements FxController { + + private static final Logger LOG = LoggerFactory.getLogger(UnlockSuccessController.class); + + private final Stage window; + private final Vault vault; + private final ExecutorService executor; + private final ObjectProperty revealButtonState; + + @Inject + public UnlockSuccessController(@UnlockWindow Stage window, @UnlockWindow Vault vault, ExecutorService executor) { + this.window = window; + this.vault = vault; + this.executor = executor; + this.revealButtonState = new SimpleObjectProperty<>(ContentDisplay.TEXT_ONLY); + } + + + public void close() { + LOG.trace("UnlockSuccessController.close()"); + window.close(); + } + + public void revealAndClose() { + LOG.trace("UnlockSuccessController.revealAndClose()"); + revealButtonState.set(ContentDisplay.LEFT); + Tasks.create(() -> { + vault.reveal(); + }).onSuccess(() -> { + window.close(); + }).onError(InvalidPassphraseException.class, e -> { + // TODO + LOG.warn("Reveal failed.", e); + }).andFinally(() -> { + revealButtonState.set(ContentDisplay.TEXT_ONLY); + }).runOnce(executor); + } + + /* Getter/Setter */ + + public Vault getVault() { + return vault; + } + + public ReadOnlyObjectProperty revealButtonStateProperty() { + return revealButtonState; + } + + public ContentDisplay getRevealButtonState() { + return revealButtonState.get(); + } + +} diff --git a/main/ui/src/main/resources/fxml/unlock2.fxml b/main/ui/src/main/resources/fxml/unlock2.fxml index 4b9c2700a..741d4aefe 100644 --- a/main/ui/src/main/resources/fxml/unlock2.fxml +++ b/main/ui/src/main/resources/fxml/unlock2.fxml @@ -28,7 +28,7 @@ + + +