|
@@ -1,16 +1,24 @@
|
|
|
package org.cryptomator.ui.quit;
|
|
|
|
|
|
-import javafx.beans.property.ObjectProperty;
|
|
|
-import javafx.beans.property.SimpleObjectProperty;
|
|
|
+import javafx.application.Platform;
|
|
|
+import javafx.collections.ObservableList;
|
|
|
+import javafx.concurrent.ScheduledService;
|
|
|
+import javafx.concurrent.Task;
|
|
|
import javafx.fxml.FXML;
|
|
|
+import javafx.scene.control.Button;
|
|
|
import javafx.scene.control.ContentDisplay;
|
|
|
import javafx.stage.Stage;
|
|
|
+import org.cryptomator.common.vaults.Vault;
|
|
|
+import org.cryptomator.common.vaults.Volume;
|
|
|
import org.cryptomator.ui.common.FxController;
|
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
import javax.inject.Inject;
|
|
|
import java.awt.desktop.QuitResponse;
|
|
|
+import java.util.Iterator;
|
|
|
+import java.util.List;
|
|
|
+import java.util.concurrent.Executor;
|
|
|
import java.util.concurrent.ExecutorService;
|
|
|
|
|
|
@QuitScoped
|
|
@@ -20,15 +28,16 @@ public class QuitController implements FxController {
|
|
|
|
|
|
private final Stage window;
|
|
|
private final QuitResponse response;
|
|
|
+ private final ObservableList<Vault> unlockedVaults;
|
|
|
private final ExecutorService executor;
|
|
|
- private final ObjectProperty<ContentDisplay> quitButtonState;
|
|
|
+ public Button lockAndQuitButton;
|
|
|
|
|
|
@Inject
|
|
|
- QuitController(@QuitWindow Stage window, QuitResponse response, ExecutorService executor) {
|
|
|
+ QuitController(@QuitWindow Stage window, QuitResponse response, ObservableList<Vault> vaults, ExecutorService executor) {
|
|
|
this.window = window;
|
|
|
this.response = response;
|
|
|
+ this.unlockedVaults = vaults.filtered(Vault::isUnlocked);
|
|
|
this.executor = executor;
|
|
|
- this.quitButtonState = new SimpleObjectProperty<>(ContentDisplay.TEXT_ONLY);
|
|
|
}
|
|
|
|
|
|
@FXML
|
|
@@ -39,26 +48,83 @@ public class QuitController implements FxController {
|
|
|
}
|
|
|
|
|
|
@FXML
|
|
|
- public void quit() {
|
|
|
- LOG.warn("Quit not yet implemented.");
|
|
|
- window.close();
|
|
|
- response.cancelQuit();
|
|
|
+ public void lockAndQuit() {
|
|
|
+ lockAndQuitButton.setDisable(true);
|
|
|
+ lockAndQuitButton.setContentDisplay(ContentDisplay.LEFT);
|
|
|
+
|
|
|
+ Iterator<Vault> toBeLocked = List.copyOf(unlockedVaults).iterator();
|
|
|
+ ScheduledService<Void> lockAllService = new LockAllVaultsService(executor, toBeLocked);
|
|
|
+ lockAllService.setOnSucceeded(evt -> {
|
|
|
+ if (!toBeLocked.hasNext()) {
|
|
|
+ window.close();
|
|
|
+ response.performQuit();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ lockAllService.setOnFailed(evt -> {
|
|
|
+ lockAndQuitButton.setDisable(false);
|
|
|
+ lockAndQuitButton.setContentDisplay(ContentDisplay.TEXT_ONLY);
|
|
|
+ // TODO: show force lock or force quit scene (and DO NOT cancelQuit() here!)
|
|
|
+ response.cancelQuit();
|
|
|
+ });
|
|
|
+ lockAllService.start();
|
|
|
}
|
|
|
|
|
|
- @FXML
|
|
|
- public void forceQuit() {
|
|
|
- LOG.warn("Force Quit not yet implemented.");
|
|
|
- window.close();
|
|
|
- response.cancelQuit();
|
|
|
+ /**
|
|
|
+ * @param vault The vault to lock
|
|
|
+ * @return Task that tries to lock the given vault gracefully.
|
|
|
+ */
|
|
|
+ private Task<Void> createGracefulLockTask(Vault vault) {
|
|
|
+ Task task = new Task<Void>() {
|
|
|
+ @Override
|
|
|
+ protected Void call() throws Volume.VolumeException {
|
|
|
+ vault.lock(false);
|
|
|
+ LOG.info("Locked {}", vault.getDisplayableName());
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ };
|
|
|
+ task.setOnSucceeded(evt -> {
|
|
|
+ vault.setState(Vault.State.LOCKED);
|
|
|
+ });
|
|
|
+ task.setOnFailed(evt -> {
|
|
|
+ LOG.warn("Failed to lock vault", vault);
|
|
|
+ });
|
|
|
+ return task;
|
|
|
}
|
|
|
|
|
|
- /* Observable Properties */
|
|
|
-
|
|
|
- public ObjectProperty<ContentDisplay> quitButtonStateProperty() {
|
|
|
- return quitButtonState;
|
|
|
+ /**
|
|
|
+ * @return Task that succeeds immediately
|
|
|
+ */
|
|
|
+ private Task<Void> createNoopTask() {
|
|
|
+ return new Task<>() {
|
|
|
+ @Override
|
|
|
+ protected Void call() {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ };
|
|
|
}
|
|
|
+
|
|
|
+ private class LockAllVaultsService extends ScheduledService<Void> {
|
|
|
+
|
|
|
+ private final Iterator<Vault> vaultsToLock;
|
|
|
+
|
|
|
+ public LockAllVaultsService(Executor executor, Iterator<Vault> vaultsToLock) {
|
|
|
+ this.vaultsToLock = vaultsToLock;
|
|
|
+ setExecutor(executor);
|
|
|
+ setRestartOnFailure(false);
|
|
|
+ }
|
|
|
|
|
|
- public ContentDisplay getQuitButtonState() {
|
|
|
- return quitButtonState.get();
|
|
|
+ @Override
|
|
|
+ protected Task<Void> createTask() {
|
|
|
+ assert Platform.isFxApplicationThread();
|
|
|
+ if (vaultsToLock.hasNext()) {
|
|
|
+ return createGracefulLockTask(vaultsToLock.next());
|
|
|
+ } else {
|
|
|
+ // This should be unreachable code, since vaultsToLock is only accessed on the FX App Thread.
|
|
|
+ // But if quitting the application takes longer for any reason, this service should shut down properly
|
|
|
+ reset();
|
|
|
+ return createNoopTask();
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
}
|