diff --git a/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java b/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java index 4eeea5c3d..0202ee3f8 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java @@ -1,10 +1,10 @@ package org.cryptomator.ui.addvaultwizard; import dagger.Lazy; -import org.cryptomator.ui.common.ErrorComponent; import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlScene; +import org.cryptomator.ui.controls.FontAwesome5IconView; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -15,21 +15,21 @@ import javafx.beans.binding.BooleanBinding; import javafx.beans.property.BooleanProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.beans.value.ObservableValue; import javafx.fxml.FXML; +import javafx.scene.Node; import javafx.scene.Scene; +import javafx.scene.control.Label; import javafx.scene.control.RadioButton; import javafx.scene.control.Toggle; import javafx.scene.control.ToggleGroup; import javafx.stage.DirectoryChooser; import javafx.stage.Stage; import java.io.File; -import java.io.IOException; -import java.nio.file.FileAlreadyExistsException; import java.nio.file.Files; -import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ResourceBundle; @@ -43,55 +43,72 @@ public class CreateNewVaultLocationController implements FxController { private final Stage window; private final Lazy chooseNameScene; private final Lazy choosePasswordScene; - private final ErrorComponent.Builder errorComponent; private final LocationPresets locationPresets; private final ObjectProperty vaultPath; private final StringProperty vaultName; private final ResourceBundle resourceBundle; private final BooleanBinding validVaultPath; private final BooleanProperty usePresetPath; - private final StringProperty warningText; + private final StringProperty statusText; + private final ObjectProperty statusGraphic; private Path customVaultPath = DEFAULT_CUSTOM_VAULT_PATH; + + //FXML public ToggleGroup predefinedLocationToggler; public RadioButton iclouddriveRadioButton; public RadioButton dropboxRadioButton; public RadioButton gdriveRadioButton; public RadioButton onedriveRadioButton; public RadioButton customRadioButton; + public Label vaultPathStatus; + public FontAwesome5IconView goodLocation; + public FontAwesome5IconView badLocation; @Inject - CreateNewVaultLocationController(@AddVaultWizardWindow Stage window, @FxmlScene(FxmlFile.ADDVAULT_NEW_NAME) Lazy chooseNameScene, @FxmlScene(FxmlFile.ADDVAULT_NEW_PASSWORD) Lazy choosePasswordScene, ErrorComponent.Builder errorComponent, LocationPresets locationPresets, ObjectProperty vaultPath, @Named("vaultName") StringProperty vaultName, ResourceBundle resourceBundle) { + CreateNewVaultLocationController(@AddVaultWizardWindow Stage window, @FxmlScene(FxmlFile.ADDVAULT_NEW_NAME) Lazy chooseNameScene, @FxmlScene(FxmlFile.ADDVAULT_NEW_PASSWORD) Lazy choosePasswordScene, LocationPresets locationPresets, ObjectProperty vaultPath, @Named("vaultName") StringProperty vaultName, ResourceBundle resourceBundle) { this.window = window; this.chooseNameScene = chooseNameScene; this.choosePasswordScene = choosePasswordScene; - this.errorComponent = errorComponent; this.locationPresets = locationPresets; this.vaultPath = vaultPath; this.vaultName = vaultName; this.resourceBundle = resourceBundle; - this.validVaultPath = Bindings.createBooleanBinding(this::isValidVaultPath, vaultPath); + this.validVaultPath = Bindings.createBooleanBinding(this::validateVaultPathAndSetStatus, this.vaultPath); this.usePresetPath = new SimpleBooleanProperty(); - this.warningText = new SimpleStringProperty(); + this.statusText = new SimpleStringProperty(); + this.statusGraphic = new SimpleObjectProperty<>(); } - private boolean isValidVaultPath() { - return vaultPath.get() != null && Files.notExists(vaultPath.get()); + private boolean validateVaultPathAndSetStatus() { + final Path p = vaultPath.get(); + if (p == null) { + statusText.set("Error: Path is NULL."); + statusGraphic.set(badLocation); + return false; + } else if (!Files.exists(p.getParent())) { + statusText.set(resourceBundle.getString("addvaultwizard.new.locationDoesNotExist")); + statusGraphic.set(badLocation); + return false; + } else if (!Files.isWritable(p.getParent())) { + statusText.set(resourceBundle.getString("addvaultwizard.new.locationIsNotWritable")); + statusGraphic.set(badLocation); + return false; + } else if (!Files.notExists(p)) { + statusText.set(resourceBundle.getString("addvaultwizard.new.fileAlreadyExists")); + statusGraphic.set(badLocation); + return false; + } else { + statusText.set(resourceBundle.getString("addvaultwizard.new.locationIsOk")); + statusGraphic.set(goodLocation); + return true; + } } @FXML public void initialize() { predefinedLocationToggler.selectedToggleProperty().addListener(this::togglePredefinedLocation); usePresetPath.bind(predefinedLocationToggler.selectedToggleProperty().isNotEqualTo(customRadioButton)); - vaultPath.addListener(this::vaultPathDidChange); - } - - private void vaultPathDidChange(@SuppressWarnings("unused") ObservableValue observable, @SuppressWarnings("unused") Path oldValue, Path newValue) { - if (!Files.notExists(newValue)) { - warningText.set(resourceBundle.getString("addvaultwizard.new.fileAlreadyExists")); - } else { - warningText.set(null); - } } private void togglePredefinedLocation(@SuppressWarnings("unused") ObservableValue observable, @SuppressWarnings("unused") Toggle oldValue, Toggle newValue) { @@ -115,21 +132,10 @@ public class CreateNewVaultLocationController implements FxController { @FXML public void next() { - try { - // check if we have write access AND the vaultPath doesn't already exist: - assert Files.isDirectory(vaultPath.get().getParent()); - Path createdDir = Files.createDirectory(vaultPath.get()); - Files.delete(createdDir); // assert: dir exists and is empty + if (validateVaultPathAndSetStatus()) { window.setScene(choosePasswordScene.get()); - } catch (FileAlreadyExistsException e) { - LOG.warn("Can not use already existing vault path {}", vaultPath.get()); - warningText.set(resourceBundle.getString("addvaultwizard.new.fileAlreadyExists")); - } catch (NoSuchFileException e) { - LOG.warn("At least one path component does not exist of path {}", vaultPath.get()); - warningText.set(resourceBundle.getString("addvaultwizard.new.locationDoesNotExist")); - } catch (IOException e) { - LOG.error("Failed to create and delete directory at chosen vault path.", e); - errorComponent.cause(e).window(window).returnToScene(window.getScene()).build().showErrorScene(); + } else { + validVaultPath.invalidate(); } } @@ -179,19 +185,27 @@ public class CreateNewVaultLocationController implements FxController { return usePresetPath.get(); } - public StringProperty warningTextProperty() { - return warningText; + public BooleanBinding anyRadioButtonSelectedProperty() { + return predefinedLocationToggler.selectedToggleProperty().isNotNull(); } - public String getWarningText() { - return warningText.get(); + public boolean isAnyRadioButtonSelected() { + return anyRadioButtonSelectedProperty().get(); } - public BooleanBinding showWarningProperty() { - return warningText.isNotEmpty(); + public StringProperty statusTextProperty() { + return statusText; } - public boolean isShowWarning() { - return showWarningProperty().get(); + public String getStatusText() { + return statusText.get(); + } + + public ObjectProperty statusGraphicProperty() { + return statusGraphic; + } + + public Node getStatusGraphic() { + return statusGraphic.get(); } } diff --git a/main/ui/src/main/resources/fxml/addvault_new_location.fxml b/main/ui/src/main/resources/fxml/addvault_new_location.fxml index 66b34ff95..d48186698 100644 --- a/main/ui/src/main/resources/fxml/addvault_new_location.fxml +++ b/main/ui/src/main/resources/fxml/addvault_new_location.fxml @@ -20,6 +20,8 @@ alignment="CENTER_LEFT"> + + @@ -47,12 +49,8 @@ diff --git a/main/ui/src/main/resources/i18n/strings.properties b/main/ui/src/main/resources/i18n/strings.properties index ad60cd0c5..824f65811 100644 --- a/main/ui/src/main/resources/i18n/strings.properties +++ b/main/ui/src/main/resources/i18n/strings.properties @@ -45,8 +45,10 @@ addvaultwizard.new.locationPrompt=… addvaultwizard.new.directoryPickerLabel=Custom Location addvaultwizard.new.directoryPickerButton=Choose… addvaultwizard.new.directoryPickerTitle=Select Directory -addvaultwizard.new.fileAlreadyExists=Vault can not be created at this path because some object already exists. -addvaultwizard.new.locationDoesNotExist=Vault can not be created at this path because at least one path component does not exist. +addvaultwizard.new.fileAlreadyExists=A file or directory with the vault name already exists +addvaultwizard.new.locationDoesNotExist=A directory in the specified path does not exist or cannot be accessed +addvaultwizard.new.locationIsNotWritable=No write access at the specified path +addvaultwizard.new.locationIsOk=Suitable location for your vault addvaultwizard.new.invalidName=Invalid vault name. Please consider a regular directory name. ### Password addvaultwizard.new.createVaultBtn=Create Vault