Bläddra i källkod

refactoring forget password dialog ( when unlocking a vault)

Armin Schrenk 5 år sedan
förälder
incheckning
200fc1a563

+ 1 - 0
main/ui/src/main/java/org/cryptomator/ui/common/FxmlFile.java

@@ -8,6 +8,7 @@ public enum FxmlFile {
 	ADDVAULT_NEW_PASSWORD("/fxml/addvault_new_password.fxml"), //
 	ADDVAULT_SUCCESS("/fxml/addvault_success.fxml"), //
 	CHANGEPASSWORD("/fxml/changepassword.fxml"), //
+	FORGET_PASSWORD("/fxml/forget_password.fxml"), //
 	MAIN_WINDOW("/fxml/main_window.fxml"), //
 	MIGRATION_RUN("/fxml/migration_run.fxml"), //
 	MIGRATION_START("/fxml/migration_start.fxml"), //

+ 14 - 0
main/ui/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPassword.java

@@ -0,0 +1,14 @@
+package org.cryptomator.ui.forgetPassword;
+
+import javax.inject.Qualifier;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface ForgetPassword {
+
+}

+ 51 - 0
main/ui/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordComponent.java

@@ -0,0 +1,51 @@
+package org.cryptomator.ui.forgetPassword;
+
+import dagger.BindsInstance;
+import dagger.Lazy;
+import dagger.Subcomponent;
+import javafx.beans.property.ReadOnlyBooleanProperty;
+import javafx.scene.Scene;
+import javafx.stage.Stage;
+import org.cryptomator.common.vaults.Vault;
+import org.cryptomator.ui.common.FxmlFile;
+import org.cryptomator.ui.common.FxmlScene;
+
+import javax.inject.Named;
+import java.util.concurrent.CompletableFuture;
+
+@ForgetPasswordScoped
+@Subcomponent(modules = {ForgetPasswordModule.class})
+public interface ForgetPasswordComponent {
+
+	@ForgetPassword
+	ReadOnlyBooleanProperty confirmedProperty();
+
+	@ForgetPassword
+	Stage window();
+
+	@FxmlScene(FxmlFile.FORGET_PASSWORD)
+	Lazy<Scene> scene();
+
+	default CompletableFuture<Boolean> showForgetPassword() {
+		CompletableFuture<Boolean> result = new CompletableFuture<>();
+		Stage stage = window();
+		stage.setScene(scene().get());
+		stage.sizeToScene();
+		stage.show();
+		stage.setOnHidden(evt -> result.complete(confirmedProperty().get()));
+		return result;
+	}
+
+	@Subcomponent.Builder
+	interface Builder {
+
+		@BindsInstance
+		Builder vault(@ForgetPassword Vault vault);
+
+		@BindsInstance
+		Builder owner(@Named("forgetPasswordOwner") Stage owner);
+
+		ForgetPasswordComponent build();
+	}
+
+}

+ 53 - 0
main/ui/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordController.java

@@ -0,0 +1,53 @@
+package org.cryptomator.ui.forgetPassword;
+
+import javafx.beans.property.BooleanProperty;
+import javafx.fxml.FXML;
+import javafx.stage.Stage;
+import org.cryptomator.common.vaults.Vault;
+import org.cryptomator.keychain.KeychainAccess;
+import org.cryptomator.keychain.KeychainAccessException;
+import org.cryptomator.ui.common.FxController;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import java.util.Optional;
+
+@ForgetPasswordScoped
+public class ForgetPasswordController implements FxController {
+
+	private static final Logger LOG = LoggerFactory.getLogger(ForgetPasswordController.class);
+
+	private final Stage window;
+	private final Vault vault;
+	private final Optional<KeychainAccess> keychainAccess;
+	private final BooleanProperty confirmedResult;
+
+	@Inject
+	public ForgetPasswordController(@ForgetPassword Stage window, @ForgetPassword Vault vault, Optional<KeychainAccess> keychainAccess, @ForgetPassword BooleanProperty confirmedResult) {
+		this.window = window;
+		this.vault = vault;
+		this.keychainAccess = keychainAccess;
+		this.confirmedResult = confirmedResult;
+	}
+
+	@FXML
+	public void close() {
+		window.close();
+	}
+
+	@FXML
+	public void finish() {
+		if (keychainAccess.isPresent()) {
+			try {
+				keychainAccess.get().deletePassphrase(vault.getId());
+				LOG.debug("Forgot password for vault {}.", vault.getDisplayableName());
+				confirmedResult.setValue(true);
+			} catch (KeychainAccessException e) {
+				LOG.error("Failed to remove entry from system keychain.", e);
+				confirmedResult.setValue(false);
+			}
+		}
+		window.close();
+	}
+}

+ 74 - 0
main/ui/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordModule.java

@@ -0,0 +1,74 @@
+package org.cryptomator.ui.forgetPassword;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.Provides;
+import dagger.multibindings.IntoMap;
+import javafx.beans.property.BooleanProperty;
+import javafx.beans.property.ReadOnlyBooleanProperty;
+import javafx.beans.property.SimpleBooleanProperty;
+import javafx.scene.Scene;
+import javafx.scene.image.Image;
+import javafx.stage.Modality;
+import javafx.stage.Stage;
+import org.cryptomator.ui.common.FXMLLoaderFactory;
+import org.cryptomator.ui.common.FxController;
+import org.cryptomator.ui.common.FxControllerKey;
+import org.cryptomator.ui.common.FxmlFile;
+import org.cryptomator.ui.common.FxmlScene;
+
+import javax.inject.Named;
+import javax.inject.Provider;
+import java.util.Map;
+import java.util.Optional;
+import java.util.ResourceBundle;
+
+@Module
+abstract class ForgetPasswordModule {
+
+	@Provides
+	@ForgetPassword
+	@ForgetPasswordScoped
+	static FXMLLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, ResourceBundle resourceBundle) {
+		return new FXMLLoaderFactory(factories, resourceBundle);
+	}
+
+	@Provides
+	@ForgetPassword
+	@ForgetPasswordScoped
+	static Stage provideStage(ResourceBundle resourceBundle, @Named("windowIcon") Optional<Image> windowIcon, @Named("forgetPasswordOwner") Stage owner) {
+		Stage stage = new Stage();
+		stage.setTitle(resourceBundle.getString("forgetPassword.title"));
+		stage.setResizable(false);
+		stage.initModality(Modality.WINDOW_MODAL);
+		stage.initOwner(owner);
+		windowIcon.ifPresent(stage.getIcons()::add);
+		return stage;
+	}
+
+	@Provides
+	@FxmlScene(FxmlFile.FORGET_PASSWORD)
+	@ForgetPasswordScoped
+	static Scene provideForgetPasswordScene(@ForgetPassword FXMLLoaderFactory fxmlLoaders, @ForgetPassword Stage window) {
+		return fxmlLoaders.createScene("/fxml/forget_password.fxml");
+	}
+
+	@Provides
+	@ForgetPassword
+	@ForgetPasswordScoped
+	static BooleanProperty provideConfirmedProperty() {
+		return new SimpleBooleanProperty(false);
+	}
+
+	@Binds
+	@ForgetPassword
+	@ForgetPasswordScoped
+	abstract ReadOnlyBooleanProperty bindReadOnlyConfirmedProperty(@ForgetPassword BooleanProperty confirmedProperty);
+
+	// ------------------
+
+	@Binds
+	@IntoMap
+	@FxControllerKey(ForgetPasswordController.class)
+	abstract FxController bindForgetPasswordController(ForgetPasswordController controller);
+}

+ 13 - 0
main/ui/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordScoped.java

@@ -0,0 +1,13 @@
+package org.cryptomator.ui.forgetPassword;
+
+import javax.inject.Scope;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Scope
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ForgetPasswordScoped {
+
+}

+ 5 - 21
main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java

@@ -12,13 +12,10 @@ import javafx.beans.property.SimpleBooleanProperty;
 import javafx.beans.value.WritableValue;
 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 javafx.util.Duration;
-import org.apache.commons.lang3.SystemUtils;
 import org.cryptomator.common.vaults.Vault;
 import org.cryptomator.common.vaults.VaultState;
 import org.cryptomator.cryptolib.api.InvalidPassphraseException;
@@ -30,8 +27,7 @@ import org.cryptomator.ui.common.FxmlFile;
 import org.cryptomator.ui.common.FxmlScene;
 import org.cryptomator.ui.common.Tasks;
 import org.cryptomator.ui.controls.NiceSecurePasswordField;
-import org.cryptomator.ui.controls.SecurePasswordField;
-import org.cryptomator.ui.util.DialogBuilderUtil;
+import org.cryptomator.ui.forgetPassword.ForgetPasswordComponent;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -55,12 +51,13 @@ public class UnlockController implements FxController {
 	private final Optional<KeychainAccess> keychainAccess;
 	private final ResourceBundle resourceBundle;
 	private final Lazy<Scene> successScene;
+	private final ForgetPasswordComponent.Builder forgetPassword;
 	private final BooleanProperty unlockButtonDisabled;
 	public NiceSecurePasswordField passwordField;
 	public CheckBox savePassword;
 
 	@Inject
-	public UnlockController(@UnlockWindow Stage window, @UnlockWindow Vault vault, ExecutorService executor, Optional<KeychainAccess> keychainAccess, ResourceBundle resourceBundle, @FxmlScene(FxmlFile.UNLOCK_SUCCESS) Lazy<Scene> successScene) {
+	public UnlockController(@UnlockWindow Stage window, @UnlockWindow Vault vault, ExecutorService executor, Optional<KeychainAccess> keychainAccess, ResourceBundle resourceBundle, @FxmlScene(FxmlFile.UNLOCK_SUCCESS) Lazy<Scene> successScene, ForgetPasswordComponent.Builder forgetPassword) {
 		this.window = window;
 		this.vault = vault;
 		this.executor = executor;
@@ -68,6 +65,7 @@ public class UnlockController implements FxController {
 		this.keychainAccess = keychainAccess;
 		this.resourceBundle = resourceBundle;
 		this.successScene = successScene;
+		this.forgetPassword = forgetPassword;
 		this.unlockButtonDisabled = new SimpleBooleanProperty();
 	}
 
@@ -128,21 +126,7 @@ public class UnlockController implements FxController {
 	@FXML
 	private void didClickSavePasswordCheckbox() {
 		if (!savePassword.isSelected() && hasStoredPassword()) {
-			Alert confirmDialog = DialogBuilderUtil.buildConfirmationDialog( //
-					resourceBundle.getString("unlock.deleteSavedPasswordDialog.title"), //
-					resourceBundle.getString("unlock.deleteSavedPasswordDialog.header"), //
-					resourceBundle.getString("unlock.deleteSavedPasswordDialog.content"), //
-					SystemUtils.IS_OS_MAC_OSX ? ButtonType.CANCEL : ButtonType.OK);
-			Optional<ButtonType> choice = confirmDialog.showAndWait();
-			if (ButtonType.OK.equals(choice.get())) {
-				try {
-					keychainAccess.get().deletePassphrase(vault.getId());
-				} catch (KeychainAccessException e) {
-					LOG.error("Failed to remove entry from system keychain.", e);
-				}
-			} else if (ButtonType.CANCEL.equals(choice.get())) {
-				savePassword.setSelected(true);
-			}
+			forgetPassword.vault(vault).build().showForgetPassword().thenAccept(forgotten -> savePassword.setSelected(!forgotten));
 		}
 	}
 

+ 2 - 1
main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java

@@ -16,6 +16,7 @@ import org.cryptomator.ui.common.FxController;
 import org.cryptomator.ui.common.FxControllerKey;
 import org.cryptomator.ui.common.FxmlFile;
 import org.cryptomator.ui.common.FxmlScene;
+import org.cryptomator.ui.forgetPassword.ForgetPasswordComponent;
 
 import javax.inject.Named;
 import javax.inject.Provider;
@@ -23,7 +24,7 @@ import java.util.Map;
 import java.util.Optional;
 import java.util.ResourceBundle;
 
-@Module
+@Module(subcomponents={ForgetPasswordComponent.class})
 abstract class UnlockModule {
 
 	@Provides

+ 40 - 0
main/ui/src/main/resources/fxml/forget_password.fxml

@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.geometry.Insets?>
+<?import javafx.scene.control.Button?>
+<?import javafx.scene.control.ButtonBar?>
+<?import javafx.scene.control.Label?>
+<?import javafx.scene.layout.HBox?>
+<?import javafx.scene.layout.StackPane?>
+<?import javafx.scene.layout.VBox?>
+<?import javafx.scene.shape.Circle?>
+<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
+<VBox xmlns="http://javafx.com/javafx"
+	  xmlns:fx="http://javafx.com/fxml"
+	  fx:controller="org.cryptomator.ui.forgetPassword.ForgetPasswordController"
+	  minWidth="400"
+	  maxWidth="400"
+	  minHeight="145"
+	  spacing="12">
+	<padding>
+		<Insets topRightBottomLeft="12"/>
+	</padding>
+	<children>
+		<HBox spacing="12" alignment="CENTER_LEFT" VBox.vgrow="ALWAYS">
+			<StackPane alignment="CENTER" HBox.hgrow="NEVER">
+				<Circle styleClass="glyph-icon-primary" radius="24"/>
+				<FontAwesome5IconView styleClass="glyph-icon-white" glyph="QUESTION" glyphSize="24"/>
+			</StackPane>
+			<Label text="%forgetPassword.information" wrapText="true" textAlignment="LEFT" HBox.hgrow="ALWAYS"/>
+		</HBox>
+
+		<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
+			<ButtonBar buttonMinWidth="120" buttonOrder="+CI">
+				<buttons>
+					<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" defaultButton="true" cancelButton="true" onAction="#close"/>
+					<Button text="%forgetPassword.confirmBtn" ButtonBar.buttonData="FINISH" onAction="#finish"/>
+				</buttons>
+			</ButtonBar>
+		</VBox>
+	</children>
+</VBox>

+ 5 - 0
main/ui/src/main/resources/i18n/strings.properties

@@ -68,6 +68,11 @@ changepassword.passwordsMatch=Passwords match!
 changepassword.passwordsDoNotMatch=Passwords do not match
 changepassword.finalConfirmation=I understand that I will not be able to recover my data if I forget my password
 
+# Forget password
+forgetPassword.title=Forget Password
+forgetPassword.information=TODO Yalla Yalla
+forgetPassword.confirmBtn=Ok, forget
+
 # Unlock
 unlock.title=Unlock Vault
 unlock.passwordPrompt=Enter password for "%s":

+ 1 - 0
main/ui/src/main/resources/i18n/strings_de.properties

@@ -145,3 +145,4 @@ passwordStrength.messageLabel.4=Sehr stark
 # Quit
 quit.prompt=Cryptomator beenden? Es sind noch Tresore entsperrt.
 quit.lockAndQuit=Sperren und beenden
+forgetPassword.information=TODO Yalla Yalla