diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..fd88223e4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Cryptomator Community + url: https://community.cryptomator.org/ + about: Please ask and answer questions here + - name: Documentation + url: https://docs.cryptomator.org/ + about: Get instructions on how to use Cryptomator diff --git a/main/commons/src/main/java/org/cryptomator/common/LazyInitializer.java b/main/commons/src/main/java/org/cryptomator/common/LazyInitializer.java deleted file mode 100644 index 7bca69457..000000000 --- a/main/commons/src/main/java/org/cryptomator/common/LazyInitializer.java +++ /dev/null @@ -1,79 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2017 Skymatic UG (haftungsbeschränkt). - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the accompanying LICENSE file. - *******************************************************************************/ -package org.cryptomator.common; - -import com.google.common.base.Throwables; - -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Supplier; -import java.util.function.UnaryOperator; - -public final class LazyInitializer { - - private LazyInitializer() { - } - - /** - * Same as {@link #initializeLazily(AtomicReference, SupplierThrowingException, Class)} except that no checked exception may be thrown by the factory function. - * - * @param Type of the value - * @param reference A reference to a maybe not yet initialized value. - * @param factory A factory providing a value for the reference, if it doesn't exist yet. The factory may be invoked multiple times, but only one result will survive. - * @return The initialized value - */ - public static T initializeLazily(AtomicReference reference, Supplier factory) { - SupplierThrowingException factoryThrowingRuntimeExceptions = () -> factory.get(); - return initializeLazily(reference, factoryThrowingRuntimeExceptions, RuntimeException.class); - } - - /** - * Threadsafe lazy initialization pattern as proposed on http://stackoverflow.com/a/30247202/4014509 - * - * @param Type of the value - * @param Type of the any expected exception that may occur during initialization - * @param reference A reference to a maybe not yet initialized value. - * @param factory A factory providing a value for the reference, if it doesn't exist yet. The factory may be invoked multiple times, but only one result will survive. - * @param exceptionType Expected exception type. - * @return The initialized value - * @throws E Exception thrown by the factory function. - */ - public static T initializeLazily(AtomicReference reference, SupplierThrowingException factory, Class exceptionType) throws E { - final T existing = reference.get(); - if (existing != null) { - return existing; - } else { - try { - return reference.updateAndGet(invokeFactoryIfNull(factory)); - } catch (InitializationException e) { - Throwables.throwIfUnchecked(e.getCause()); - Throwables.throwIfInstanceOf(e.getCause(), exceptionType); - throw e; - } - } - } - - private static UnaryOperator invokeFactoryIfNull(SupplierThrowingException factory) throws InitializationException { - return currentValue -> { - if (currentValue == null) { - try { - return factory.get(); - } catch (Exception e) { - throw new InitializationException(e); - } - } else { - return currentValue; - } - }; - } - - private static class InitializationException extends RuntimeException { - - public InitializationException(Throwable cause) { - super(cause); - } - - } -} diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/SettingsProvider.java b/main/commons/src/main/java/org/cryptomator/common/settings/SettingsProvider.java index 390e40f5a..85bc436a2 100644 --- a/main/commons/src/main/java/org/cryptomator/common/settings/SettingsProvider.java +++ b/main/commons/src/main/java/org/cryptomator/common/settings/SettingsProvider.java @@ -8,13 +8,13 @@ *******************************************************************************/ package org.cryptomator.common.settings; +import com.google.common.base.Suppliers; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; import com.google.gson.JsonParser; import org.cryptomator.common.Environment; -import org.cryptomator.common.LazyInitializer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,7 +48,7 @@ public class SettingsProvider implements Supplier { private static final long SAVE_DELAY_MS = 1000; private final AtomicReference> scheduledSaveCmd = new AtomicReference<>(); - private final AtomicReference settings = new AtomicReference<>(); + private final Supplier settings = Suppliers.memoize(this::load); private final SettingsJsonAdapter settingsJsonAdapter = new SettingsJsonAdapter(); private final Environment env; private final ScheduledExecutorService scheduler; @@ -66,7 +66,7 @@ public class SettingsProvider implements Supplier { @Override public Settings get() { - return LazyInitializer.initializeLazily(settings, this::load); + return settings.get(); } private Settings load() { diff --git a/main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java b/main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java index f2ab973f6..730f0fb6d 100644 --- a/main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java +++ b/main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java @@ -10,7 +10,6 @@ package org.cryptomator.common.vaults; import com.google.common.base.Strings; import org.apache.commons.lang3.SystemUtils; -import org.cryptomator.common.LazyInitializer; import org.cryptomator.common.mountpoint.InvalidMountPointException; import org.cryptomator.common.settings.VaultSettings; import org.cryptomator.common.vaults.Volume.VolumeException; @@ -100,11 +99,7 @@ public class Vault { // Commands // ********************************************************************************/ - private CryptoFileSystem getCryptoFileSystem(CharSequence passphrase) throws NoSuchFileException, IOException, InvalidPassphraseException, CryptoException { - return LazyInitializer.initializeLazily(cryptoFileSystem, () -> unlockCryptoFileSystem(passphrase), IOException.class); - } - - private CryptoFileSystem unlockCryptoFileSystem(CharSequence passphrase) throws NoSuchFileException, IOException, InvalidPassphraseException, CryptoException { + private CryptoFileSystem createCryptoFileSystem(CharSequence passphrase) throws NoSuchFileException, IOException, InvalidPassphraseException, CryptoException { Set flags = EnumSet.noneOf(FileSystemFlags.class); if (vaultSettings.usesReadOnlyMode().get()) { flags.add(FileSystemFlags.READONLY); @@ -127,9 +122,14 @@ public class Vault { } public synchronized void unlock(CharSequence passphrase) throws CryptoException, IOException, VolumeException, InvalidMountPointException { - CryptoFileSystem fs = getCryptoFileSystem(passphrase); - volume = volumeProvider.get(); - volume.mount(fs, getEffectiveMountFlags()); + if (cryptoFileSystem.get() == null) { + CryptoFileSystem fs = createCryptoFileSystem(passphrase); + cryptoFileSystem.set(fs); + volume = volumeProvider.get(); + volume.mount(fs, getEffectiveMountFlags()); + } else { + throw new IllegalStateException("Already unlocked."); + } } public synchronized void lock(boolean forced) throws VolumeException { diff --git a/main/commons/src/test/java/org/cryptomator/common/vaults/VaultModuleTest.java b/main/commons/src/test/java/org/cryptomator/common/vaults/VaultModuleTest.java index 9b25ebb08..835c05e16 100644 --- a/main/commons/src/test/java/org/cryptomator/common/vaults/VaultModuleTest.java +++ b/main/commons/src/test/java/org/cryptomator/common/vaults/VaultModuleTest.java @@ -43,7 +43,7 @@ public class VaultModuleTest { StringBinding result = module.provideDefaultMountFlags(settings, vaultSettings); - MatcherAssert.assertThat(result.get(), CoreMatchers.containsString("-ovolname=TEST")); + MatcherAssert.assertThat(result.get(), CoreMatchers.containsString("-ovolname=\"TEST\"")); MatcherAssert.assertThat(result.get(), CoreMatchers.containsString("-ordonly")); } diff --git a/main/pom.xml b/main/pom.xml index 5989c3276..77690a641 100644 --- a/main/pom.xml +++ b/main/pom.xml @@ -175,6 +175,13 @@ java-jwt ${jwt.version} + + + com.fasterxml.jackson.core + jackson-databind + 2.10.5.1 + + 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 460d074e6..1a4cb84de 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 @@ -27,8 +27,9 @@ import javafx.application.Platform; import javafx.beans.binding.Bindings; import javafx.beans.binding.BooleanBinding; import javafx.beans.value.ObservableValue; -import javafx.collections.ObservableSet; +import javafx.collections.ObservableList; import javafx.stage.Stage; +import javafx.stage.Window; import java.awt.desktop.QuitResponse; import java.util.Optional; @@ -47,11 +48,12 @@ public class FxApplication extends Application { private final Optional appearanceProvider; private final VaultService vaultService; private final LicenseHolder licenseHolder; - private final BooleanBinding hasVisibleStages; + private final ObservableList visibleWindows; + private final BooleanBinding hasVisibleWindows; private final UiAppearanceListener systemInterfaceThemeListener = this::systemInterfaceThemeChanged; @Inject - FxApplication(Settings settings, Lazy mainWindow, Lazy preferencesWindow, Provider unlockWindowBuilderProvider, Provider lockWindowBuilderProvider, Lazy quitWindow, Optional trayIntegration, Optional appearanceProvider, VaultService vaultService, LicenseHolder licenseHolder, ObservableSet visibleStages) { + FxApplication(Settings settings, Lazy mainWindow, Lazy preferencesWindow, Provider unlockWindowBuilderProvider, Provider lockWindowBuilderProvider, Lazy quitWindow, Optional trayIntegration, Optional appearanceProvider, VaultService vaultService, LicenseHolder licenseHolder) { this.settings = settings; this.mainWindow = mainWindow; this.preferencesWindow = preferencesWindow; @@ -62,14 +64,15 @@ public class FxApplication extends Application { this.appearanceProvider = appearanceProvider; this.vaultService = vaultService; this.licenseHolder = licenseHolder; - this.hasVisibleStages = Bindings.isNotEmpty(visibleStages); + this.visibleWindows = Stage.getWindows().filtered(Window::isShowing); + this.hasVisibleWindows = Bindings.isNotEmpty(visibleWindows); } public void start() { LOG.trace("FxApplication.start()"); Platform.setImplicitExit(false); - hasVisibleStages.addListener(this::hasVisibleStagesChanged); + hasVisibleWindows.addListener(this::hasVisibleStagesChanged); settings.theme().addListener(this::appThemeChanged); loadSelectedStyleSheet(settings.theme().get()); @@ -81,6 +84,7 @@ public class FxApplication extends Application { } private void hasVisibleStagesChanged(@SuppressWarnings("unused") ObservableValue observableValue, @SuppressWarnings("unused") boolean oldValue, boolean newValue) { + LOG.warn("has visible stages: {}", newValue); if (newValue) { trayIntegration.ifPresent(TrayIntegrationProvider::restoredFromTray); } else { 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 87f408490..74c201372 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 @@ -19,7 +19,6 @@ import org.cryptomator.ui.unlock.UnlockComponent; import javax.inject.Named; import javafx.application.Application; -import javafx.collections.FXCollections; import javafx.collections.ObservableSet; import javafx.scene.image.Image; import javafx.stage.Stage; @@ -32,12 +31,6 @@ import java.util.List; @Module(includes = {UpdateCheckerModule.class}, subcomponents = {MainWindowComponent.class, PreferencesComponent.class, UnlockComponent.class, LockComponent.class, QuitComponent.class, ErrorComponent.class}) abstract class FxApplicationModule { - @Provides - @FxApplicationScoped - static ObservableSet provideVisibleStages() { - return FXCollections.observableSet(); - } - @Provides @Named("windowIcons") @FxApplicationScoped @@ -57,16 +50,9 @@ abstract class FxApplicationModule { @Provides @FxApplicationScoped - static StageFactory provideStageFactory(@Named("windowIcons") List windowIcons, ObservableSet visibleStages) { + static StageFactory provideStageFactory(@Named("windowIcons") List windowIcons) { return new StageFactory(stage -> { stage.getIcons().addAll(windowIcons); - stage.showingProperty().addListener((observableValue, wasShowing, isShowing) -> { - if (isShowing) { - visibleStages.add(stage); - } else { - visibleStages.remove(stage); - } - }); }); }