From bcf2a3d20cc57425db4df996a25e151e9b6eba92 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 18 Nov 2020 17:16:43 +0100 Subject: [PATCH 01/48] Setting default onFailed handler in lock tasks --- .../ui/src/main/java/org/cryptomator/ui/common/VaultService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/main/ui/src/main/java/org/cryptomator/ui/common/VaultService.java b/main/ui/src/main/java/org/cryptomator/ui/common/VaultService.java index 35ed49870..1f4ffc3fd 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/common/VaultService.java +++ b/main/ui/src/main/java/org/cryptomator/ui/common/VaultService.java @@ -65,6 +65,7 @@ public class VaultService { public Task createLockTask(Vault vault, boolean forced) { Task task = new LockVaultTask(vault, forced); task.setOnSucceeded(evt -> LOG.info("Locked {}", vault.getDisplayName())); + task.setOnFailed(evt -> LOG.info("Failed to lock {}.", vault.getDisplayName(), evt.getSource().getException())); return task; } From c44911dcac8a3936a27b789466de0c03a6978837 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 18 Nov 2020 17:16:58 +0100 Subject: [PATCH 02/48] Prepare strucutre and classes for lock workflow --- .../cryptomator/ui/fxapp/FxApplication.java | 7 ++++ .../cryptomator/ui/lock/LockComponent.java | 39 +++++++++++++++++++ .../ui/lock/LockForcedController.java | 5 +++ .../org/cryptomator/ui/lock/LockModule.java | 8 ++++ .../org/cryptomator/ui/lock/LockScoped.java | 13 +++++++ .../org/cryptomator/ui/lock/LockWindow.java | 14 +++++++ .../org/cryptomator/ui/lock/LockWorkflow.java | 11 ++++++ 7 files changed, 97 insertions(+) create mode 100644 main/ui/src/main/java/org/cryptomator/ui/lock/LockComponent.java create mode 100644 main/ui/src/main/java/org/cryptomator/ui/lock/LockForcedController.java create mode 100644 main/ui/src/main/java/org/cryptomator/ui/lock/LockModule.java create mode 100644 main/ui/src/main/java/org/cryptomator/ui/lock/LockScoped.java create mode 100644 main/ui/src/main/java/org/cryptomator/ui/lock/LockWindow.java create mode 100644 main/ui/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java diff --git a/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java b/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java index 650254649..643d7827d 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java +++ b/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java @@ -107,6 +107,13 @@ public class FxApplication extends Application { }); } + public void startLockWorkflow(Vault vault, Optional owner) { + Platform.runLater(() -> { + //TODO + LOG.debug("Locking vault {}", vault.getDisplayName()); + }); + } + public void showQuitWindow(QuitResponse response) { Platform.runLater(() -> { quitWindowBuilderProvider.get().quitResponse(response).build().showQuitWindow(); diff --git a/main/ui/src/main/java/org/cryptomator/ui/lock/LockComponent.java b/main/ui/src/main/java/org/cryptomator/ui/lock/LockComponent.java new file mode 100644 index 000000000..a348d4807 --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/lock/LockComponent.java @@ -0,0 +1,39 @@ +package org.cryptomator.ui.lock; + +import dagger.BindsInstance; +import dagger.Subcomponent; +import org.cryptomator.common.vaults.Vault; + +import javax.inject.Named; +import javafx.stage.Stage; +import java.util.Optional; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; + + +@LockScoped +@Subcomponent(modules = {LockModule.class}) +public interface LockComponent { + + ExecutorService defaultExecutorService(); + + LockWorkflow lockWorkflow(); + + default Future startUnlockWorkflow() { + LockWorkflow workflow = lockWorkflow(); + defaultExecutorService().submit(workflow); + return workflow; + } + + @Subcomponent.Builder + interface Builder { + + @BindsInstance + LockComponent.Builder vault(@LockWindow Vault vault); + + @BindsInstance + LockComponent.Builder owner(@Named("lockWindowOwner") Optional owner); + + LockComponent build(); + } +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/lock/LockForcedController.java b/main/ui/src/main/java/org/cryptomator/ui/lock/LockForcedController.java new file mode 100644 index 000000000..a5746082d --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/lock/LockForcedController.java @@ -0,0 +1,5 @@ +package org.cryptomator.ui.lock; + +public class LockForcedController { + +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/lock/LockModule.java b/main/ui/src/main/java/org/cryptomator/ui/lock/LockModule.java new file mode 100644 index 000000000..a4ccc97cd --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/lock/LockModule.java @@ -0,0 +1,8 @@ +package org.cryptomator.ui.lock; + +import dagger.Module; + +@Module +public class LockModule { + +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/lock/LockScoped.java b/main/ui/src/main/java/org/cryptomator/ui/lock/LockScoped.java new file mode 100644 index 000000000..68d05f6e0 --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/lock/LockScoped.java @@ -0,0 +1,13 @@ +package org.cryptomator.ui.lock; + +import javax.inject.Scope; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Scope +@Documented +@Retention(RetentionPolicy.RUNTIME) +@interface LockScoped { + +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/lock/LockWindow.java b/main/ui/src/main/java/org/cryptomator/ui/lock/LockWindow.java new file mode 100644 index 000000000..10d6445ab --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/lock/LockWindow.java @@ -0,0 +1,14 @@ +package org.cryptomator.ui.lock; + +import javax.inject.Qualifier; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Qualifier +@Documented +@Retention(RUNTIME) +@interface LockWindow { + +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java b/main/ui/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java new file mode 100644 index 000000000..b038fea4b --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java @@ -0,0 +1,11 @@ +package org.cryptomator.ui.lock; + +import javafx.concurrent.Task; + +public class LockWorkflow extends Task { + + @Override + protected Boolean call() throws Exception { + return true; + } +} From 57bfa3276dcd44f266021965f1b08fe01319554f Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Thu, 19 Nov 2020 11:42:00 +0100 Subject: [PATCH 03/48] Integrate new lockWorkflow into application (gui and tray) --- .../cryptomator/ui/fxapp/FxApplication.java | 7 +- .../ui/fxapp/FxApplicationModule.java | 3 +- .../cryptomator/ui/lock/LockComponent.java | 2 +- .../org/cryptomator/ui/lock/LockWorkflow.java | 72 ++++++++++++++++++- .../VaultDetailUnlockedController.java | 12 +++- .../ui/traymenu/TrayMenuController.java | 2 +- 6 files changed, 89 insertions(+), 9 deletions(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java b/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java index 643d7827d..18c9a499c 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java +++ b/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java @@ -12,6 +12,7 @@ import org.cryptomator.integrations.uiappearance.UiAppearanceException; import org.cryptomator.integrations.uiappearance.UiAppearanceListener; import org.cryptomator.integrations.uiappearance.UiAppearanceProvider; import org.cryptomator.ui.common.VaultService; +import org.cryptomator.ui.lock.LockComponent; import org.cryptomator.ui.mainwindow.MainWindowComponent; import org.cryptomator.ui.preferences.PreferencesComponent; import org.cryptomator.ui.preferences.SelectedPreferencesTab; @@ -41,6 +42,7 @@ public class FxApplication extends Application { private final Lazy mainWindow; private final Lazy preferencesWindow; private final Provider unlockWindowBuilderProvider; + private final Provider lockWindowBuilderProvider; private final Provider quitWindowBuilderProvider; private final Optional trayIntegration; private final Optional appearanceProvider; @@ -50,11 +52,12 @@ public class FxApplication extends Application { private final UiAppearanceListener systemInterfaceThemeListener = this::systemInterfaceThemeChanged; @Inject - FxApplication(Settings settings, Lazy mainWindow, Lazy preferencesWindow, Provider unlockWindowBuilderProvider, Provider quitWindowBuilderProvider, Optional trayIntegration, Optional appearanceProvider, VaultService vaultService, LicenseHolder licenseHolder, ObservableSet visibleStages) { + FxApplication(Settings settings, Lazy mainWindow, Lazy preferencesWindow, Provider unlockWindowBuilderProvider, Provider lockWindowBuilderProvider, Provider quitWindowBuilderProvider, Optional trayIntegration, Optional appearanceProvider, VaultService vaultService, LicenseHolder licenseHolder, ObservableSet visibleStages) { this.settings = settings; this.mainWindow = mainWindow; this.preferencesWindow = preferencesWindow; this.unlockWindowBuilderProvider = unlockWindowBuilderProvider; + this.lockWindowBuilderProvider = lockWindowBuilderProvider; this.quitWindowBuilderProvider = quitWindowBuilderProvider; this.trayIntegration = trayIntegration; this.appearanceProvider = appearanceProvider; @@ -109,7 +112,7 @@ public class FxApplication extends Application { public void startLockWorkflow(Vault vault, Optional owner) { Platform.runLater(() -> { - //TODO + lockWindowBuilderProvider.get().vault(vault).owner(owner).build().startLockWorkflow(); LOG.debug("Locking vault {}", vault.getDisplayName()); }); } diff --git a/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java b/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java index a6297ce4a..39b3020be 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java @@ -11,6 +11,7 @@ import dagger.Provides; import org.apache.commons.lang3.SystemUtils; import org.cryptomator.ui.common.ErrorComponent; import org.cryptomator.ui.common.StageFactory; +import org.cryptomator.ui.lock.LockComponent; import org.cryptomator.ui.mainwindow.MainWindowComponent; import org.cryptomator.ui.preferences.PreferencesComponent; import org.cryptomator.ui.quit.QuitComponent; @@ -28,7 +29,7 @@ import java.io.UncheckedIOException; import java.util.Collections; import java.util.List; -@Module(includes = {UpdateCheckerModule.class}, subcomponents = {MainWindowComponent.class, PreferencesComponent.class, UnlockComponent.class, QuitComponent.class, ErrorComponent.class}) +@Module(includes = {UpdateCheckerModule.class}, subcomponents = {MainWindowComponent.class, PreferencesComponent.class, UnlockComponent.class, LockComponent.class, QuitComponent.class, ErrorComponent.class}) abstract class FxApplicationModule { @Provides diff --git a/main/ui/src/main/java/org/cryptomator/ui/lock/LockComponent.java b/main/ui/src/main/java/org/cryptomator/ui/lock/LockComponent.java index a348d4807..972ebc5f9 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/lock/LockComponent.java +++ b/main/ui/src/main/java/org/cryptomator/ui/lock/LockComponent.java @@ -19,7 +19,7 @@ public interface LockComponent { LockWorkflow lockWorkflow(); - default Future startUnlockWorkflow() { + default Future startLockWorkflow() { LockWorkflow workflow = lockWorkflow(); defaultExecutorService().submit(workflow); return workflow; diff --git a/main/ui/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java b/main/ui/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java index b038fea4b..381c6fdb9 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java +++ b/main/ui/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java @@ -1,11 +1,81 @@ package org.cryptomator.ui.lock; +import org.cryptomator.common.vaults.Vault; +import org.cryptomator.common.vaults.VaultState; +import org.cryptomator.common.vaults.Volume; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; import javafx.concurrent.Task; public class LockWorkflow extends Task { + private static final Logger LOG = LoggerFactory.getLogger(LockWorkflow.class); + + private final Vault vault; + + @Inject + public LockWorkflow(@LockWindow Vault vault) { + this.vault = vault; + } + @Override protected Boolean call() throws Exception { - return true; + // change vault state to processing -- done by overriding scheduled method of Task + if (attemptLock() || attemptForcedLock()) { + handleSuccess(); + return true; + } else { + //canceled -- for error the overriden failed() method is responsible + return false; + } } + + private boolean attemptLock() { + try { + vault.lock(false); + return true; + } catch (Volume.VolumeException e) { + e.printStackTrace(); + return false; + } + } + + 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 void handleSuccess() { + LOG.info("Lock of {} succeeded.", vault.getDisplayName()); + // set vault state to locked + } + + @Override + protected void scheduled() { + vault.setState(VaultState.PROCESSING); + } + + @Override + protected void succeeded() { + vault.setState(VaultState.LOCKED); + } + + @Override + protected void failed() { + LOG.info("Failed to lock {}.", vault.getDisplayName()); + vault.setState(VaultState.UNLOCKED); + } + + @Override + protected void cancelled() { + vault.setState(VaultState.UNLOCKED); + } + } diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnlockedController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnlockedController.java index 1806d9e5e..0af909bbc 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnlockedController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnlockedController.java @@ -6,25 +6,32 @@ import com.google.common.cache.LoadingCache; import org.cryptomator.common.vaults.Vault; import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.common.VaultService; +import org.cryptomator.ui.fxapp.FxApplication; import org.cryptomator.ui.stats.VaultStatisticsComponent; import javax.inject.Inject; import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyObjectProperty; import javafx.fxml.FXML; +import javafx.stage.Stage; +import java.util.Optional; @MainWindowScoped public class VaultDetailUnlockedController implements FxController { private final ReadOnlyObjectProperty vault; + private final FxApplication application; private final VaultService vaultService; + private final Stage mainWindow; private final LoadingCache vaultStats; private final VaultStatisticsComponent.Builder vaultStatsBuilder; @Inject - public VaultDetailUnlockedController(ObjectProperty vault, VaultService vaultService, VaultStatisticsComponent.Builder vaultStatsBuilder) { + public VaultDetailUnlockedController(ObjectProperty vault, FxApplication application, VaultService vaultService, VaultStatisticsComponent.Builder vaultStatsBuilder, @MainWindow Stage mainWindow) { this.vault = vault; + this.application = application; this.vaultService = vaultService; + this.mainWindow = mainWindow; this.vaultStats = CacheBuilder.newBuilder().weakValues().build(CacheLoader.from(this::buildVaultStats)); this.vaultStatsBuilder = vaultStatsBuilder; } @@ -40,8 +47,7 @@ public class VaultDetailUnlockedController implements FxController { @FXML public void lock() { - vaultService.lock(vault.get(), false); - // TODO count lock attempts, and allow forced lock + application.startLockWorkflow(vault.get(), Optional.of(mainWindow)); } @FXML diff --git a/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayMenuController.java b/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayMenuController.java index 51f7c2225..a65f1e493 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayMenuController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayMenuController.java @@ -108,7 +108,7 @@ class TrayMenuController { } private void lockVault(Vault vault) { - fxApplicationStarter.get(true).thenAccept(app -> app.getVaultService().lock(vault, false)); + fxApplicationStarter.get(true).thenAccept(app -> app.startLockWorkflow(vault, Optional.empty())); } private void lockAllVaults(ActionEvent actionEvent) { From 432a9a27f1b073fe611dee32a8ec4de49bdd976c Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Thu, 19 Nov 2020 12:52:16 +0100 Subject: [PATCH 04/48] Add forceLock Dialogue: * integrate it in workflow if normal lock throws exception * add stubs if also forced lock fails --- .../org/cryptomator/ui/common/FxmlFile.java | 2 + .../ui/lock/LockFailedController.java | 14 ++++ .../ui/lock/LockForcedController.java | 45 +++++++++- .../org/cryptomator/ui/lock/LockModule.java | 83 ++++++++++++++++++- .../org/cryptomator/ui/lock/LockWorkflow.java | 55 +++++++++--- .../src/main/resources/fxml/lock_failed.fxml | 20 +++++ .../src/main/resources/fxml/lock_forced.fxml | 40 +++++++++ 7 files changed, 245 insertions(+), 14 deletions(-) create mode 100644 main/ui/src/main/java/org/cryptomator/ui/lock/LockFailedController.java create mode 100644 main/ui/src/main/resources/fxml/lock_failed.fxml create mode 100644 main/ui/src/main/resources/fxml/lock_forced.fxml diff --git a/main/ui/src/main/java/org/cryptomator/ui/common/FxmlFile.java b/main/ui/src/main/java/org/cryptomator/ui/common/FxmlFile.java index 43074a605..310e11747 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/common/FxmlFile.java +++ b/main/ui/src/main/java/org/cryptomator/ui/common/FxmlFile.java @@ -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"), diff --git a/main/ui/src/main/java/org/cryptomator/ui/lock/LockFailedController.java b/main/ui/src/main/java/org/cryptomator/ui/lock/LockFailedController.java new file mode 100644 index 000000000..66dd203ea --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/lock/LockFailedController.java @@ -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() { + + } + +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/lock/LockForcedController.java b/main/ui/src/main/java/org/cryptomator/ui/lock/LockForcedController.java index a5746082d..a66af9902 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/lock/LockForcedController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/lock/LockForcedController.java @@ -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 forceLockDecisionLock; + + @Inject + public LockForcedController(@LockWindow Stage window, @LockWindow Vault vault, UserInteractionLock 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); + } + } } diff --git a/main/ui/src/main/java/org/cryptomator/ui/lock/LockModule.java b/main/ui/src/main/java/org/cryptomator/ui/lock/LockModule.java index a4ccc97cd..bbc8c2209 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/lock/LockModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/lock/LockModule.java @@ -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 provideForceLockDecisionLock() { + return new UserInteractionLock<>(null); + } + + @Provides + @LockWindow + @LockScoped + static FXMLLoaderFactory provideFxmlLoaderFactory(Map, Provider> 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 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); } diff --git a/main/ui/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java b/main/ui/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java index 381c6fdb9..d63661e02 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java +++ b/main/ui/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java @@ -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 { private static final Logger LOG = LoggerFactory.getLogger(LockWorkflow.class); + private final Stage lockWindow; private final Vault vault; + private final UserInteractionLock forceLockDecisionLock; + private final Lazy lockForcedScene; + private final Lazy lockFailedScene; @Inject - public LockWorkflow(@LockWindow Vault vault) { + public LockWorkflow(@LockWindow Stage lockWindow, @LockWindow Vault vault, UserInteractionLock forceLockDecisionLock, @FxmlScene(FxmlFile.LOCK_FORCED) Lazy lockForcedScene, @FxmlScene(FxmlFile.LOCK_FAILED) Lazy 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 { } } - 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 diff --git a/main/ui/src/main/resources/fxml/lock_failed.fxml b/main/ui/src/main/resources/fxml/lock_failed.fxml new file mode 100644 index 000000000..9b4e0a2b9 --- /dev/null +++ b/main/ui/src/main/resources/fxml/lock_failed.fxml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + diff --git a/main/ui/src/main/resources/fxml/lock_forced.fxml b/main/ui/src/main/resources/fxml/lock_forced.fxml new file mode 100644 index 000000000..be311261d --- /dev/null +++ b/main/ui/src/main/resources/fxml/lock_forced.fxml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + - -