Ver código fonte

Deduplicated UI code
Made "Enter Password" and "Reenter Password" a reusable component that is included in its original places
preparation for #1018

Sebastian Stenzel 5 anos atrás
pai
commit
148eed172a

+ 16 - 0
main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/AddVaultModule.java

@@ -19,6 +19,8 @@ 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.common.NewPasswordController;
+import org.cryptomator.ui.common.PasswordStrengthUtil;
 import org.cryptomator.ui.mainwindow.MainWindow;
 import org.cryptomator.ui.recoverykey.RecoveryKeyDisplayController;
 
@@ -32,6 +34,13 @@ import java.util.ResourceBundle;
 @Module
 public abstract class AddVaultModule {
 
+	@Provides
+	@AddVaultWizardScoped
+	@Named("newPassword")
+	static ObjectProperty<CharSequence> provideNewPasswordProperty() {
+		return new SimpleObjectProperty<>("");
+	}
+
 	@Provides
 	@AddVaultWizardWindow
 	@AddVaultWizardScoped
@@ -169,6 +178,13 @@ public abstract class AddVaultModule {
 	@FxControllerKey(CreateNewVaultPasswordController.class)
 	abstract FxController bindCreateNewVaultPasswordController(CreateNewVaultPasswordController controller);
 
+	@Provides
+	@IntoMap
+	@FxControllerKey(NewPasswordController.class)
+	static FxController provideNewPasswordController(ResourceBundle resourceBundle, PasswordStrengthUtil strengthRater, @Named("newPassword") ObjectProperty<CharSequence> password) {
+		return new NewPasswordController(resourceBundle, strengthRater, password);
+	}
+
 	@Binds
 	@IntoMap
 	@FxControllerKey(CreateNewVaultRecoveryKeyController.class)

Diferenças do arquivo suprimidas por serem muito extensas
+ 11 - 52
main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultPasswordController.java


+ 12 - 40
main/ui/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordController.java

@@ -3,6 +3,7 @@ package org.cryptomator.ui.changepassword;
 import javafx.beans.binding.Bindings;
 import javafx.beans.binding.BooleanBinding;
 import javafx.beans.property.IntegerProperty;
+import javafx.beans.property.ObjectProperty;
 import javafx.beans.property.SimpleIntegerProperty;
 import javafx.fxml.FXML;
 import javafx.scene.control.Button;
@@ -22,6 +23,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 import java.io.IOException;
 import java.util.ResourceBundle;
 
@@ -33,47 +35,24 @@ public class ChangePasswordController implements FxController {
 
 	private final Stage window;
 	private final Vault vault;
-	private final ResourceBundle resourceBundle;
-	private final PasswordStrengthUtil strengthRater;
-	private final IntegerProperty passwordStrength;
+	private final ObjectProperty<CharSequence> newPassword;
 
 	public NiceSecurePasswordField oldPasswordField;
-	public NiceSecurePasswordField newPasswordField;
-	public NiceSecurePasswordField reenterPasswordField;
-	public Label passwordStrengthLabel;
-	public HBox passwordMatchBox;
-	public FontAwesome5IconView checkmark;
-	public FontAwesome5IconView cross;
-	public Label passwordMatchLabel;
 	public CheckBox finalConfirmationCheckbox;
 	public Button finishButton;
 
 	@Inject
-	public ChangePasswordController(@ChangePasswordWindow Stage window, @ChangePasswordWindow Vault vault, ResourceBundle resourceBundle, PasswordStrengthUtil strengthRater) {
+	public ChangePasswordController(@ChangePasswordWindow Stage window, @ChangePasswordWindow Vault vault, @Named("newPassword") ObjectProperty<CharSequence> newPassword) {
 		this.window = window;
 		this.vault = vault;
-		this.resourceBundle = resourceBundle;
-		this.strengthRater = strengthRater;
-		this.passwordStrength = new SimpleIntegerProperty(-1);
+		this.newPassword = newPassword;
 	}
 
 	@FXML
 	public void initialize() {
-		//binds the actual strength value to the rating of the password util
-		passwordStrength.bind(Bindings.createIntegerBinding(() -> strengthRater.computeRate(newPasswordField.getCharacters().toString()), newPasswordField.textProperty()));
-		//binding indicating if the passwords not match
-		BooleanBinding passwordsMatch = Bindings.createBooleanBinding(() -> CharSequence.compare(newPasswordField.getCharacters(), reenterPasswordField.getCharacters()) == 0, newPasswordField.textProperty(), reenterPasswordField.textProperty());
-		BooleanBinding reenterFieldNotEmpty = reenterPasswordField.textProperty().isNotEmpty();
-		//disable the finish button when passwords do not match or one is empty
-		finishButton.disableProperty().bind(reenterFieldNotEmpty.not().or(passwordsMatch.not()).or(finalConfirmationCheckbox.selectedProperty().not()));
-		//make match indicator invisible when passwords do not match or one is empty
-		passwordMatchBox.visibleProperty().bind(reenterFieldNotEmpty);
-		checkmark.visibleProperty().bind(passwordsMatch.and(reenterFieldNotEmpty));
-		checkmark.managedProperty().bind(checkmark.visibleProperty());
-		cross.visibleProperty().bind(passwordsMatch.not().and(reenterFieldNotEmpty));
-		cross.managedProperty().bind(cross.visibleProperty());
-		passwordMatchLabel.textProperty().bind(Bindings.when(passwordsMatch.and(reenterFieldNotEmpty)).then(resourceBundle.getString("changepassword.passwordsMatch")).otherwise(resourceBundle.getString("changepassword.passwordsDoNotMatch")));
-		passwordStrengthLabel.textProperty().bind(EasyBind.map(passwordStrength, strengthRater::getStrengthDescription));
+		BooleanBinding hasNotConfirmedCheckbox = finalConfirmationCheckbox.selectedProperty().not();
+		BooleanBinding isInvalidNewPassword = Bindings.createBooleanBinding(() -> newPassword.get() == null || newPassword.get().length() == 0, newPassword); 
+		finishButton.disableProperty().bind(hasNotConfirmedCheckbox.or(isInvalidNewPassword));
 	}
 
 	@FXML
@@ -84,15 +63,15 @@ public class ChangePasswordController implements FxController {
 	@FXML
 	public void finish() {
 		try {
-			CryptoFileSystemProvider.changePassphrase(vault.getPath(), MASTERKEY_FILENAME, oldPasswordField.getCharacters(), newPasswordField.getCharacters());
+			CryptoFileSystemProvider.changePassphrase(vault.getPath(), MASTERKEY_FILENAME, oldPasswordField.getCharacters(), newPassword.get());
 			LOG.info("Successful changed password for {}", vault.getDisplayableName());
 			window.close();
 		} catch (IOException e) {
-			//TODO
+			// TODO show generic error screen
 			LOG.error("IO error occured during password change. Unable to perform operation.", e);
 			e.printStackTrace();
 		} catch (InvalidPassphraseException e) {
-			//TODO
+			// TODO shake
 			LOG.info("Wrong old password.");
 		}
 	}
@@ -102,12 +81,5 @@ public class ChangePasswordController implements FxController {
 	public Vault getVault() {
 		return vault;
 	}
-
-	public IntegerProperty passwordStrengthProperty() {
-		return passwordStrength;
-	}
-
-	public int getPasswordStrength() {
-		return passwordStrength.get();
-	}
+	
 }

+ 19 - 0
main/ui/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordModule.java

@@ -4,6 +4,8 @@ import dagger.Binds;
 import dagger.Module;
 import dagger.Provides;
 import dagger.multibindings.IntoMap;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleObjectProperty;
 import javafx.scene.Scene;
 import javafx.scene.image.Image;
 import javafx.stage.Modality;
@@ -14,15 +16,25 @@ 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.common.NewPasswordController;
+import org.cryptomator.ui.common.PasswordStrengthUtil;
 
 import javax.inject.Named;
 import javax.inject.Provider;
+import java.nio.CharBuffer;
 import java.util.Map;
 import java.util.Optional;
 import java.util.ResourceBundle;
 
 @Module
 abstract class ChangePasswordModule {
+	
+	@Provides
+	@ChangePasswordScoped
+	@Named("newPassword")
+	static ObjectProperty<CharSequence> provideNewPasswordProperty() {
+		return new SimpleObjectProperty<>("");
+	}
 
 	@Provides
 	@ChangePasswordWindow
@@ -58,5 +70,12 @@ abstract class ChangePasswordModule {
 	@IntoMap
 	@FxControllerKey(ChangePasswordController.class)
 	abstract FxController bindUnlockController(ChangePasswordController controller);
+	
+	@Provides
+	@IntoMap
+	@FxControllerKey(NewPasswordController.class)
+	static FxController provideNewPasswordController(ResourceBundle resourceBundle, PasswordStrengthUtil strengthRater, @Named("newPassword") ObjectProperty<CharSequence> password) {
+		return new NewPasswordController(resourceBundle, strengthRater, password);
+	}
 
 }

+ 74 - 0
main/ui/src/main/java/org/cryptomator/ui/common/NewPasswordController.java

@@ -0,0 +1,74 @@
+package org.cryptomator.ui.common;
+
+import javafx.beans.Observable;
+import javafx.beans.binding.Bindings;
+import javafx.beans.binding.BooleanBinding;
+import javafx.beans.property.IntegerProperty;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleIntegerProperty;
+import javafx.fxml.FXML;
+import javafx.scene.control.Label;
+import org.cryptomator.ui.controls.FontAwesome5IconView;
+import org.cryptomator.ui.controls.NiceSecurePasswordField;
+import org.fxmisc.easybind.EasyBind;
+
+import java.util.ResourceBundle;
+
+public class NewPasswordController implements FxController {
+
+	private final ResourceBundle resourceBundle;
+	private final PasswordStrengthUtil strengthRater;
+	private final ObjectProperty<CharSequence> password;
+	private final IntegerProperty passwordStrength = new SimpleIntegerProperty(-1);
+
+	public NiceSecurePasswordField passwordField;
+	public NiceSecurePasswordField reenterField;
+	public Label passwordStrengthLabel;
+	public Label passwordMatchLabel;
+	public FontAwesome5IconView checkmark;
+	public FontAwesome5IconView cross;
+
+	public NewPasswordController(ResourceBundle resourceBundle, PasswordStrengthUtil strengthRater, ObjectProperty<CharSequence> password) {
+		this.resourceBundle = resourceBundle;
+		this.strengthRater = strengthRater;
+		this.password = password;
+	}
+
+	@FXML
+	public void initialize() {
+		BooleanBinding passwordsMatch = Bindings.createBooleanBinding(this::hasSamePasswordInBothFields, passwordField.textProperty(), reenterField.textProperty());
+		BooleanBinding reenterFieldNotEmpty = reenterField.textProperty().isNotEmpty();
+		passwordStrength.bind(Bindings.createIntegerBinding(() -> strengthRater.computeRate(passwordField.getCharacters().toString()), passwordField.textProperty()));
+		passwordStrengthLabel.textProperty().bind(EasyBind.map(passwordStrength, strengthRater::getStrengthDescription));
+		
+		passwordMatchLabel.visibleProperty().bind(reenterFieldNotEmpty);
+		passwordMatchLabel.graphicProperty().bind(Bindings.when(passwordsMatch.and(reenterFieldNotEmpty)).then(checkmark).otherwise(cross));
+		passwordMatchLabel.textProperty().bind(Bindings.when(passwordsMatch.and(reenterFieldNotEmpty)).then(resourceBundle.getString("newPassword.passwordsMatch")).otherwise(resourceBundle.getString("newPassword.passwordsDoNotMatch")));
+
+		passwordField.textProperty().addListener(this::passwordsDidChange);
+		reenterField.textProperty().addListener(this::passwordsDidChange);
+	}
+
+	private void passwordsDidChange(@SuppressWarnings("unused") Observable observable) {
+		if (hasSamePasswordInBothFields()) {
+			password.set(passwordField.getCharacters());
+		} else {
+			password.set("");
+		}
+	}
+
+	private boolean hasSamePasswordInBothFields() {
+		return CharSequence.compare(passwordField.getCharacters(), reenterField.getCharacters()) == 0;
+	}
+
+	/* Getter/Setter */
+
+	public IntegerProperty passwordStrengthProperty() {
+		return passwordStrength;
+	}
+
+	public int getPasswordStrength() {
+		return passwordStrength.get();
+	}
+
+}

+ 1 - 1
main/ui/src/main/java/org/cryptomator/ui/controls/NiceSecurePasswordField.java

@@ -89,7 +89,7 @@ public class NiceSecurePasswordField extends StackPane {
 	}
 
 	public void swipe() {
-		passwordField.swipe();;
+		passwordField.swipe();
 	}
 
 	public void selectAll() {

+ 3 - 21
main/ui/src/main/resources/fxml/addvault_new_password.fxml

@@ -5,14 +5,10 @@
 <?import javafx.scene.control.ButtonBar?>
 <?import javafx.scene.control.Label?>
 <?import javafx.scene.control.ProgressIndicator?>
-<?import javafx.scene.layout.HBox?>
-<?import javafx.scene.layout.Region?>
-<?import javafx.scene.layout.VBox?>
-<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
-<?import org.cryptomator.ui.controls.NiceSecurePasswordField?>
-<?import org.cryptomator.ui.controls.PasswordStrengthIndicator?>
 <?import javafx.scene.control.RadioButton?>
 <?import javafx.scene.control.ToggleGroup?>
+<?import javafx.scene.layout.Region?>
+<?import javafx.scene.layout.VBox?>
 <VBox xmlns="http://javafx.com/javafx"
 	  xmlns:fx="http://javafx.com/fxml"
 	  fx:controller="org.cryptomator.ui.addvaultwizard.CreateNewVaultPasswordController"
@@ -27,21 +23,7 @@
 		<Insets topRightBottomLeft="24"/>
 	</padding>
 	<children>
-		<VBox spacing="6">
-			<Label text="%addvaultwizard.new.enterPassword" labelFor="$passwordField"/>
-			<NiceSecurePasswordField fx:id="passwordField"/>
-			<PasswordStrengthIndicator spacing="6" prefHeight="6" strength="${controller.passwordStrength}"/>
-			<Label fx:id="passwordStrengthLabel" styleClass="label-secondary" labelFor="$passwordField" alignment="CENTER_RIGHT" maxWidth="Infinity"/>
-		</VBox>
-		<VBox spacing="6">
-			<Label text="%addvaultwizard.new.reenterPassword" labelFor="$reenterField"/>
-			<NiceSecurePasswordField fx:id="reenterField"/>
-			<HBox fx:id="passwordMatchBox" spacing="6" alignment="CENTER_RIGHT">
-				<FontAwesome5IconView fx:id="checkmark" styleClass="glyph-icon-primary" glyph="CHECK"/>
-				<FontAwesome5IconView fx:id="cross" styleClass="glyph-icon-red" glyph="TIMES"/>
-				<Label fx:id="passwordMatchLabel" styleClass="label-secondary" labelFor="$reenterField"/>
-			</HBox>
-		</VBox>
+		<fx:include source="/fxml/new_password.fxml"/>
 
 		<Region VBox.vgrow="ALWAYS"/>
 		

+ 2 - 15
main/ui/src/main/resources/fxml/changepassword.fxml

@@ -28,22 +28,9 @@
 		</VBox>
 
 		<Region prefHeight="12" VBox.vgrow="NEVER"/>
+		
+		<fx:include source="/fxml/new_password.fxml"/>
 
-		<VBox spacing="6">
-			<Label labelFor="$newPasswordField" text="%changepassword.enterNewPassword"/>
-			<NiceSecurePasswordField fx:id="newPasswordField"/>
-			<PasswordStrengthIndicator prefHeight="6" spacing="6" strength="${controller.passwordStrength}"/>
-			<Label fx:id="passwordStrengthLabel" styleClass="label-secondary" alignment="CENTER_RIGHT" maxWidth="Infinity"/>
-		</VBox>
-		<VBox spacing="6">
-			<Label labelFor="$reenterPasswordField" text="%changepassword.reenterNewPassword"/>
-			<NiceSecurePasswordField fx:id="reenterPasswordField"/>
-			<HBox fx:id="passwordMatchBox" spacing="6" alignment="CENTER_RIGHT">
-				<FontAwesome5IconView fx:id="checkmark" styleClass="glyph-icon-primary" glyph="CHECK"/>
-				<FontAwesome5IconView fx:id="cross" styleClass="glyph-icon-red" glyph="TIMES"/>
-				<Label fx:id="passwordMatchLabel" styleClass="label-secondary" labelFor="$reenterPasswordField"/>
-			</HBox>
-		</VBox>
 		<CheckBox fx:id="finalConfirmationCheckbox" text="%changepassword.finalConfirmation" wrapText="true"/>
 
 		<Region VBox.vgrow="ALWAYS"/>

+ 30 - 0
main/ui/src/main/resources/fxml/new_password.fxml

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.scene.control.Label?>
+<?import javafx.scene.layout.Region?>
+<?import javafx.scene.layout.VBox?>
+<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
+<?import org.cryptomator.ui.controls.NiceSecurePasswordField?>
+<?import org.cryptomator.ui.controls.PasswordStrengthIndicator?>
+<VBox xmlns="http://javafx.com/javafx"
+	  xmlns:fx="http://javafx.com/fxml"
+	  fx:controller="org.cryptomator.ui.common.NewPasswordController"
+	  spacing="6"
+	  alignment="CENTER_LEFT">
+	<fx:define>
+		<FontAwesome5IconView fx:id="checkmark" styleClass="glyph-icon-primary" glyph="CHECK"/>
+		<FontAwesome5IconView fx:id="cross" styleClass="glyph-icon-red" glyph="TIMES"/>
+	</fx:define>
+	<children>
+		<Label text="%newPassword.promptText" labelFor="$passwordField"/>
+		<NiceSecurePasswordField fx:id="passwordField"/>
+		<PasswordStrengthIndicator spacing="6" prefHeight="6" strength="${controller.passwordStrength}"/>
+		<Label fx:id="passwordStrengthLabel" styleClass="label-secondary" alignment="CENTER_RIGHT" maxWidth="Infinity"/>
+	
+		<Region/>
+
+		<Label text="%newPassword.reenterPassword" labelFor="$reenterField"/>
+		<NiceSecurePasswordField fx:id="reenterField"/>
+		<Label fx:id="passwordMatchLabel" styleClass="label-secondary" alignment="CENTER_RIGHT" maxWidth="Infinity" graphicTextGap="6" contentDisplay="LEFT" />
+	</children>
+</VBox>

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

@@ -40,14 +40,10 @@ addvaultwizard.new.locationPrompt=…
 addvaultwizard.new.directoryPickerLabel=Custom Location
 addvaultwizard.new.directoryPickerButton=Choose…
 addvaultwizard.new.directoryPickerTitle=Select Directory
-addvaultwizard.new.enterPassword=Enter a password for the vault
 addvaultwizard.new.fileAlreadyExists=Vault can not be created at this path because some object already exists.
 addvaultwizard.new.invalidName=Invalid vault name. Please consider a regular directory name.
 addvaultwizard.new.ioException=Selected directory failed a basic test. Make sure to have the appropriate access rights and nothing interferes with Cryptomator.
 ### Password
-addvaultwizard.new.reenterPassword=Confirm the password
-addvaultwizard.new.passwordsMatch=Passwords match!
-addvaultwizard.new.passwordsDoNotMatch=Passwords do not match
 addvaultwizard.new.createVaultBtn=Create Vault
 addvaultwizard.new.generateRecoveryKeyChoice=You won't be able to access your data without your password. Do you want a recovery key for the case you lose your password?
 addvaultwizard.new.generateRecoveryKeyChoice.yes=Yes please, better safe than sorry
@@ -79,10 +75,6 @@ removeVault.confirmBtn=Remove Vault
 # Change Password
 changepassword.title=Change Password
 changepassword.enterOldPassword=Enter the current password for "%s"
-changepassword.enterNewPassword=Enter a new password for your vault
-changepassword.reenterNewPassword=Confirm the new password
-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
@@ -196,7 +188,11 @@ recoveryKey.enterPassword.prompt=Enter your password to show the recovery key fo
 recoveryKey.display.message=The following recovery key can be used to restore access to "%s":
 recoveryKey.display.StorageHints=Keep it somewhere very secure, e.g.:\n • Store it using a password manager\n • Save it on a USB flash drive\n • Print it on paper
 
-# Misc
+# New Password
+newPassword.promptText=Enter a new password
+newPassword.reenterPassword=Confirm the new password
+newPassword.passwordsMatch=Passwords match!
+newPassword.passwordsDoNotMatch=Passwords do not match
 passwordStrength.messageLabel.0=Very weak
 passwordStrength.messageLabel.1=Weak
 passwordStrength.messageLabel.2=Fair