diff --git a/src/main/java/org/cryptomator/common/ObservableUtil.java b/src/main/java/org/cryptomator/common/ObservableUtil.java new file mode 100644 index 000000000..289f6e929 --- /dev/null +++ b/src/main/java/org/cryptomator/common/ObservableUtil.java @@ -0,0 +1,18 @@ +package org.cryptomator.common; + +import javafx.beans.binding.Bindings; +import javafx.beans.value.ObservableValue; +import java.util.function.Function; + +public class ObservableUtil { + + public static ObservableValue mapWithDefault(ObservableValue observable, Function mapper, U defaultValue) { + return Bindings.createObjectBinding(() -> { + if (observable.getValue() == null) { + return defaultValue; + } else { + return mapper.apply(observable.getValue()); + } + }, observable); + } +} diff --git a/src/main/java/org/cryptomator/common/mount/ActualMountService.java b/src/main/java/org/cryptomator/common/mount/ActualMountService.java new file mode 100644 index 000000000..a96cc8e37 --- /dev/null +++ b/src/main/java/org/cryptomator/common/mount/ActualMountService.java @@ -0,0 +1,6 @@ +package org.cryptomator.common.mount; + +import org.cryptomator.integrations.mount.MountService; + +public record ActualMountService(MountService service, boolean isDesired) { +} diff --git a/src/main/java/org/cryptomator/common/mount/MountModule.java b/src/main/java/org/cryptomator/common/mount/MountModule.java index ac2e5f598..d885a644e 100644 --- a/src/main/java/org/cryptomator/common/mount/MountModule.java +++ b/src/main/java/org/cryptomator/common/mount/MountModule.java @@ -2,6 +2,7 @@ package org.cryptomator.common.mount; import dagger.Module; import dagger.Provides; +import org.cryptomator.common.ObservableUtil; import org.cryptomator.common.settings.Settings; import org.cryptomator.integrations.mount.MountService; @@ -20,11 +21,14 @@ public class MountModule { @Provides @Singleton - static ObservableValue provideMountService(Settings settings, List serviceImpls) { - return settings.mountService().map(desiredServiceImpl -> { - var fallbackProvider = serviceImpls.stream().findFirst().orElse(null); - return serviceImpls.stream().filter(serviceImpl -> serviceImpl.getClass().getName().equals(desiredServiceImpl)).findAny().orElse(fallbackProvider); - }); + static ObservableValue provideMountService(Settings settings, List serviceImpls) { + var fallbackProvider = serviceImpls.stream().findFirst().orElse(null); + return ObservableUtil.mapWithDefault(settings.mountService(), // + desiredServiceImpl -> { // + var desiredService = serviceImpls.stream().filter(serviceImpl -> serviceImpl.getClass().getName().equals(desiredServiceImpl)).findAny(); // + return new ActualMountService(desiredService.orElse(fallbackProvider), desiredService.isPresent()); // + }, // + new ActualMountService(fallbackProvider, true)); } } diff --git a/src/main/java/org/cryptomator/common/vaults/Vault.java b/src/main/java/org/cryptomator/common/vaults/Vault.java index 835560120..e5a997bc3 100644 --- a/src/main/java/org/cryptomator/common/vaults/Vault.java +++ b/src/main/java/org/cryptomator/common/vaults/Vault.java @@ -12,6 +12,8 @@ import com.google.common.base.Strings; import org.apache.commons.lang3.SystemUtils; import org.cryptomator.common.Constants; import org.cryptomator.common.Environment; +import org.cryptomator.common.mount.ActualMountService; +import org.cryptomator.common.mount.MountModule; import org.cryptomator.common.mount.WindowsDriveLetters; import org.cryptomator.common.settings.Settings; import org.cryptomator.common.settings.VaultSettings; @@ -72,7 +74,7 @@ public class Vault { private final AtomicReference cryptoFileSystem; private final VaultState state; private final ObjectProperty lastKnownException; - private final ObservableValue mountService; + private final ObservableValue mountService; private final ObservableValue defaultMountFlags; private final VaultConfigCache configCache; private final VaultStats stats; @@ -90,7 +92,7 @@ public class Vault { private AtomicReference mountHandle = new AtomicReference<>(null); @Inject - Vault(Environment env, Settings settings, VaultSettings vaultSettings, VaultConfigCache configCache, AtomicReference cryptoFileSystem, VaultState state, @Named("lastKnownException") ObjectProperty lastKnownException, ObservableValue mountService, VaultStats stats, WindowsDriveLetters windowsDriveLetters) { + Vault(Environment env, Settings settings, VaultSettings vaultSettings, VaultConfigCache configCache, AtomicReference cryptoFileSystem, VaultState state, @Named("lastKnownException") ObjectProperty lastKnownException, ObservableValue mountService, VaultStats stats, WindowsDriveLetters windowsDriveLetters) { this.env = env; this.settings = settings; this.vaultSettings = vaultSettings; @@ -99,7 +101,7 @@ public class Vault { this.state = state; this.lastKnownException = lastKnownException; this.mountService = mountService; - this.defaultMountFlags = mountService.map(MountService::getDefaultMountFlags); + this.defaultMountFlags = mountService.map(s -> s.service().getDefaultMountFlags()); this.stats = stats; this.displayablePath = Bindings.createStringBinding(this::getDisplayablePath, vaultSettings.path()); this.locked = Bindings.createBooleanBinding(this::isLocked, state); @@ -159,8 +161,8 @@ public class Vault { } } - private MountBuilder prepareMount(Path cryptoRoot) throws IOException { - var mountProvider = mountService.getValue(); + private MountBuilder prepareMount(MountService actualMountService, Path cryptoRoot) throws IOException { + var mountProvider = mountService.getValue().service(); var builder = mountProvider.forFileSystem(cryptoRoot); for (var capability : mountProvider.capabilities()) { @@ -207,8 +209,9 @@ public class Vault { try { cryptoFileSystem.set(fs); var rootPath = fs.getRootDirectories().iterator().next(); - var supportsForcedUnmount = mountService.getValue().hasCapability(MountCapability.UNMOUNT_FORCED); - var mountHandle = new MountHandle(prepareMount(rootPath).mount(), supportsForcedUnmount); + var actualMountService = mountService.getValue().service(); + var supportsForcedUnmount = actualMountService.hasCapability(MountCapability.UNMOUNT_FORCED); + var mountHandle = new MountHandle(prepareMount(actualMountService, rootPath).mount(), supportsForcedUnmount); success = this.mountHandle.compareAndSet(null, mountHandle); } finally { if (!success) { diff --git a/src/main/java/org/cryptomator/ui/preferences/VolumePreferencesController.java b/src/main/java/org/cryptomator/ui/preferences/VolumePreferencesController.java index ac4903d11..7474561cf 100644 --- a/src/main/java/org/cryptomator/ui/preferences/VolumePreferencesController.java +++ b/src/main/java/org/cryptomator/ui/preferences/VolumePreferencesController.java @@ -1,5 +1,6 @@ package org.cryptomator.ui.preferences; +import org.cryptomator.common.mount.ActualMountService; import org.cryptomator.common.settings.Settings; import org.cryptomator.integrations.mount.MountCapability; import org.cryptomator.integrations.mount.MountService; @@ -22,7 +23,7 @@ import java.util.List; public class VolumePreferencesController implements FxController { private final Settings settings; - private final ObservableValue selectedMountService; + private final ObservableValue selectedMountService; private final BooleanExpression loopbackPortSupported; private final List mountProviders; public ChoiceBox volumeTypeChoiceBox; @@ -30,17 +31,17 @@ public class VolumePreferencesController implements FxController { public Button loopbackPortApplyButton; @Inject - VolumePreferencesController(Settings settings, List mountProviders, ObservableValue selectedMountService) { + VolumePreferencesController(Settings settings, List mountProviders, ObservableValue actualMountService) { this.settings = settings; this.mountProviders = mountProviders; - this.selectedMountService = selectedMountService; - this.loopbackPortSupported = BooleanExpression.booleanExpression(selectedMountService.map(s -> s.hasCapability(MountCapability.LOOPBACK_PORT))); + this.selectedMountService = actualMountService; + this.loopbackPortSupported = BooleanExpression.booleanExpression(selectedMountService.map(as -> as.service().hasCapability(MountCapability.LOOPBACK_PORT))); } public void initialize() { volumeTypeChoiceBox.getItems().addAll(mountProviders); volumeTypeChoiceBox.setConverter(new MountServiceConverter()); - volumeTypeChoiceBox.getSelectionModel().select(selectedMountService.getValue()); + volumeTypeChoiceBox.getSelectionModel().select(selectedMountService.getValue().service()); volumeTypeChoiceBox.valueProperty().addListener((observableValue, oldProvide, newProvider) -> settings.mountService().set(newProvider.getClass().getName())); loopbackPortField.setText(String.valueOf(settings.port().get())); @@ -81,7 +82,7 @@ public class VolumePreferencesController implements FxController { @Override public String toString(MountService provider) { - return provider== null? "None" : provider.displayName(); //TODO: adjust message + return provider== null? "Automatic" : provider.displayName(); //TODO: adjust message } @Override diff --git a/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java b/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java index 1c8fd71a5..bc4d0cda0 100644 --- a/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java +++ b/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java @@ -1,10 +1,10 @@ package org.cryptomator.ui.vaultoptions; import org.cryptomator.common.Environment; +import org.cryptomator.common.mount.ActualMountService; import org.cryptomator.common.mount.WindowsDriveLetters; import org.cryptomator.common.vaults.Vault; import org.cryptomator.integrations.mount.MountCapability; -import org.cryptomator.integrations.mount.MountService; import org.cryptomator.ui.common.FxController; import javax.inject.Inject; @@ -54,15 +54,15 @@ public class MountOptionsController implements FxController { public ChoiceBox driveLetterSelection; @Inject - MountOptionsController(@VaultOptionsWindow Stage window, @VaultOptionsWindow Vault vault, ObservableValue mountService, WindowsDriveLetters windowsDriveLetters, ResourceBundle resourceBundle, Environment environment) { + MountOptionsController(@VaultOptionsWindow Stage window, @VaultOptionsWindow Vault vault, ObservableValue mountService, WindowsDriveLetters windowsDriveLetters, ResourceBundle resourceBundle, Environment environment) { this.window = window; this.vault = vault; this.windowsDriveLetters = windowsDriveLetters; this.resourceBundle = resourceBundle; - this.mountpointDirSupported = mountService.map(s -> s.hasCapability(MountCapability.MOUNT_TO_EXISTING_DIR) || s.hasCapability(MountCapability.MOUNT_WITHIN_EXISTING_PARENT)); - this.mountpointDriveLetterSupported = mountService.map(s -> s.hasCapability(MountCapability.MOUNT_AS_DRIVE_LETTER)); - this.mountFlagsSupported = mountService.map(s -> s.hasCapability(MountCapability.MOUNT_FLAGS)); - this.readOnlySupported = mountService.map(s -> s.hasCapability(MountCapability.READ_ONLY)); + this.mountpointDirSupported = mountService.map(as -> as.service().hasCapability(MountCapability.MOUNT_TO_EXISTING_DIR) || as.service().hasCapability(MountCapability.MOUNT_WITHIN_EXISTING_PARENT)); + this.mountpointDriveLetterSupported = mountService.map(as -> as.service().hasCapability(MountCapability.MOUNT_AS_DRIVE_LETTER)); + this.mountFlagsSupported = mountService.map(as -> as.service().hasCapability(MountCapability.MOUNT_FLAGS)); + this.readOnlySupported = mountService.map(as -> as.service().hasCapability(MountCapability.READ_ONLY)); this.driveLetter = vault.getVaultSettings().mountPoint().map(p -> isDriveLetter(p) ? p : null); this.directoryPath = vault.getVaultSettings().mountPoint().map(p -> isDriveLetter(p) ? null : p.toString()); }