diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockedController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockedController.java index 509b07b17..ff8a57028 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockedController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockedController.java @@ -10,10 +10,12 @@ package org.cryptomator.ui.controllers; import static java.lang.String.format; +import java.io.IOException; import java.util.Optional; import javax.inject.Inject; +import org.cryptomator.frontend.webdav.ServerLifecycleException; import org.cryptomator.frontend.webdav.mount.Mounter.CommandFailedException; import org.cryptomator.ui.l10n.Localization; import org.cryptomator.ui.model.Vault; @@ -23,6 +25,8 @@ import org.fxmisc.easybind.EasyBind; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.util.concurrent.Runnables; + import javafx.animation.Animation; import javafx.animation.KeyFrame; import javafx.animation.Timeline; @@ -82,6 +86,9 @@ public class UnlockedController implements ViewController { @FXML private MenuItem mountVaultMenuItem; + @FXML + private MenuItem unmountVaultMenuItem; + @FXML private MenuItem revealVaultMenuItem; @@ -96,8 +103,9 @@ public class UnlockedController implements ViewController { @Override public void initialize() { - revealVaultMenuItem.disableProperty().bind(vaultMounted.not()); mountVaultMenuItem.disableProperty().bind(vaultMounted); + unmountVaultMenuItem.disableProperty().bind(vaultMounted.not()); + revealVaultMenuItem.disableProperty().bind(vaultMounted.not()); EasyBind.subscribe(vault, this::vaultChanged); EasyBind.subscribe(moreOptionsMenu.showingProperty(), moreOptionsButton::setSelected); @@ -124,61 +132,16 @@ public class UnlockedController implements ViewController { @FXML private void didClickLockVault(ActionEvent event) { - regularLockVault(); + regularUnmountVault(this::lockVault); } - private void regularLockVault() { - asyncTaskService.asyncTaskOf(() -> { - vault.get().unmount(); + private void lockVault() { + try { vault.get().lock(); - }).onSuccess(() -> { - listener.ifPresent(listener -> listener.didLock(this)); - LOG.trace("Regular lock succeeded"); - }).onError(Exception.class, e -> { - onRegularLockVaultFailed(e); - }).run(); - } - - private void forcedLockVault() { - asyncTaskService.asyncTaskOf(() -> { - vault.get().unmountForced(); - vault.get().lock(); - }).onSuccess(() -> { - listener.ifPresent(listener -> listener.didLock(this)); - LOG.trace("Forced lock succeeded"); - }).onError(Exception.class, e -> { - onForcedLockVaultFailed(e); - }).run(); - } - - private void onRegularLockVaultFailed(Exception e) { - if (vault.get().supportsForcedUnmount()) { - LOG.trace("Regular unmount failed", e); - Alert confirmDialog = DialogBuilderUtil.buildYesNoDialog( // - format(localization.getString("unlocked.lock.force.confirmation.title"), vault.get().name().getValue()), // - localization.getString("unlocked.lock.force.confirmation.header"), // - localization.getString("unlocked.lock.force.confirmation.content"), // - ButtonType.NO); - - Optional choice = confirmDialog.showAndWait(); - if (ButtonType.YES.equals(choice.get())) { - forcedLockVault(); - } else { - LOG.trace("Unmount cancelled", e); - } - } else { - LOG.error("Regular unmount failed", e); - showUnmountFailedMessage(); + } catch (ServerLifecycleException | IOException e) { + LOG.error("Lock failed", e); } - } - - private void onForcedLockVaultFailed(Exception e) { - LOG.error("Forced unmount failed", e); - showUnmountFailedMessage(); - } - - private void showUnmountFailedMessage() { - messageLabel.setText(localization.getString("unlocked.label.unmountFailed")); + listener.ifPresent(listener -> listener.didLock(this)); } @FXML @@ -200,16 +163,67 @@ public class UnlockedController implements ViewController { asyncTaskService.asyncTaskOf(() -> { vault.mount(); }).onSuccess(() -> { + LOG.trace("Mount succeeded."); messageLabel.setText(null); if (vault.getVaultSettings().revealAfterMount().get()) { revealVault(vault); } }).onError(CommandFailedException.class, e -> { + LOG.error("Mount failed.", e); // TODO Markus Kreusch #393: hyperlink auf FAQ oder sowas? messageLabel.setText(localization.getString("unlocked.label.mountFailed")); }).run(); } + @FXML + public void didClickUnmountVault(ActionEvent event) { + regularUnmountVault(Runnables.doNothing()); + } + + private void regularUnmountVault(Runnable onSuccess) { + asyncTaskService.asyncTaskOf(() -> { + vault.get().unmount(); + }).onSuccess(() -> { + LOG.trace("Regular unmount succeeded."); + onSuccess.run(); + }).onError(Exception.class, e -> { + onRegularUnmountVaultFailed(e, onSuccess); + }).run(); + } + + private void forcedUnmountVault(Runnable onSuccess) { + asyncTaskService.asyncTaskOf(() -> { + vault.get().unmountForced(); + }).onSuccess(() -> { + LOG.trace("Forced unmount succeeded."); + onSuccess.run(); + }).onError(Exception.class, e -> { + LOG.error("Forced unmount failed.", e); + messageLabel.setText(localization.getString("unlocked.label.unmountFailed")); + }).run(); + } + + private void onRegularUnmountVaultFailed(Exception e, Runnable onSuccess) { + if (vault.get().supportsForcedUnmount()) { + LOG.trace("Regular unmount failed.", e); + Alert confirmDialog = DialogBuilderUtil.buildYesNoDialog( // + format(localization.getString("unlocked.lock.force.confirmation.title"), vault.get().name().getValue()), // + localization.getString("unlocked.lock.force.confirmation.header"), // + localization.getString("unlocked.lock.force.confirmation.content"), // + ButtonType.NO); + + Optional choice = confirmDialog.showAndWait(); + if (ButtonType.YES.equals(choice.get())) { + forcedUnmountVault(onSuccess); + } else { + LOG.trace("Unmount cancelled.", e); + } + } else { + LOG.error("Regular unmount failed.", e); + messageLabel.setText(localization.getString("unlocked.label.unmountFailed")); + } + } + @FXML private void didClickRevealVault(ActionEvent event) { revealVault(vault.get()); @@ -219,8 +233,10 @@ public class UnlockedController implements ViewController { asyncTaskService.asyncTaskOf(() -> { vault.reveal(); }).onSuccess(() -> { + LOG.trace("Reveal succeeded."); messageLabel.setText(null); - }).onError(CommandFailedException.class, () -> { + }).onError(CommandFailedException.class, e -> { + LOG.error("Reveal failed.", e); messageLabel.setText(localization.getString("unlocked.label.revealFailed")); }).run(); } diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java b/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java index 07d3ccc74..c7c4c9224 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java @@ -162,7 +162,7 @@ public class Vault { return mount != null && mount.forced().isPresent(); } - public synchronized void lock() throws Exception { + public synchronized void lock() throws ServerLifecycleException, IOException { if (servlet != null) { servlet.stop(); } diff --git a/main/ui/src/main/resources/fxml/unlocked.fxml b/main/ui/src/main/resources/fxml/unlocked.fxml index 72eec0a7b..c29268378 100644 --- a/main/ui/src/main/resources/fxml/unlocked.fxml +++ b/main/ui/src/main/resources/fxml/unlocked.fxml @@ -31,6 +31,9 @@ + + + diff --git a/main/ui/src/main/resources/localization/en.txt b/main/ui/src/main/resources/localization/en.txt index 716e58b35..3cad2a15d 100644 --- a/main/ui/src/main/resources/localization/en.txt +++ b/main/ui/src/main/resources/localization/en.txt @@ -90,6 +90,7 @@ changePassword.errorMessage.decryptionFailed=Decryption failed # unlocked.fxml unlocked.button.lock=Lock Vault unlocked.moreOptions.mount=Mount Drive +unlocked.moreOptions.unmount=Eject Drive unlocked.moreOptions.reveal=Reveal Drive unlocked.moreOptions.copyUrl=Copy WebDAV URL unlocked.label.mountFailed=Connecting drive failed