|
@@ -11,7 +11,8 @@ package org.cryptomator.ui.controllers;
|
|
|
import com.google.common.base.CharMatcher;
|
|
|
import com.google.common.base.Strings;
|
|
|
import javafx.application.Application;
|
|
|
-import javafx.beans.Observable;
|
|
|
+import javafx.beans.property.BooleanProperty;
|
|
|
+import javafx.beans.property.SimpleBooleanProperty;
|
|
|
import javafx.beans.value.ChangeListener;
|
|
|
import javafx.beans.value.ObservableValue;
|
|
|
import javafx.fxml.FXML;
|
|
@@ -21,12 +22,11 @@ import javafx.scene.control.Button;
|
|
|
import javafx.scene.control.ButtonType;
|
|
|
import javafx.scene.control.CheckBox;
|
|
|
import javafx.scene.control.ChoiceBox;
|
|
|
+import javafx.scene.control.ContentDisplay;
|
|
|
import javafx.scene.control.Hyperlink;
|
|
|
import javafx.scene.control.Label;
|
|
|
-import javafx.scene.control.ProgressIndicator;
|
|
|
import javafx.scene.control.TextField;
|
|
|
import javafx.scene.input.KeyEvent;
|
|
|
-import javafx.scene.layout.GridPane;
|
|
|
import javafx.scene.layout.HBox;
|
|
|
import javafx.scene.layout.VBox;
|
|
|
import javafx.scene.text.Text;
|
|
@@ -85,6 +85,7 @@ public class UnlockController implements ViewController {
|
|
|
private Vault vault;
|
|
|
private Optional<UnlockListener> listener = Optional.empty();
|
|
|
private Subscription vaultSubs = Subscription.EMPTY;
|
|
|
+ private BooleanProperty unlocking = new SimpleBooleanProperty();
|
|
|
|
|
|
@Inject
|
|
|
public UnlockController(Application app, @Named("mainWindow") Stage mainWindow, Localization localization, WindowsDriveLetters driveLetters, Optional<KeychainAccess> keychainAccess, Settings settings, ExecutorService executor) {
|
|
@@ -125,7 +126,7 @@ public class UnlockController implements ViewController {
|
|
|
private CheckBox revealAfterMount;
|
|
|
|
|
|
@FXML
|
|
|
- private Label winDriveLetterLabel;
|
|
|
+ private CheckBox useCustomWinDriveLetter;
|
|
|
|
|
|
@FXML
|
|
|
private ChoiceBox<Character> winDriveLetter;
|
|
@@ -139,9 +140,6 @@ public class UnlockController implements ViewController {
|
|
|
@FXML
|
|
|
private Label customMountPointLabel;
|
|
|
|
|
|
- @FXML
|
|
|
- private ProgressIndicator progressIndicator;
|
|
|
-
|
|
|
@FXML
|
|
|
private Hyperlink downloadsPageLink;
|
|
|
|
|
@@ -160,7 +158,8 @@ public class UnlockController implements ViewController {
|
|
|
@Override
|
|
|
public void initialize() {
|
|
|
advancedOptions.managedProperty().bind(advancedOptions.visibleProperty());
|
|
|
- unlockButton.disableProperty().bind(passwordField.textProperty().isEmpty());
|
|
|
+ advancedOptions.disableProperty().bind(unlocking);
|
|
|
+ unlockButton.disableProperty().bind(unlocking.or(passwordField.textProperty().isEmpty()));
|
|
|
mountName.addEventFilter(KeyEvent.KEY_TYPED, this::filterAlphanumericKeyEvents);
|
|
|
mountName.textProperty().addListener(this::mountNameDidChange);
|
|
|
useCustomMountFlags.selectedProperty().addListener(this::useCustomMountFlagsDidChange);
|
|
@@ -168,14 +167,16 @@ public class UnlockController implements ViewController {
|
|
|
mountFlags.textProperty().addListener(this::mountFlagsDidChange);
|
|
|
savePassword.setDisable(!keychainAccess.isPresent());
|
|
|
unlockAfterStartup.disableProperty().bind(savePassword.disabledProperty().or(savePassword.selectedProperty().not()));
|
|
|
+ downloadsPageLink.visibleProperty().bind(downloadsPageLink.managedProperty());
|
|
|
|
|
|
customMountPoint.visibleProperty().bind(useCustomMountPoint.selectedProperty());
|
|
|
customMountPoint.managedProperty().bind(useCustomMountPoint.selectedProperty());
|
|
|
winDriveLetter.setConverter(new WinDriveLetterLabelConverter());
|
|
|
+ winDriveLetter.disableProperty().bind(useCustomWinDriveLetter.selectedProperty().not());
|
|
|
|
|
|
if (!SystemUtils.IS_OS_WINDOWS) {
|
|
|
- winDriveLetterLabel.setVisible(false);
|
|
|
- winDriveLetterLabel.setManaged(false);
|
|
|
+ useCustomWinDriveLetter.setVisible(false);
|
|
|
+ useCustomWinDriveLetter.setManaged(false);
|
|
|
winDriveLetter.setVisible(false);
|
|
|
winDriveLetter.setManaged(false);
|
|
|
}
|
|
@@ -205,18 +206,9 @@ public class UnlockController implements ViewController {
|
|
|
this.vault = vault;
|
|
|
advancedOptions.setVisible(false);
|
|
|
advancedOptionsButton.setText(localization.getString("unlock.button.advancedOptions.show"));
|
|
|
- progressIndicator.setVisible(false);
|
|
|
+ unlockButton.setContentDisplay(ContentDisplay.TEXT_ONLY);
|
|
|
state.successMessage().map(localization::getString).ifPresent(messageText::setText);
|
|
|
- if (SystemUtils.IS_OS_WINDOWS) {
|
|
|
- winDriveLetter.valueProperty().removeListener(driveLetterChangeListener);
|
|
|
- winDriveLetter.getItems().clear();
|
|
|
- winDriveLetter.getItems().add(null);
|
|
|
- winDriveLetter.getItems().addAll(driveLetters.getAvailableDriveLetters());
|
|
|
- winDriveLetter.getItems().sort(new WinDriveLetterComparator());
|
|
|
- winDriveLetter.valueProperty().addListener(driveLetterChangeListener);
|
|
|
- chooseSelectedDriveLetter();
|
|
|
- }
|
|
|
- downloadsPageLink.setVisible(false);
|
|
|
+ downloadsPageLink.setManaged(false);
|
|
|
mountName.setText(vault.getMountName());
|
|
|
useCustomMountFlags.setSelected(vault.isHavingCustomMountFlags());
|
|
|
mountFlags.setText(vault.getMountFlags());
|
|
@@ -251,10 +243,6 @@ public class UnlockController implements ViewController {
|
|
|
|
|
|
// DOKANY-dependent controls:
|
|
|
if (VolumeImpl.DOKANY.equals(settings.preferredVolumeImpl().get())) {
|
|
|
- winDriveLetter.visibleProperty().bind(useCustomMountPoint.selectedProperty().not());
|
|
|
- winDriveLetter.managedProperty().bind(useCustomMountPoint.selectedProperty().not());
|
|
|
- winDriveLetterLabel.visibleProperty().bind(useCustomMountPoint.selectedProperty().not());
|
|
|
- winDriveLetterLabel.managedProperty().bind(useCustomMountPoint.selectedProperty().not());
|
|
|
// readonly not yet supported by dokany
|
|
|
useReadOnlyMode.setSelected(false);
|
|
|
useReadOnlyMode.setVisible(false);
|
|
@@ -265,10 +253,18 @@ public class UnlockController implements ViewController {
|
|
|
|
|
|
// OS-dependent controls:
|
|
|
if (SystemUtils.IS_OS_WINDOWS) {
|
|
|
+ winDriveLetter.valueProperty().removeListener(driveLetterChangeListener);
|
|
|
+ winDriveLetter.getItems().clear();
|
|
|
+ winDriveLetter.getItems().add(null);
|
|
|
+ winDriveLetter.getItems().addAll(driveLetters.getAvailableDriveLetters());
|
|
|
+ winDriveLetter.getItems().sort(new WinDriveLetterComparator());
|
|
|
+ winDriveLetter.valueProperty().addListener(driveLetterChangeListener);
|
|
|
+ chooseSelectedDriveLetter();
|
|
|
+
|
|
|
winDriveLetter.visibleProperty().bind(useCustomMountPoint.selectedProperty().not());
|
|
|
winDriveLetter.managedProperty().bind(useCustomMountPoint.selectedProperty().not());
|
|
|
- winDriveLetterLabel.visibleProperty().bind(useCustomMountPoint.selectedProperty().not());
|
|
|
- winDriveLetterLabel.managedProperty().bind(useCustomMountPoint.selectedProperty().not());
|
|
|
+ useCustomWinDriveLetter.visibleProperty().bind(useCustomMountPoint.selectedProperty().not());
|
|
|
+ useCustomWinDriveLetter.managedProperty().bind(useCustomMountPoint.selectedProperty().not());
|
|
|
}
|
|
|
|
|
|
vaultSubs = vaultSubs.and(EasyBind.subscribe(unlockAfterStartup.selectedProperty(), vaultSettings.unlockAfterStartup()::set));
|
|
@@ -305,6 +301,7 @@ public class UnlockController implements ViewController {
|
|
|
@FXML
|
|
|
private void didClickAdvancedOptionsButton() {
|
|
|
messageText.setText(null);
|
|
|
+ downloadsPageLink.setManaged(false);
|
|
|
advancedOptions.setVisible(!advancedOptions.isVisible());
|
|
|
if (advancedOptions.isVisible()) {
|
|
|
advancedOptionsButton.setText(localization.getString("unlock.button.advancedOptions.hide"));
|
|
@@ -355,6 +352,13 @@ public class UnlockController implements ViewController {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ @FXML
|
|
|
+ public void didClickCustomWinDriveLetterCheckbox() {
|
|
|
+ if (!useCustomWinDriveLetter.isSelected()) {
|
|
|
+ winDriveLetter.setValue(null);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* Converts 'C' to "C:" to translate between model and GUI.
|
|
|
*/
|
|
@@ -404,7 +408,7 @@ public class UnlockController implements ViewController {
|
|
|
private void chooseSelectedDriveLetter() {
|
|
|
assert SystemUtils.IS_OS_WINDOWS;
|
|
|
// if the vault prefers a drive letter, that is currently occupied, this is our last chance to reset this:
|
|
|
- if (driveLetters.getOccupiedDriveLetters().contains(vault.getWinDriveLetter())) {
|
|
|
+ if (vault.getWinDriveLetter() != null && driveLetters.getOccupiedDriveLetters().contains(vault.getWinDriveLetter())) {
|
|
|
vault.setWinDriveLetter(null);
|
|
|
}
|
|
|
final Character letter = vault.getWinDriveLetter();
|
|
@@ -453,10 +457,9 @@ public class UnlockController implements ViewController {
|
|
|
|
|
|
@FXML
|
|
|
private void didClickUnlockButton() {
|
|
|
- advancedOptions.setDisable(true);
|
|
|
- advancedOptions.setVisible(false);
|
|
|
+ unlocking.set(true);
|
|
|
advancedOptionsButton.setText(localization.getString("unlock.button.advancedOptions.show"));
|
|
|
- progressIndicator.setVisible(true);
|
|
|
+ unlockButton.setContentDisplay(ContentDisplay.LEFT);
|
|
|
|
|
|
CharSequence password = passwordField.getCharacters();
|
|
|
Tasks.create(() -> {
|
|
@@ -465,22 +468,23 @@ public class UnlockController implements ViewController {
|
|
|
keychainAccess.get().storePassphrase(vault.getId(), password);
|
|
|
}
|
|
|
}).onSuccess(() -> {
|
|
|
- messageText.setText("");
|
|
|
- downloadsPageLink.setVisible(false);
|
|
|
+ messageText.setText(null);
|
|
|
+ downloadsPageLink.setManaged(false);
|
|
|
listener.ifPresent(lstnr -> lstnr.didUnlock(vault));
|
|
|
passwordField.swipe();
|
|
|
}).onError(InvalidPassphraseException.class, e -> {
|
|
|
messageText.setText(localization.getString("unlock.errorMessage.wrongPassword"));
|
|
|
+ downloadsPageLink.setManaged(false);
|
|
|
passwordField.selectAll();
|
|
|
passwordField.requestFocus();
|
|
|
}).onError(UnsupportedVaultFormatException.class, e -> {
|
|
|
if (e.isVaultOlderThanSoftware()) {
|
|
|
// whitespace after localized text used as separator between text and hyperlink
|
|
|
messageText.setText(localization.getString("unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware") + " ");
|
|
|
- downloadsPageLink.setVisible(true);
|
|
|
+ downloadsPageLink.setManaged(true);
|
|
|
} else if (e.isSoftwareOlderThanVault()) {
|
|
|
messageText.setText(localization.getString("unlock.errorMessage.unsupportedVersion.softwareOlderThanVault") + " ");
|
|
|
- downloadsPageLink.setVisible(true);
|
|
|
+ downloadsPageLink.setManaged(true);
|
|
|
} else if (e.getDetectedVersion() == Integer.MAX_VALUE) {
|
|
|
messageText.setText(localization.getString("unlock.errorMessage.unauthenticVersionMac"));
|
|
|
}
|
|
@@ -488,18 +492,21 @@ public class UnlockController implements ViewController {
|
|
|
LOG.error("Unlock failed. Mount point not a directory: {}", e.getMessage());
|
|
|
advancedOptions.setVisible(true);
|
|
|
messageText.setText(null);
|
|
|
+ downloadsPageLink.setManaged(false);
|
|
|
showUnlockFailedErrorDialog("unlock.failedDialog.content.mountPathNonExisting");
|
|
|
}).onError(DirectoryNotEmptyException.class, e -> {
|
|
|
LOG.error("Unlock failed. Mount point not empty: {}", e.getMessage());
|
|
|
advancedOptions.setVisible(true);
|
|
|
messageText.setText(null);
|
|
|
+ downloadsPageLink.setManaged(false);
|
|
|
showUnlockFailedErrorDialog("unlock.failedDialog.content.mountPathNotEmpty");
|
|
|
}).onError(Exception.class, e -> { // including RuntimeExceptions
|
|
|
LOG.error("Unlock failed for technical reasons.", e);
|
|
|
messageText.setText(localization.getString("unlock.errorMessage.unlockFailed"));
|
|
|
+ downloadsPageLink.setManaged(false);
|
|
|
}).andFinally(() -> {
|
|
|
- advancedOptions.setDisable(false);
|
|
|
- progressIndicator.setVisible(false);
|
|
|
+ unlocking.set(false);
|
|
|
+ unlockButton.setContentDisplay(ContentDisplay.TEXT_ONLY);
|
|
|
}).runOnce(executor);
|
|
|
}
|
|
|
|