moved mount + reveal from UnlockController to UnlockedController

This commit is contained in:
Sebastian Stenzel
2017-05-29 01:03:22 +02:00
parent 8c55946cf0
commit 4ea3e8de8b
6 changed files with 115 additions and 59 deletions

View File

@@ -21,7 +21,6 @@ import org.cryptomator.common.settings.VaultSettings;
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
import org.cryptomator.cryptolib.api.UnsupportedVaultFormatException;
import org.cryptomator.frontend.webdav.ServerLifecycleException;
import org.cryptomator.frontend.webdav.mount.Mounter.CommandFailedException;
import org.cryptomator.keychain.KeychainAccess;
import org.cryptomator.ui.controls.SecPasswordField;
import org.cryptomator.ui.l10n.Localization;
@@ -38,7 +37,6 @@ import com.google.common.base.CharMatcher;
import com.google.common.base.Strings;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
@@ -345,59 +343,42 @@ public class UnlockController implements ViewController {
private void didClickUnlockButton(ActionEvent event) {
advancedOptions.setDisable(true);
progressIndicator.setVisible(true);
downloadsPageLink.setVisible(false);
CharSequence password = passwordField.getCharacters();
asyncTaskService.asyncTaskOf(() -> this.unlock(password)).run();
}
private void unlock(CharSequence password) {
try {
CharSequence password = passwordField.getCharacters();
asyncTaskService.asyncTaskOf(() -> {
vault.unlock(password);
if (mountAfterUnlock.isSelected()) {
vault.mount();
if (revealAfterMount.isSelected()) {
vault.reveal();
}
}
Platform.runLater(() -> {
messageText.setText(null);
listener.ifPresent(lstnr -> lstnr.didUnlock(vault));
});
if (keychainAccess.isPresent() && savePassword.isSelected()) {
keychainAccess.get().storePassphrase(vault.getId(), password);
} else {
Platform.runLater(passwordField::swipe);
}
} catch (InvalidPassphraseException e) {
Platform.runLater(() -> {
messageText.setText(localization.getString("unlock.errorMessage.wrongPassword"));
passwordField.selectAll();
passwordField.requestFocus();
});
} catch (UnsupportedVaultFormatException e) {
Platform.runLater(() -> {
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);
} else if (e.isSoftwareOlderThanVault()) {
messageText.setText(localization.getString("unlock.errorMessage.unsupportedVersion.softwareOlderThanVault") + " ");
downloadsPageLink.setVisible(true);
} else if (e.getDetectedVersion() == Integer.MAX_VALUE) {
messageText.setText(localization.getString("unlock.errorMessage.unauthenticVersionMac"));
}
});
} catch (ServerLifecycleException | CommandFailedException e) {
}).onSuccess(() -> {
messageText.setText(null);
downloadsPageLink.setVisible(false);
listener.ifPresent(lstnr -> lstnr.didUnlock(vault));
}).onError(InvalidPassphraseException.class, e -> {
messageText.setText(localization.getString("unlock.errorMessage.wrongPassword"));
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);
} else if (e.isSoftwareOlderThanVault()) {
messageText.setText(localization.getString("unlock.errorMessage.unsupportedVersion.softwareOlderThanVault") + " ");
downloadsPageLink.setVisible(true);
} else if (e.getDetectedVersion() == Integer.MAX_VALUE) {
messageText.setText(localization.getString("unlock.errorMessage.unauthenticVersionMac"));
}
}).onError(ServerLifecycleException.class, e -> {
LOG.error("Unlock failed for technical reasons.", e);
Platform.runLater(() -> {
messageText.setText(localization.getString("unlock.errorMessage.mountingFailed"));
});
} finally {
Platform.runLater(() -> {
advancedOptions.setDisable(false);
progressIndicator.setVisible(false);
});
}
messageText.setText(localization.getString("unlock.errorMessage.unlockFailed"));
}).andFinally(() -> {
if (!savePassword.isSelected()) {
passwordField.swipe();
}
advancedOptions.setDisable(false);
progressIndicator.setVisible(false);
}).run();
}
/* callback */

View File

@@ -14,6 +14,7 @@ import java.util.Optional;
import javax.inject.Inject;
import org.cryptomator.frontend.webdav.mount.Mounter.CommandFailedException;
import org.cryptomator.ui.l10n.Localization;
import org.cryptomator.ui.model.Vault;
import org.cryptomator.ui.util.AsyncTaskService;
@@ -25,6 +26,7 @@ import org.slf4j.LoggerFactory;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.beans.binding.BooleanExpression;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.event.ActionEvent;
@@ -58,6 +60,7 @@ public class UnlockedController implements ViewController {
private final Localization localization;
private final AsyncTaskService asyncTaskService;
private final ObjectProperty<Vault> vault = new SimpleObjectProperty<>();
private final BooleanExpression vaultMounted = BooleanExpression.booleanExpression(EasyBind.select(vault).selectObject(Vault::mountedProperty).orElse(false));
private Optional<LockListener> listener = Optional.empty();
private Timeline ioAnimation;
@@ -76,6 +79,9 @@ public class UnlockedController implements ViewController {
@FXML
private ContextMenu moreOptionsMenu;
@FXML
private MenuItem mountVaultMenuItem;
@FXML
private MenuItem revealVaultMenuItem;
@@ -90,7 +96,8 @@ public class UnlockedController implements ViewController {
@Override
public void initialize() {
revealVaultMenuItem.disableProperty().bind(EasyBind.map(vault, vault -> vault != null && !vault.isMounted()));
revealVaultMenuItem.disableProperty().bind(vaultMounted.not());
mountVaultMenuItem.disableProperty().bind(vaultMounted);
EasyBind.subscribe(vault, this::vaultChanged);
EasyBind.subscribe(moreOptionsMenu.showingProperty(), moreOptionsButton::setSelected);
@@ -106,9 +113,8 @@ public class UnlockedController implements ViewController {
return;
}
if (newVault.getVaultSettings().mountAfterUnlock().get() && !newVault.isMounted()) {
// TODO Markus Kreusch #393: hyperlink auf FAQ oder sowas?
messageLabel.setText(localization.getString("unlocked.label.mountFailed"));
if (newVault.getVaultSettings().mountAfterUnlock().get()) {
mountVault(newVault);
}
// (re)start throughput statistics:
@@ -186,11 +192,35 @@ public class UnlockedController implements ViewController {
}
@FXML
private void didClickRevealVault(ActionEvent event) {
public void didClickMountVault(ActionEvent event) {
mountVault(vault.get());
}
private void mountVault(Vault vault) {
asyncTaskService.asyncTaskOf(() -> {
vault.get().reveal();
}).onError(RuntimeException.class, () -> {
// TODO overheadhunter catch more specific exception type thrown by reveal()
vault.mount();
}).onSuccess(() -> {
messageLabel.setText(null);
if (vault.getVaultSettings().revealAfterMount().get()) {
revealVault(vault);
}
}).onError(CommandFailedException.class, e -> {
// TODO Markus Kreusch #393: hyperlink auf FAQ oder sowas?
messageLabel.setText(localization.getString("unlocked.label.mountFailed"));
}).run();
}
@FXML
private void didClickRevealVault(ActionEvent event) {
revealVault(vault.get());
}
private void revealVault(Vault vault) {
asyncTaskService.asyncTaskOf(() -> {
vault.reveal();
}).onSuccess(() -> {
messageLabel.setText(null);
}).onError(CommandFailedException.class, () -> {
messageLabel.setText(localization.getString("unlocked.label.revealFailed"));
}).run();
}

View File

@@ -33,6 +33,7 @@ import org.cryptomator.cryptofs.CryptoFileSystemProperties;
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
import org.cryptomator.cryptolib.api.CryptoException;
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
import org.cryptomator.frontend.webdav.ServerLifecycleException;
import org.cryptomator.frontend.webdav.WebDavServer;
import org.cryptomator.frontend.webdav.mount.MountParams;
import org.cryptomator.frontend.webdav.mount.Mounter.CommandFailedException;
@@ -108,7 +109,7 @@ public class Vault {
CryptoFileSystemProvider.changePassphrase(getPath(), MASTERKEY_FILENAME, oldPassphrase, newPassphrase);
}
public synchronized void unlock(CharSequence passphrase) {
public synchronized void unlock(CharSequence passphrase) throws ServerLifecycleException {
try {
FileSystem fs = getCryptoFileSystem(passphrase);
if (!server.isRunning()) {

View File

@@ -32,6 +32,12 @@ public class AsyncTaskService {
this.executor = executor;
}
/**
* Creates a new async task
*
* @param task Tasks to be invoked in a background thread.
* @return The async task
*/
public AsyncTaskWithoutSuccessHandler<Void> asyncTaskOf(RunnableThrowingException<?> task) {
return new AsyncTaskImpl<>(() -> {
task.run();
@@ -39,6 +45,12 @@ public class AsyncTaskService {
});
}
/**
* Creates a new async task
*
* @param task Tasks to be invoked in a background thread.
* @return The async task
*/
public <ResultType> AsyncTaskWithoutSuccessHandler<ResultType> asyncTaskOf(SupplierThrowingException<ResultType, ?> task) {
return new AsyncTaskImpl<>(task);
}
@@ -153,27 +165,55 @@ public class AsyncTaskService {
public interface AsyncTaskWithoutSuccessHandler<ResultType> extends AsyncTaskWithoutErrorHandler {
/**
* @param handler Tasks to be invoked on the JavaFX application thread.
* @return The async task
*/
AsyncTaskWithoutErrorHandler onSuccess(ConsumerThrowingException<ResultType, ?> handler);
/**
* @param handler Tasks to be invoked on the JavaFX application thread.
* @return The async task
*/
AsyncTaskWithoutErrorHandler onSuccess(RunnableThrowingException<?> handler);
}
public interface AsyncTaskWithoutErrorHandler extends AsyncTaskWithoutFinallyHandler {
/**
* @param type Exception type to catch
* @param handler Tasks to be invoked on the JavaFX application thread.
* @return The async task
*/
<ErrorType extends Throwable> AsyncTaskWithoutErrorHandler onError(Class<ErrorType> type, ConsumerThrowingException<ErrorType, ?> handler);
/**
* @param type Exception type to catch
* @param handler Tasks to be invoked on the JavaFX application thread.
* @return The async task
*/
<ErrorType extends Throwable> AsyncTaskWithoutErrorHandler onError(Class<ErrorType> type, RunnableThrowingException<?> handler);
}
public interface AsyncTaskWithoutFinallyHandler extends AsyncTask {
/**
* @param handler Tasks to be invoked on the JavaFX application thread.
* @return The async task
*/
AsyncTask andFinally(RunnableThrowingException<?> handler);
}
public interface AsyncTask extends Runnable {
/**
* Starts the async task.
*/
@Override
void run();
}
}

View File

@@ -28,6 +28,9 @@
<fx:define>
<ContextMenu fx:id="moreOptionsMenu">
<items>
<MenuItem fx:id="mountVaultMenuItem" text="%unlocked.moreOptions.mount" onAction="#didClickMountVault">
<graphic><Label text="&#xf139;" styleClass="ionicons"/></graphic>
</MenuItem>
<MenuItem fx:id="revealVaultMenuItem" text="%unlocked.moreOptions.reveal" onAction="#didClickRevealVault">
<graphic><Label text="&#xf133;" styleClass="ionicons"/></graphic>
</MenuItem>

View File

@@ -72,7 +72,7 @@ unlock.savePassword.delete.confirmation.header=Do you really want to delete the
unlock.savePassword.delete.confirmation.content=The saved password of this vault will be immediately deleted from your system keychain. If you'd like to save your password again, you'd have to unlock your vault with the "Save Password" option enabled.
unlock.choicebox.winDriveLetter.auto=Assign automatically
unlock.errorMessage.wrongPassword=Wrong password
unlock.errorMessage.mountingFailed=Mounting failed. See log file for details.
unlock.errorMessage.unlockFailed=Unlock failed. See log file for details.
unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware=Unsupported vault. This vault has been created with an older version of Cryptomator.
unlock.errorMessage.unsupportedVersion.softwareOlderThanVault=Unsupported vault. This vault has been created with a newer version of Cryptomator.
unlock.errorMessage.unauthenticVersionMac=Could not authenticate version MAC.
@@ -89,6 +89,7 @@ changePassword.errorMessage.decryptionFailed=Decryption failed
# unlocked.fxml
unlocked.button.lock=Lock Vault
unlocked.moreOptions.mount=Mount Drive
unlocked.moreOptions.reveal=Reveal Drive
unlocked.moreOptions.copyUrl=Copy WebDAV URL
unlocked.label.mountFailed=Connecting drive failed