From 2de151aebe463c010d51219e2d79087894ca03c0 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 18 Nov 2020 18:08:00 +0100 Subject: [PATCH 01/13] use less generic name --- .../common/mountpoint/MountPointHelper.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/main/commons/src/main/java/org/cryptomator/common/mountpoint/MountPointHelper.java b/main/commons/src/main/java/org/cryptomator/common/mountpoint/MountPointHelper.java index c72aeb44c..704f2f62d 100644 --- a/main/commons/src/main/java/org/cryptomator/common/mountpoint/MountPointHelper.java +++ b/main/commons/src/main/java/org/cryptomator/common/mountpoint/MountPointHelper.java @@ -20,11 +20,10 @@ import java.util.Optional; class MountPointHelper { public static Logger LOG = LoggerFactory.getLogger(MountPointHelper.class); - private static final int MAX_TMPMOUNTPOINT_CREATION_RETRIES = 10; private final Optional tmpMountPointDir; - private volatile boolean alreadyChecked = false; + private volatile boolean unmountDebrisCleared = false; @Inject public MountPointHelper(Environment env) { @@ -55,13 +54,13 @@ class MountPointHelper { } public synchronized void clearIrregularUnmountDebrisIfNeeded() { - if (alreadyChecked || tmpMountPointDir.isEmpty()) { - return; //nuthin to do + if (unmountDebrisCleared || tmpMountPointDir.isEmpty()) { + return; // nothing to do } if (Files.exists(tmpMountPointDir.get(), LinkOption.NOFOLLOW_LINKS)) { clearIrregularUnmountDebris(tmpMountPointDir.get()); } - alreadyChecked = true; + unmountDebrisCleared = true; } private void clearIrregularUnmountDebris(Path dirContainingMountPoints) { @@ -92,7 +91,7 @@ class MountPointHelper { } catch (IOException e) { LOG.warn("Unable to perform cleanup of mountpoint dir {}.", dirContainingMountPoints, e); } finally { - alreadyChecked = true; + unmountDebrisCleared = true; } } From 4c66f81736dd05300404efd7a7d9804df66508a6 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 18 Nov 2020 18:09:30 +0100 Subject: [PATCH 02/13] simplified line --- .../cryptomator/common/mountpoint/MacVolumeMountChooser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/commons/src/main/java/org/cryptomator/common/mountpoint/MacVolumeMountChooser.java b/main/commons/src/main/java/org/cryptomator/common/mountpoint/MacVolumeMountChooser.java index 64c0ed979..334746860 100644 --- a/main/commons/src/main/java/org/cryptomator/common/mountpoint/MacVolumeMountChooser.java +++ b/main/commons/src/main/java/org/cryptomator/common/mountpoint/MacVolumeMountChooser.java @@ -28,7 +28,7 @@ class MacVolumeMountChooser implements MountPointChooser { @Override public Optional chooseMountPoint(Volume caller) { - return Optional.of(VOLUME_PATH).map(dir -> this.helper.chooseTemporaryMountPoint(this.vaultSettings, dir)); + return Optional.of(helper.chooseTemporaryMountPoint(vaultSettings, VOLUME_PATH)); } @Override From 02fc9b263a55bc1045b194a1bada6caef5cebdfd Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 18 Nov 2020 18:12:41 +0100 Subject: [PATCH 03/13] re-added applicable choosers to exception text --- .../java/org/cryptomator/common/vaults/AbstractVolume.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/main/commons/src/main/java/org/cryptomator/common/vaults/AbstractVolume.java b/main/commons/src/main/java/org/cryptomator/common/vaults/AbstractVolume.java index 6a09683ca..d66ad19d8 100644 --- a/main/commons/src/main/java/org/cryptomator/common/vaults/AbstractVolume.java +++ b/main/commons/src/main/java/org/cryptomator/common/vaults/AbstractVolume.java @@ -20,7 +20,8 @@ public abstract class AbstractVolume implements Volume { } protected Path determineMountPoint() throws InvalidMountPointException { - for (var chooser : Iterables.filter(choosers, c -> c.isApplicable(this))) { + var applicableChoosers = Iterables.filter(choosers, c -> c.isApplicable(this)); + for (var chooser : applicableChoosers) { Optional chosenPath = chooser.chooseMountPoint(this); if (chosenPath.isEmpty()) { // chooser couldn't find a feasible mountpoint continue; @@ -29,7 +30,7 @@ public abstract class AbstractVolume implements Volume { this.usedChooser = chooser; return chosenPath.get(); } - throw new InvalidMountPointException("No feasible MountPoint found!"); + throw new InvalidMountPointException(String.format("No feasible MountPoint found by choosers: %s", applicableChoosers)); } protected void cleanupMountPoint() { From 5d00b3dd76fbaeba7dc2913b1ba65de21923113c Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Thu, 19 Nov 2020 17:20:08 +0100 Subject: [PATCH 04/13] activate ability to abort vault locking if it is mounted with dokany and still busy references #1228 --- .../cryptomator/common/vaults/DokanyVolume.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/main/commons/src/main/java/org/cryptomator/common/vaults/DokanyVolume.java b/main/commons/src/main/java/org/cryptomator/common/vaults/DokanyVolume.java index 89fd73203..0bf39f669 100644 --- a/main/commons/src/main/java/org/cryptomator/common/vaults/DokanyVolume.java +++ b/main/commons/src/main/java/org/cryptomator/common/vaults/DokanyVolume.java @@ -13,7 +13,6 @@ import org.slf4j.LoggerFactory; import javax.inject.Inject; import javax.inject.Named; -import java.util.SortedSet; import java.util.concurrent.ExecutorService; public class DokanyVolume extends AbstractVolume { @@ -42,7 +41,6 @@ public class DokanyVolume extends AbstractVolume { @Override public void mount(CryptoFileSystem fs, String mountFlags) throws InvalidMountPointException, VolumeException { this.mountPoint = determineMountPoint(); - String mountName = vaultSettings.mountName().get(); try { this.mount = mountFactory.mount(fs.getPath("/"), mountPoint, vaultSettings.mountName().get(), FS_TYPE_NAME, mountFlags.strip()); } catch (MountFailedException e) { @@ -62,8 +60,18 @@ public class DokanyVolume extends AbstractVolume { } @Override - public void unmount() { - mount.close(); + public void unmount() throws VolumeException { + try { + mount.unmount(); + } catch (IllegalStateException e) { + throw new VolumeException("Unmount Failed.", e); + } + cleanupMountPoint(); + } + + @Override + public void unmountForced() { + mount.close(); //TODO: with next dokany-nio-release, change this to unmountForced() cleanupMountPoint(); } From c9ec8fecef652d12ec28ebeb9532da1673a88d8c Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Fri, 20 Nov 2020 16:09:31 +0100 Subject: [PATCH 05/13] fix wrong method name --- main/ui/src/main/java/org/cryptomator/ui/quit/QuitModule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/quit/QuitModule.java b/main/ui/src/main/java/org/cryptomator/ui/quit/QuitModule.java index e73fa9d46..9c779f434 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/quit/QuitModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/quit/QuitModule.java @@ -43,7 +43,7 @@ abstract class QuitModule { @Provides @FxmlScene(FxmlFile.QUIT) @QuitScoped - static Scene provideUnlockScene(@QuitWindow FXMLLoaderFactory fxmlLoaders) { + static Scene provideQuitScene(@QuitWindow FXMLLoaderFactory fxmlLoaders) { return fxmlLoaders.createScene("/fxml/quit.fxml"); } From a71f8b350ee665ea4930a42ebc7a4ee293376213 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Fri, 20 Nov 2020 16:12:49 +0100 Subject: [PATCH 06/13] Show only one quit dialogue at a time --- .../cryptomator/ui/fxapp/FxApplication.java | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 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 650254649..3c2db73ce 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 @@ -26,6 +26,8 @@ import javafx.application.Application; import javafx.application.Platform; import javafx.beans.binding.Bindings; import javafx.beans.binding.BooleanBinding; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ObservableValue; import javafx.collections.ObservableSet; import javafx.stage.Stage; @@ -49,6 +51,9 @@ public class FxApplication extends Application { private final BooleanBinding hasVisibleStages; private final UiAppearanceListener systemInterfaceThemeListener = this::systemInterfaceThemeChanged; + private volatile boolean quitDialogueIsShowing; + private ObjectProperty quitStage; + @Inject FxApplication(Settings settings, Lazy mainWindow, Lazy preferencesWindow, Provider unlockWindowBuilderProvider, Provider quitWindowBuilderProvider, Optional trayIntegration, Optional appearanceProvider, VaultService vaultService, LicenseHolder licenseHolder, ObservableSet visibleStages) { this.settings = settings; @@ -61,6 +66,8 @@ public class FxApplication extends Application { this.vaultService = vaultService; this.licenseHolder = licenseHolder; this.hasVisibleStages = Bindings.isNotEmpty(visibleStages); + this.quitDialogueIsShowing = false; + this.quitStage = new SimpleObjectProperty<>(null); } public void start() { @@ -107,11 +114,29 @@ public class FxApplication extends Application { }); } - public void showQuitWindow(QuitResponse response) { - Platform.runLater(() -> { - quitWindowBuilderProvider.get().quitResponse(response).build().showQuitWindow(); - LOG.debug("Showing QuitWindow"); - }); + public synchronized void showQuitWindow(QuitResponse response) { + //TODO: manage a list of quit responses and execute for all the same actions? + if (quitDialogueIsShowing) { + if (quitStage.isNotNull().get()) { + Platform.runLater(() -> { + quitStage.get().requestFocus(); + LOG.debug("Focus QuitWindow"); + }); + } + } else { + quitDialogueIsShowing = true; + Platform.runLater(() -> { + var window = quitWindowBuilderProvider.get().quitResponse(response).build().showQuitWindow(); + quitStage.set(window); + var originalListener = window.getOnCloseRequest(); + window.setOnCloseRequest(windowEvent -> { + originalListener.handle(windowEvent); + quitStage.set(null); + }); + LOG.debug("Showing QuitWindow"); + }); + } + } public VaultService getVaultService() { From dc4fd482b5752d0c32dce4699a62b38ef8578cfb Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Fri, 20 Nov 2020 17:17:16 +0100 Subject: [PATCH 07/13] Filter any whitespaces when entering text in donationkey form. --- .../preferences/DonationKeyPreferencesController.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/DonationKeyPreferencesController.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/DonationKeyPreferencesController.java index e7708af81..a4814ec82 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/preferences/DonationKeyPreferencesController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/preferences/DonationKeyPreferencesController.java @@ -1,5 +1,6 @@ package org.cryptomator.ui.preferences; +import com.google.common.base.CharMatcher; import org.cryptomator.common.LicenseHolder; import org.cryptomator.common.settings.Settings; import org.cryptomator.common.settings.UiTheme; @@ -10,6 +11,7 @@ import javafx.application.Application; import javafx.beans.value.ObservableValue; import javafx.fxml.FXML; import javafx.scene.control.TextArea; +import javafx.scene.control.TextFormatter; @PreferencesScoped public class DonationKeyPreferencesController implements FxController { @@ -32,6 +34,15 @@ public class DonationKeyPreferencesController implements FxController { public void initialize() { donationKeyField.setText(licenseHolder.getLicenseKey().orElse(null)); donationKeyField.textProperty().addListener(this::registrationKeyChanged); + donationKeyField.setTextFormatter(new TextFormatter<>(this::checkVaultNameLength)); + } + + private TextFormatter.Change checkVaultNameLength(TextFormatter.Change change) { + if (change.isContentChange()) { + var strippedText = CharMatcher.whitespace().removeFrom(change.getText()); + change.setText(strippedText); + } + return change; } private void registrationKeyChanged(@SuppressWarnings("unused") ObservableValue observable, @SuppressWarnings("unused") String oldValue, String newValue) { From e82167b5e651f256616f7f2809d9f98017fcbb38 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Fri, 20 Nov 2020 17:29:56 +0100 Subject: [PATCH 08/13] correct wrong method name --- .../ui/vaultoptions/GeneralVaultOptionsController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/GeneralVaultOptionsController.java b/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/GeneralVaultOptionsController.java index b760ebf9a..e860ee811 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/GeneralVaultOptionsController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/GeneralVaultOptionsController.java @@ -39,7 +39,7 @@ public class GeneralVaultOptionsController implements FxController { public void initialize() { vaultName.textProperty().set(vault.getVaultSettings().displayName().get()); vaultName.focusedProperty().addListener(this::trimVaultNameOnFocusLoss); - vaultName.setTextFormatter(new TextFormatter<>(this::checkVaultNameLength)); + vaultName.setTextFormatter(new TextFormatter<>(this::removeWhitespaces)); unlockOnStartupCheckbox.selectedProperty().bindBidirectional(vault.getVaultSettings().unlockAfterStartup()); actionAfterUnlockChoiceBox.getItems().addAll(WhenUnlocked.values()); actionAfterUnlockChoiceBox.valueProperty().bindBidirectional(vault.getVaultSettings().actionAfterUnlock()); @@ -53,7 +53,7 @@ public class GeneralVaultOptionsController implements FxController { } } - private TextFormatter.Change checkVaultNameLength(TextFormatter.Change change) { + private TextFormatter.Change removeWhitespaces(TextFormatter.Change change) { if (change.isContentChange() && change.getControlNewText().length() > VAULTNAME_TRUNCATE_THRESHOLD) { return null; // reject any change that would lead to a text exceeding threshold } else { From c6b786a771824444fabf764a10abfcee3128fa1f Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Tue, 24 Nov 2020 13:34:12 +0100 Subject: [PATCH 09/13] Reworked implemenation by using dagger now: * create and inject QuitResponse container * QuitComponent manges now if quit window needs to be created * controller only handles the most recent QuitResponse --- .../cryptomator/ui/fxapp/FxApplication.java | 45 +++++-------------- .../ui/fxapp/FxApplicationModule.java | 12 +++++ .../cryptomator/ui/quit/QuitComponent.java | 19 +++++--- .../cryptomator/ui/quit/QuitController.java | 19 ++++---- .../org/cryptomator/ui/quit/QuitModule.java | 8 ++++ 5 files changed, 55 insertions(+), 48 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 3c2db73ce..b05a6687f 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 @@ -26,13 +26,12 @@ import javafx.application.Application; import javafx.application.Platform; import javafx.beans.binding.Bindings; import javafx.beans.binding.BooleanBinding; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ObservableValue; import javafx.collections.ObservableSet; import javafx.stage.Stage; import java.awt.desktop.QuitResponse; import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; @FxApplicationScoped public class FxApplication extends Application { @@ -42,32 +41,29 @@ public class FxApplication extends Application { private final Settings settings; private final Lazy mainWindow; private final Lazy preferencesWindow; + private final Lazy quitWindow; private final Provider unlockWindowBuilderProvider; - private final Provider quitWindowBuilderProvider; private final Optional trayIntegration; private final Optional appearanceProvider; private final VaultService vaultService; private final LicenseHolder licenseHolder; private final BooleanBinding hasVisibleStages; private final UiAppearanceListener systemInterfaceThemeListener = this::systemInterfaceThemeChanged; - - private volatile boolean quitDialogueIsShowing; - private ObjectProperty quitStage; + private final AtomicReference quitResponse; @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, Lazy quitWindow, Optional trayIntegration, Optional appearanceProvider, VaultService vaultService, LicenseHolder licenseHolder, ObservableSet visibleStages, AtomicReference quitResponse) { this.settings = settings; this.mainWindow = mainWindow; this.preferencesWindow = preferencesWindow; this.unlockWindowBuilderProvider = unlockWindowBuilderProvider; - this.quitWindowBuilderProvider = quitWindowBuilderProvider; + this.quitWindow = quitWindow; this.trayIntegration = trayIntegration; this.appearanceProvider = appearanceProvider; this.vaultService = vaultService; this.licenseHolder = licenseHolder; this.hasVisibleStages = Bindings.isNotEmpty(visibleStages); - this.quitDialogueIsShowing = false; - this.quitStage = new SimpleObjectProperty<>(null); + this.quitResponse = quitResponse; } public void start() { @@ -114,29 +110,12 @@ public class FxApplication extends Application { }); } - public synchronized void showQuitWindow(QuitResponse response) { - //TODO: manage a list of quit responses and execute for all the same actions? - if (quitDialogueIsShowing) { - if (quitStage.isNotNull().get()) { - Platform.runLater(() -> { - quitStage.get().requestFocus(); - LOG.debug("Focus QuitWindow"); - }); - } - } else { - quitDialogueIsShowing = true; - Platform.runLater(() -> { - var window = quitWindowBuilderProvider.get().quitResponse(response).build().showQuitWindow(); - quitStage.set(window); - var originalListener = window.getOnCloseRequest(); - window.setOnCloseRequest(windowEvent -> { - originalListener.handle(windowEvent); - quitStage.set(null); - }); - LOG.debug("Showing QuitWindow"); - }); - } - + public void showQuitWindow(QuitResponse response) { + quitResponse.set(response); + Platform.runLater(() -> { + quitWindow.get().showQuitWindow(); + LOG.debug("Showing QuitWindow"); + }); } public VaultService getVaultService() { 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..549ea4536 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 @@ -22,15 +22,23 @@ import javafx.collections.FXCollections; import javafx.collections.ObservableSet; import javafx.scene.image.Image; import javafx.stage.Stage; +import java.awt.desktop.QuitResponse; import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; import java.util.Collections; import java.util.List; +import java.util.concurrent.atomic.AtomicReference; @Module(includes = {UpdateCheckerModule.class}, subcomponents = {MainWindowComponent.class, PreferencesComponent.class, UnlockComponent.class, QuitComponent.class, ErrorComponent.class}) abstract class FxApplicationModule { + @Provides + @FxApplicationScoped + static AtomicReference provideQuitResponse() { + return new AtomicReference<>(); + } + @Provides @FxApplicationScoped static ObservableSet provideVisibleStages() { @@ -88,4 +96,8 @@ abstract class FxApplicationModule { return builder.build(); } + @Provides + static QuitComponent provideQuitComponent(QuitComponent.Builder builder) { + return builder.build(); + } } diff --git a/main/ui/src/main/java/org/cryptomator/ui/quit/QuitComponent.java b/main/ui/src/main/java/org/cryptomator/ui/quit/QuitComponent.java index 23ddf311a..eadd32052 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/quit/QuitComponent.java +++ b/main/ui/src/main/java/org/cryptomator/ui/quit/QuitComponent.java @@ -5,15 +5,14 @@ *******************************************************************************/ package org.cryptomator.ui.quit; -import dagger.BindsInstance; import dagger.Lazy; import dagger.Subcomponent; import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlScene; +import javafx.beans.property.ObjectProperty; import javafx.scene.Scene; import javafx.stage.Stage; -import java.awt.desktop.QuitResponse; @QuitScoped @Subcomponent(modules = {QuitModule.class}) @@ -25,9 +24,18 @@ public interface QuitComponent { @FxmlScene(FxmlFile.QUIT) Lazy scene(); + ObjectProperty provideStageProperty(); + default Stage showQuitWindow() { - Stage stage = window(); - stage.setScene(scene().get()); + var stageProperty = provideStageProperty(); + Stage stage; + if (stageProperty.isNull().get()) { + stage = window(); + stage.setScene(scene().get()); + stageProperty.set(stage); + } else { + stage = stageProperty.get(); + } stage.show(); stage.requestFocus(); return stage; @@ -36,9 +44,6 @@ public interface QuitComponent { @Subcomponent.Builder interface Builder { - @BindsInstance - Builder quitResponse(QuitResponse response); - QuitComponent build(); } diff --git a/main/ui/src/main/java/org/cryptomator/ui/quit/QuitController.java b/main/ui/src/main/java/org/cryptomator/ui/quit/QuitController.java index 130556ef2..583e9c010 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/quit/QuitController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/quit/QuitController.java @@ -16,6 +16,7 @@ import javafx.stage.Stage; import java.awt.desktop.QuitResponse; import java.util.Collection; import java.util.concurrent.ExecutorService; +import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; @QuitScoped @@ -24,26 +25,28 @@ public class QuitController implements FxController { private static final Logger LOG = LoggerFactory.getLogger(QuitController.class); private final Stage window; - private final QuitResponse response; private final ObservableList unlockedVaults; private final ExecutorService executorService; private final VaultService vaultService; + private final AtomicReference quitResponse; public Button lockAndQuitButton; @Inject - QuitController(@QuitWindow Stage window, QuitResponse response, ObservableList vaults, ExecutorService executorService, VaultService vaultService) { + QuitController(@QuitWindow Stage window, ObservableList vaults, ExecutorService executorService, VaultService vaultService, AtomicReference quitResponse) { this.window = window; - this.response = response; this.unlockedVaults = vaults.filtered(Vault::isUnlocked); this.executorService = executorService; this.vaultService = vaultService; + this.quitResponse = quitResponse; + window.setOnCloseRequest(windowEvent -> cancel()); } @FXML public void cancel() { LOG.info("Quitting application canceled by user."); window.close(); - response.cancelQuit(); + quitResponse.get().cancelQuit(); + quitResponse.set(null); } @FXML @@ -56,16 +59,16 @@ public class QuitController implements FxController { LOG.info("Locked {}", lockAllTask.getValue().stream().map(Vault::getDisplayName).collect(Collectors.joining(", "))); if (unlockedVaults.isEmpty()) { window.close(); - response.performQuit(); + quitResponse.getAndSet(null).performQuit(); } }); lockAllTask.setOnFailed(evt -> { LOG.warn("Locking failed", lockAllTask.getException()); lockAndQuitButton.setDisable(false); lockAndQuitButton.setContentDisplay(ContentDisplay.TEXT_ONLY); - // TODO: show force lock or force quit scene (and DO NOT cancelQuit() here!) - // see https://github.com/cryptomator/cryptomator/blob/1.4.16/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java#L151-L163 - response.cancelQuit(); + // TODO: show force lock or force quit scene (and DO NOT cancelQuit() here!) (see https://github.com/cryptomator/cryptomator/pull/1416) + window.close(); + quitResponse.getAndSet(null).cancelQuit(); }); executorService.execute(lockAllTask); } diff --git a/main/ui/src/main/java/org/cryptomator/ui/quit/QuitModule.java b/main/ui/src/main/java/org/cryptomator/ui/quit/QuitModule.java index 9c779f434..75408165e 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/quit/QuitModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/quit/QuitModule.java @@ -13,6 +13,8 @@ import org.cryptomator.ui.common.FxmlScene; import org.cryptomator.ui.common.StageFactory; import javax.inject.Provider; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; import javafx.scene.Scene; import javafx.stage.Modality; import javafx.stage.Stage; @@ -22,6 +24,12 @@ import java.util.ResourceBundle; @Module abstract class QuitModule { + @Provides + @QuitScoped + static ObjectProperty provideStageProperty() { + return new SimpleObjectProperty<>(); + } + @Provides @QuitWindow @QuitScoped From 4779bbf415e849b5fb3cf72197e827575678c0b1 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Tue, 24 Nov 2020 15:04:09 +0100 Subject: [PATCH 10/13] Don't bother FxApplication with stuff that is meant to be dealt with internally within QuitComponent --- .../cryptomator/ui/fxapp/FxApplication.java | 8 ++---- .../ui/fxapp/FxApplicationModule.java | 8 ------ .../cryptomator/ui/quit/QuitComponent.java | 18 +++++-------- .../cryptomator/ui/quit/QuitController.java | 27 ++++++++++++++----- .../org/cryptomator/ui/quit/QuitModule.java | 6 ----- 5 files changed, 28 insertions(+), 39 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 b05a6687f..5c6b6e368 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 @@ -31,7 +31,6 @@ import javafx.collections.ObservableSet; import javafx.stage.Stage; import java.awt.desktop.QuitResponse; import java.util.Optional; -import java.util.concurrent.atomic.AtomicReference; @FxApplicationScoped public class FxApplication extends Application { @@ -49,10 +48,9 @@ public class FxApplication extends Application { private final LicenseHolder licenseHolder; private final BooleanBinding hasVisibleStages; private final UiAppearanceListener systemInterfaceThemeListener = this::systemInterfaceThemeChanged; - private final AtomicReference quitResponse; @Inject - FxApplication(Settings settings, Lazy mainWindow, Lazy preferencesWindow, Provider unlockWindowBuilderProvider, Lazy quitWindow, Optional trayIntegration, Optional appearanceProvider, VaultService vaultService, LicenseHolder licenseHolder, ObservableSet visibleStages, AtomicReference quitResponse) { + FxApplication(Settings settings, Lazy mainWindow, Lazy preferencesWindow, Provider unlockWindowBuilderProvider, Lazy quitWindow, Optional trayIntegration, Optional appearanceProvider, VaultService vaultService, LicenseHolder licenseHolder, ObservableSet visibleStages) { this.settings = settings; this.mainWindow = mainWindow; this.preferencesWindow = preferencesWindow; @@ -63,7 +61,6 @@ public class FxApplication extends Application { this.vaultService = vaultService; this.licenseHolder = licenseHolder; this.hasVisibleStages = Bindings.isNotEmpty(visibleStages); - this.quitResponse = quitResponse; } public void start() { @@ -111,9 +108,8 @@ public class FxApplication extends Application { } public void showQuitWindow(QuitResponse response) { - quitResponse.set(response); Platform.runLater(() -> { - quitWindow.get().showQuitWindow(); + quitWindow.get().showQuitWindow(response); LOG.debug("Showing QuitWindow"); }); } 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 549ea4536..5b4e16ffb 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 @@ -22,23 +22,15 @@ import javafx.collections.FXCollections; import javafx.collections.ObservableSet; import javafx.scene.image.Image; import javafx.stage.Stage; -import java.awt.desktop.QuitResponse; import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; import java.util.Collections; import java.util.List; -import java.util.concurrent.atomic.AtomicReference; @Module(includes = {UpdateCheckerModule.class}, subcomponents = {MainWindowComponent.class, PreferencesComponent.class, UnlockComponent.class, QuitComponent.class, ErrorComponent.class}) abstract class FxApplicationModule { - @Provides - @FxApplicationScoped - static AtomicReference provideQuitResponse() { - return new AtomicReference<>(); - } - @Provides @FxApplicationScoped static ObservableSet provideVisibleStages() { diff --git a/main/ui/src/main/java/org/cryptomator/ui/quit/QuitComponent.java b/main/ui/src/main/java/org/cryptomator/ui/quit/QuitComponent.java index eadd32052..e100c52e9 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/quit/QuitComponent.java +++ b/main/ui/src/main/java/org/cryptomator/ui/quit/QuitComponent.java @@ -10,9 +10,9 @@ import dagger.Subcomponent; import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlScene; -import javafx.beans.property.ObjectProperty; import javafx.scene.Scene; import javafx.stage.Stage; +import java.awt.desktop.QuitResponse; @QuitScoped @Subcomponent(modules = {QuitModule.class}) @@ -24,18 +24,12 @@ public interface QuitComponent { @FxmlScene(FxmlFile.QUIT) Lazy scene(); - ObjectProperty provideStageProperty(); + QuitController controller(); - default Stage showQuitWindow() { - var stageProperty = provideStageProperty(); - Stage stage; - if (stageProperty.isNull().get()) { - stage = window(); - stage.setScene(scene().get()); - stageProperty.set(stage); - } else { - stage = stageProperty.get(); - } + default Stage showQuitWindow(QuitResponse response) { + controller().updateQuitRequest(response); + Stage stage = window(); + stage.setScene(scene().get()); stage.show(); stage.requestFocus(); return stage; diff --git a/main/ui/src/main/java/org/cryptomator/ui/quit/QuitController.java b/main/ui/src/main/java/org/cryptomator/ui/quit/QuitController.java index 583e9c010..12ddbbca3 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/quit/QuitController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/quit/QuitController.java @@ -17,6 +17,7 @@ import java.awt.desktop.QuitResponse; import java.util.Collection; import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; import java.util.stream.Collectors; @QuitScoped @@ -28,25 +29,37 @@ public class QuitController implements FxController { private final ObservableList unlockedVaults; private final ExecutorService executorService; private final VaultService vaultService; - private final AtomicReference quitResponse; + private final AtomicReference quitResponse = new AtomicReference<>(); public Button lockAndQuitButton; @Inject - QuitController(@QuitWindow Stage window, ObservableList vaults, ExecutorService executorService, VaultService vaultService, AtomicReference quitResponse) { + QuitController(@QuitWindow Stage window, ObservableList vaults, ExecutorService executorService, VaultService vaultService) { this.window = window; this.unlockedVaults = vaults.filtered(Vault::isUnlocked); this.executorService = executorService; this.vaultService = vaultService; - this.quitResponse = quitResponse; window.setOnCloseRequest(windowEvent -> cancel()); } + public void updateQuitRequest(QuitResponse newResponse) { + var oldResponse = quitResponse.getAndSet(newResponse); + if (oldResponse != null) { + oldResponse.cancelQuit(); + } + } + + private void respondToQuitRequest(Consumer action) { + var response = quitResponse.getAndSet(null); + if (response != null) { + action.accept(response); + } + } + @FXML public void cancel() { LOG.info("Quitting application canceled by user."); window.close(); - quitResponse.get().cancelQuit(); - quitResponse.set(null); + respondToQuitRequest(QuitResponse::cancelQuit); } @FXML @@ -59,7 +72,7 @@ public class QuitController implements FxController { LOG.info("Locked {}", lockAllTask.getValue().stream().map(Vault::getDisplayName).collect(Collectors.joining(", "))); if (unlockedVaults.isEmpty()) { window.close(); - quitResponse.getAndSet(null).performQuit(); + respondToQuitRequest(QuitResponse::performQuit); } }); lockAllTask.setOnFailed(evt -> { @@ -68,7 +81,7 @@ public class QuitController implements FxController { lockAndQuitButton.setContentDisplay(ContentDisplay.TEXT_ONLY); // TODO: show force lock or force quit scene (and DO NOT cancelQuit() here!) (see https://github.com/cryptomator/cryptomator/pull/1416) window.close(); - quitResponse.getAndSet(null).cancelQuit(); + respondToQuitRequest(QuitResponse::cancelQuit); }); executorService.execute(lockAllTask); } diff --git a/main/ui/src/main/java/org/cryptomator/ui/quit/QuitModule.java b/main/ui/src/main/java/org/cryptomator/ui/quit/QuitModule.java index 75408165e..5047427af 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/quit/QuitModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/quit/QuitModule.java @@ -24,12 +24,6 @@ import java.util.ResourceBundle; @Module abstract class QuitModule { - @Provides - @QuitScoped - static ObjectProperty provideStageProperty() { - return new SimpleObjectProperty<>(); - } - @Provides @QuitWindow @QuitScoped From 62ade6113b1a087d08632c3f7e4cd486989f27eb Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Tue, 24 Nov 2020 15:07:23 +0100 Subject: [PATCH 11/13] cleanup [ci skip] --- main/ui/src/main/java/org/cryptomator/ui/quit/QuitModule.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/quit/QuitModule.java b/main/ui/src/main/java/org/cryptomator/ui/quit/QuitModule.java index 5047427af..9c779f434 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/quit/QuitModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/quit/QuitModule.java @@ -13,8 +13,6 @@ import org.cryptomator.ui.common.FxmlScene; import org.cryptomator.ui.common.StageFactory; import javax.inject.Provider; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; import javafx.scene.Scene; import javafx.stage.Modality; import javafx.stage.Stage; From ab3dd779d223785c9e850e88e04a8e9624f53eb7 Mon Sep 17 00:00:00 2001 From: Tobias Hagemann Date: Wed, 2 Dec 2020 14:59:17 +0100 Subject: [PATCH 12/13] partially reverted 900fdd7f, fixing "stutter" startup on macos --- .../CreateNewVaultLocationController.java | 7 +++---- .../java/org/cryptomator/ui/fxapp/FxApplication.java | 5 ++--- .../ui/mainwindow/VaultListController.java | 11 ++++++----- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java b/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java index 1efd5ba50..4eeea5c3d 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java @@ -1,6 +1,5 @@ package org.cryptomator.ui.addvaultwizard; -import com.tobiasdiez.easybind.EasyBind; import dagger.Lazy; import org.cryptomator.ui.common.ErrorComponent; import org.cryptomator.ui.common.FxController; @@ -84,11 +83,11 @@ public class CreateNewVaultLocationController implements FxController { public void initialize() { predefinedLocationToggler.selectedToggleProperty().addListener(this::togglePredefinedLocation); usePresetPath.bind(predefinedLocationToggler.selectedToggleProperty().isNotEqualTo(customRadioButton)); - EasyBind.subscribe(vaultPath, this::vaultPathDidChange); + vaultPath.addListener(this::vaultPathDidChange); } - private void vaultPathDidChange(Path newValue) { - if (newValue != null && !Files.notExists(newValue)) { + private void vaultPathDidChange(@SuppressWarnings("unused") ObservableValue observable, @SuppressWarnings("unused") Path oldValue, Path newValue) { + if (!Files.notExists(newValue)) { warningText.set(resourceBundle.getString("addvaultwizard.new.fileAlreadyExists")); } else { warningText.set(null); 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 5c6b6e368..ca029f271 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 @@ -1,6 +1,5 @@ package org.cryptomator.ui.fxapp; -import com.tobiasdiez.easybind.EasyBind; import dagger.Lazy; import org.cryptomator.common.LicenseHolder; import org.cryptomator.common.settings.Settings; @@ -67,7 +66,7 @@ public class FxApplication extends Application { LOG.trace("FxApplication.start()"); Platform.setImplicitExit(false); - EasyBind.subscribe(hasVisibleStages, this::hasVisibleStagesChanged); + hasVisibleStages.addListener(this::hasVisibleStagesChanged); settings.theme().addListener(this::appThemeChanged); loadSelectedStyleSheet(settings.theme().get()); @@ -78,7 +77,7 @@ public class FxApplication extends Application { throw new UnsupportedOperationException("Use start() instead."); } - private void hasVisibleStagesChanged(boolean newValue) { + private void hasVisibleStagesChanged(@SuppressWarnings("unused") ObservableValue observableValue, @SuppressWarnings("unused") boolean oldValue, boolean newValue) { if (newValue) { trayIntegration.ifPresent(TrayIntegrationProvider::restoredFromTray); } else { diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java index 0533cf50f..fc751d862 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java @@ -1,6 +1,5 @@ package org.cryptomator.ui.mainwindow; -import com.tobiasdiez.easybind.EasyBind; import org.cryptomator.common.vaults.Vault; import org.cryptomator.common.vaults.VaultListManager; import org.cryptomator.ui.addvaultwizard.AddVaultWizardComponent; @@ -13,6 +12,7 @@ import javax.inject.Inject; import javafx.beans.binding.Bindings; import javafx.beans.binding.BooleanBinding; import javafx.beans.property.ObjectProperty; +import javafx.beans.value.ObservableValue; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; import javafx.fxml.FXML; @@ -41,7 +41,7 @@ public class VaultListController implements FxController { this.removeVault = removeVault; this.noVaultSelected = selectedVault.isNull(); this.emptyVaultList = Bindings.isEmpty(vaults); - EasyBind.subscribe(selectedVault, this::selectedVaultDidChange); + selectedVault.addListener(this::selectedVaultDidChange); } public void initialize() { @@ -58,10 +58,11 @@ public class VaultListController implements FxController { }); } - private void selectedVaultDidChange(Vault newValue) { - if (newValue != null) { - VaultListManager.redetermineVaultState(newValue); + private void selectedVaultDidChange(@SuppressWarnings("unused") ObservableValue observableValue, @SuppressWarnings("unused") Vault oldValue, Vault newValue) { + if (newValue == null) { + return; } + VaultListManager.redetermineVaultState(newValue); } @FXML From 935aaccdaecf6cedabcb2a2f4f1e20e13161ddbe Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 2 Dec 2020 15:05:59 +0100 Subject: [PATCH 13/13] Update bug template * Make introduction section more visible * emphasize task to complete for successful bug ticket --- .github/ISSUE_TEMPLATE/bug.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index 4775a0aa2..528dd76ad 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -5,8 +5,11 @@ labels: type:bug ---