mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-22 12:41:27 +00:00
Add forceLock Dialogue:
* integrate it in workflow if normal lock throws exception * add stubs if also forced lock fails
This commit is contained in:
@@ -11,6 +11,8 @@ public enum FxmlFile {
|
||||
CHANGEPASSWORD("/fxml/changepassword.fxml"), //
|
||||
ERROR("/fxml/error.fxml"), //
|
||||
FORGET_PASSWORD("/fxml/forget_password.fxml"), //
|
||||
LOCK_FORCED("/fxml/lock_forced.fxml"), //
|
||||
LOCK_FAILED("/fxml/lock_failed.fxml"), //
|
||||
MAIN_WINDOW("/fxml/main_window.fxml"), //
|
||||
MIGRATION_CAPABILITY_ERROR("/fxml/migration_capability_error.fxml"), //
|
||||
MIGRATION_IMPOSSIBLE("/fxml/migration_impossible.fxml"),
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package org.cryptomator.ui.lock;
|
||||
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class LockFailedController implements FxController {
|
||||
|
||||
@Inject
|
||||
public LockFailedController() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,48 @@
|
||||
package org.cryptomator.ui.lock;
|
||||
|
||||
public class LockForcedController {
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.UserInteractionLock;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.WindowEvent;
|
||||
|
||||
public class LockForcedController implements FxController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(LockForcedController.class);
|
||||
|
||||
private final Stage window;
|
||||
private final Vault vault;
|
||||
private final UserInteractionLock<LockModule.ForceLockDecision> forceLockDecisionLock;
|
||||
|
||||
@Inject
|
||||
public LockForcedController(@LockWindow Stage window, @LockWindow Vault vault, UserInteractionLock<LockModule.ForceLockDecision> forceLockDecisionLock) {
|
||||
this.window = window;
|
||||
this.vault = vault;
|
||||
this.forceLockDecisionLock = forceLockDecisionLock;
|
||||
this.window.setOnHiding(this::windowClosed);
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
forceLockDecisionLock.interacted(LockModule.ForceLockDecision.CANCEL);
|
||||
window.close();
|
||||
}
|
||||
|
||||
public void confirmForcedLock(ActionEvent actionEvent) {
|
||||
forceLockDecisionLock.interacted(LockModule.ForceLockDecision.FORCE);
|
||||
window.close();
|
||||
}
|
||||
|
||||
private void windowClosed(WindowEvent windowEvent) {
|
||||
// if not already interacted, mark this workflow as cancelled:
|
||||
if (forceLockDecisionLock.awaitingInteraction().get()) {
|
||||
LOG.debug("Lock canceled in force-lock-phase by user.");
|
||||
forceLockDecisionLock.interacted(LockModule.ForceLockDecision.CANCEL);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,89 @@
|
||||
package org.cryptomator.ui.lock;
|
||||
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||
import org.cryptomator.ui.common.FXMLLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.common.StageFactory;
|
||||
import org.cryptomator.ui.common.UserInteractionLock;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
@Module
|
||||
public class LockModule {
|
||||
abstract class LockModule {
|
||||
|
||||
enum ForceLockDecision {
|
||||
CANCEL,
|
||||
FORCE;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@LockScoped
|
||||
static UserInteractionLock<LockModule.ForceLockDecision> provideForceLockDecisionLock() {
|
||||
return new UserInteractionLock<>(null);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@LockWindow
|
||||
@LockScoped
|
||||
static FXMLLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FXMLLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@LockWindow
|
||||
@LockScoped
|
||||
static Stage provideWindow(StageFactory factory, @LockWindow Vault vault, @Named("lockWindowOwner") Optional<Stage> owner) {
|
||||
Stage stage = factory.create();
|
||||
stage.setTitle(vault.getDisplayName());
|
||||
stage.setResizable(false);
|
||||
if (owner.isPresent()) {
|
||||
stage.initOwner(owner.get());
|
||||
stage.initModality(Modality.WINDOW_MODAL);
|
||||
} else {
|
||||
stage.initModality(Modality.APPLICATION_MODAL);
|
||||
}
|
||||
return stage;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.LOCK_FORCED)
|
||||
@LockScoped
|
||||
static Scene provideForceLockScene(@LockWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/lock_forced.fxml");
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.LOCK_FAILED)
|
||||
@LockScoped
|
||||
static Scene provideLockFailedScene(@LockWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/lock_failed.fxml");
|
||||
}
|
||||
|
||||
// ------------------
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(LockForcedController.class)
|
||||
abstract FxController bindLockForcedController(LockForcedController controller);
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(LockFailedController.class)
|
||||
abstract FxController bindLockFailedController(LockFailedController controller);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,27 +1,43 @@
|
||||
package org.cryptomator.ui.lock;
|
||||
|
||||
import dagger.Lazy;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.common.vaults.VaultState;
|
||||
import org.cryptomator.common.vaults.Volume;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.common.UserInteractionLock;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.application.Platform;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.Window;
|
||||
|
||||
public class LockWorkflow extends Task<Boolean> {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(LockWorkflow.class);
|
||||
|
||||
private final Stage lockWindow;
|
||||
private final Vault vault;
|
||||
private final UserInteractionLock<LockModule.ForceLockDecision> forceLockDecisionLock;
|
||||
private final Lazy<Scene> lockForcedScene;
|
||||
private final Lazy<Scene> lockFailedScene;
|
||||
|
||||
@Inject
|
||||
public LockWorkflow(@LockWindow Vault vault) {
|
||||
public LockWorkflow(@LockWindow Stage lockWindow, @LockWindow Vault vault, UserInteractionLock<LockModule.ForceLockDecision> forceLockDecisionLock, @FxmlScene(FxmlFile.LOCK_FORCED) Lazy<Scene> lockForcedScene, @FxmlScene(FxmlFile.LOCK_FAILED) Lazy<Scene> lockFailedScene) {
|
||||
this.lockWindow = lockWindow;
|
||||
this.vault = vault;
|
||||
this.forceLockDecisionLock = forceLockDecisionLock;
|
||||
this.lockForcedScene = lockForcedScene;
|
||||
this.lockFailedScene = lockFailedScene;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean call() throws Exception {
|
||||
protected Boolean call() throws Volume.VolumeException, InterruptedException {
|
||||
// change vault state to processing -- done by overriding scheduled method of Task
|
||||
if (attemptLock() || attemptForcedLock()) {
|
||||
handleSuccess();
|
||||
@@ -42,19 +58,34 @@ public class LockWorkflow extends Task<Boolean> {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean attemptForcedLock() {
|
||||
// show forcedLock dialogue
|
||||
// wait for answer
|
||||
// depening on answer do one of two things
|
||||
// a) force Lock -> needs to throw exception on failure
|
||||
// b) cancel
|
||||
// if lock was performed over main window, show it again
|
||||
return false;
|
||||
private boolean attemptForcedLock() throws Volume.VolumeException, InterruptedException {
|
||||
// show forcedLock dialogue ...
|
||||
Platform.runLater(() -> {
|
||||
lockWindow.setScene(lockForcedScene.get());
|
||||
lockWindow.show();
|
||||
Window owner = lockWindow.getOwner();
|
||||
if (owner != null) {
|
||||
lockWindow.setX(owner.getX() + (owner.getWidth() - lockWindow.getWidth()) / 2);
|
||||
lockWindow.setY(owner.getY() + (owner.getHeight() - lockWindow.getHeight()) / 2);
|
||||
} else {
|
||||
lockWindow.centerOnScreen();
|
||||
}
|
||||
});
|
||||
// ... and wait for answer
|
||||
switch (forceLockDecisionLock.awaitInteraction()) {
|
||||
case FORCE:
|
||||
vault.lock(true);
|
||||
return true;
|
||||
case CANCEL:
|
||||
// if lock was performed over main window, show it again
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSuccess() {
|
||||
LOG.info("Lock of {} succeeded.", vault.getDisplayName());
|
||||
// set vault state to locked
|
||||
LOG.info("Lock of {} succeeded.", vault.getDisplayName());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
20
main/ui/src/main/resources/fxml/lock_failed.fxml
Normal file
20
main/ui/src/main/resources/fxml/lock_failed.fxml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<VBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.lock.LockFailedController"
|
||||
minWidth="400"
|
||||
maxWidth="400"
|
||||
minHeight="145"
|
||||
spacing="12">
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<Label text="This is a stub." wrapText="true" textAlignment="LEFT" HBox.hgrow="ALWAYS"/>
|
||||
</children>
|
||||
</VBox>
|
||||
40
main/ui/src/main/resources/fxml/lock_forced.fxml
Normal file
40
main/ui/src/main/resources/fxml/lock_forced.fxml
Normal file
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.ButtonBar?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.Circle?>
|
||||
<VBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.lock.LockForcedController"
|
||||
minWidth="400"
|
||||
maxWidth="400"
|
||||
minHeight="145"
|
||||
spacing="12">
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<HBox spacing="12" alignment="CENTER_LEFT" VBox.vgrow="ALWAYS">
|
||||
<StackPane alignment="CENTER" HBox.hgrow="NEVER">
|
||||
<Circle styleClass="glyph-icon-orange" radius="24"/>
|
||||
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="EXCLAMATION" glyphSize="24"/>
|
||||
</StackPane>
|
||||
<Label text="Yadda yadda" wrapText="true" textAlignment="LEFT" HBox.hgrow="ALWAYS"/>
|
||||
</HBox>
|
||||
|
||||
<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+CI">
|
||||
<buttons>
|
||||
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" defaultButton="true" cancelButton="true" onAction="#cancel"/>
|
||||
<Button text="Use the FORCE, Luke!" ButtonBar.buttonData="FINISH" onAction="#confirmForcedLock"/>
|
||||
</buttons>
|
||||
</ButtonBar>
|
||||
</VBox>
|
||||
</children>
|
||||
</VBox>
|
||||
Reference in New Issue
Block a user