Lock remaining vaults on shutdown (references #838)

This commit is contained in:
Sebastian Stenzel
2019-08-06 17:03:05 +02:00
parent 04c45756b9
commit cb50b2011f
2 changed files with 87 additions and 22 deletions

View File

@@ -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> {
public ContentDisplay getQuitButtonState() {
return quitButtonState.get();
private final Iterator<Vault> vaultsToLock;
public LockAllVaultsService(Executor executor, Iterator<Vault> vaultsToLock) {
this.vaultsToLock = vaultsToLock;
setExecutor(executor);
setRestartOnFailure(false);
}
@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();
}
}
}
}

View File

@@ -23,8 +23,7 @@
<HBox>
<Button text="TODO cancel" cancelButton="true" onAction="#cancel"/>
<Region HBox.hgrow="ALWAYS"/>
<Button text="TODO force quit" cancelButton="true" onAction="#forceQuit"/>
<Button text="TODO lock and quit" defaultButton="true" onAction="#quit" contentDisplay="${controller.quitButtonState}">
<Button text="TODO lock and quit" defaultButton="true" onAction="#lockAndQuit" fx:id="lockAndQuitButton" contentDisplay="TEXT_ONLY">
<graphic>
<ProgressIndicator progress="-1" prefWidth="12" prefHeight="12"/>
</graphic>