mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-18 10:41:26 +00:00
Lock remaining vaults on shutdown (references #838)
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user