mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-25 14:10:20 +00:00
implemented volume type selection in 'vault options mount'
This commit is contained in:
@@ -1,18 +1,26 @@
|
||||
package org.cryptomator.ui.vaultoptions;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import dagger.Lazy;
|
||||
import org.cryptomator.common.ObservableUtil;
|
||||
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;
|
||||
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 org.cryptomator.ui.fxapp.FxApplicationWindows;
|
||||
import org.cryptomator.ui.preferences.SelectedPreferencesTab;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javafx.application.Application;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.binding.BooleanExpression;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.ChoiceBox;
|
||||
import javafx.scene.control.RadioButton;
|
||||
@@ -26,16 +34,25 @@ import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@VaultOptionsScoped
|
||||
public class MountOptionsController implements FxController {
|
||||
|
||||
private static final String DOCS_MOUNTING_URL = "https://docs.cryptomator.org/en/1.7/desktop/volume-type/";
|
||||
private static final int MIN_PORT = 1024;
|
||||
private static final int MAX_PORT = 65535;
|
||||
|
||||
private final Stage window;
|
||||
private final VaultSettings vaultSettings;
|
||||
private final WindowsDriveLetters windowsDriveLetters;
|
||||
private final ResourceBundle resourceBundle;
|
||||
private final Lazy<Application> application;
|
||||
private final Settings settings;
|
||||
|
||||
private final ObservableValue<String> defaultMountFlags;
|
||||
private final ObservableValue<Boolean> mountpointDirSupported;
|
||||
@@ -43,7 +60,10 @@ public class MountOptionsController implements FxController {
|
||||
private final ObservableValue<Boolean> readOnlySupported;
|
||||
private final ObservableValue<Boolean> mountFlagsSupported;
|
||||
private final ObservableValue<String> directoryPath;
|
||||
private final FxApplicationWindows applicationWindows;
|
||||
private final List<MountService> mountProviders;
|
||||
private final ObservableValue<MountService> selectedMountService;
|
||||
private final ObservableValue<Boolean> fuseRestartRequired;
|
||||
private final BooleanExpression loopbackPortSupported;
|
||||
|
||||
|
||||
//-- FXML objects --
|
||||
@@ -56,9 +76,21 @@ public class MountOptionsController implements FxController {
|
||||
public RadioButton mountPointDirBtn;
|
||||
public TextField directoryPathField;
|
||||
public ChoiceBox<Path> driveLetterSelection;
|
||||
public ChoiceBox<MountService> volumeTypeChoiceBox;
|
||||
public TextField loopbackPortField;
|
||||
public Button loopbackPortApplyButton;
|
||||
|
||||
|
||||
@Inject
|
||||
MountOptionsController(@VaultOptionsWindow Stage window, @VaultOptionsWindow Vault vault, ObservableValue<ActualMountService> mountService, WindowsDriveLetters windowsDriveLetters, ResourceBundle resourceBundle, FxApplicationWindows applicationWindows) {
|
||||
MountOptionsController(@VaultOptionsWindow Stage window, //
|
||||
@VaultOptionsWindow Vault vault, //
|
||||
ObservableValue<ActualMountService> mountService, //
|
||||
WindowsDriveLetters windowsDriveLetters, //
|
||||
ResourceBundle resourceBundle, //
|
||||
Lazy<Application> application,
|
||||
Settings settings, //
|
||||
List<MountService> mountProviders, //
|
||||
@Named("FUPFMS") AtomicReference<MountService> firstUsedProblematicFuseMountService) {
|
||||
this.window = window;
|
||||
this.vaultSettings = vault.getVaultSettings();
|
||||
this.windowsDriveLetters = windowsDriveLetters;
|
||||
@@ -75,7 +107,17 @@ public class MountOptionsController implements FxController {
|
||||
this.mountFlagsSupported = mountService.map(as -> as.service().hasCapability(MountCapability.MOUNT_FLAGS));
|
||||
this.readOnlySupported = mountService.map(as -> as.service().hasCapability(MountCapability.READ_ONLY));
|
||||
this.directoryPath = vault.getVaultSettings().mountPoint.map(p -> isDriveLetter(p) ? null : p.toString());
|
||||
this.applicationWindows = applicationWindows;
|
||||
this.application = application;
|
||||
this.settings = settings;
|
||||
this.mountProviders = mountProviders;
|
||||
var fallbackProvider = mountProviders.stream().findFirst().orElse(null);
|
||||
this.selectedMountService = ObservableUtil.mapWithDefault(settings.mountService, serviceName -> mountProviders.stream().filter(s -> s.getClass().getName().equals(serviceName)).findFirst().orElse(fallbackProvider), fallbackProvider);
|
||||
this.fuseRestartRequired = selectedMountService.map(s -> {//
|
||||
return firstUsedProblematicFuseMountService.get() != null //
|
||||
&& MountModule.isProblematicFuseService(s) //
|
||||
&& !firstUsedProblematicFuseMountService.get().equals(s);
|
||||
});
|
||||
this.loopbackPortSupported = BooleanExpression.booleanExpression(selectedMountService.map(s -> s.hasCapability(MountCapability.LOOPBACK_PORT)));
|
||||
}
|
||||
|
||||
@FXML
|
||||
@@ -106,11 +148,21 @@ public class MountOptionsController implements FxController {
|
||||
mountPointToggleGroup.selectToggle(mountPointDirBtn);
|
||||
}
|
||||
mountPointToggleGroup.selectedToggleProperty().addListener(this::selectedToggleChanged);
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void openVolumePreferences() {
|
||||
applicationWindows.showPreferencesWindow(SelectedPreferencesTab.VOLUME);
|
||||
volumeTypeChoiceBox.getItems().add(null);
|
||||
volumeTypeChoiceBox.getItems().addAll(mountProviders);
|
||||
volumeTypeChoiceBox.setConverter(new MountServiceConverter());
|
||||
boolean autoSelected = settings.mountService.get() == null;
|
||||
volumeTypeChoiceBox.getSelectionModel().select(autoSelected ? null : selectedMountService.getValue());
|
||||
volumeTypeChoiceBox.valueProperty().addListener((observableValue, oldProvider, newProvider) -> {
|
||||
var toSet = Optional.ofNullable(newProvider).map(nP -> nP.getClass().getName()).orElse(null);
|
||||
settings.mountService.set(toSet);
|
||||
});
|
||||
|
||||
loopbackPortField.setText(String.valueOf(settings.port.get()));
|
||||
loopbackPortApplyButton.visibleProperty().bind(settings.port.asString().isNotEqualTo(loopbackPortField.textProperty()));
|
||||
loopbackPortApplyButton.disableProperty().bind(Bindings.createBooleanBinding(this::validateLoopbackPort, loopbackPortField.textProperty()).not());
|
||||
|
||||
}
|
||||
|
||||
@FXML
|
||||
@@ -229,6 +281,26 @@ public class MountOptionsController implements FxController {
|
||||
|
||||
}
|
||||
|
||||
public void openDocs() {
|
||||
application.get().getHostServices().showDocument(DOCS_MOUNTING_URL);
|
||||
}
|
||||
|
||||
private boolean validateLoopbackPort() {
|
||||
try {
|
||||
int port = Integer.parseInt(loopbackPortField.getText());
|
||||
return port == 0 // choose port automatically
|
||||
|| port >= MIN_PORT && port <= MAX_PORT; // port within range
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void doChangeLoopbackPort() {
|
||||
if (validateLoopbackPort()) {
|
||||
settings.port.set(Integer.parseInt(loopbackPortField.getText()));
|
||||
}
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
private static class NoDirSelectedException extends Exception {}
|
||||
//@formatter:on
|
||||
@@ -274,4 +346,40 @@ public class MountOptionsController implements FxController {
|
||||
public String getDirectoryPath() {
|
||||
return directoryPath.getValue();
|
||||
}
|
||||
|
||||
public ObservableValue<Boolean> fuseRestartRequiredProperty() {
|
||||
return fuseRestartRequired;
|
||||
}
|
||||
|
||||
public boolean getFuseRestartRequired() {
|
||||
return fuseRestartRequired.getValue();
|
||||
}
|
||||
|
||||
public BooleanExpression loopbackPortSupportedProperty() {
|
||||
return loopbackPortSupported;
|
||||
}
|
||||
|
||||
public boolean isLoopbackPortSupported() {
|
||||
return loopbackPortSupported.get();
|
||||
}
|
||||
|
||||
//Helpers
|
||||
/* Helpers */
|
||||
|
||||
private class MountServiceConverter extends StringConverter<MountService> {
|
||||
|
||||
@Override
|
||||
public String toString(MountService provider) {
|
||||
if (provider == null) {
|
||||
return resourceBundle.getString("preferences.volume.type.automatic");
|
||||
} else {
|
||||
return provider.displayName();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MountService fromString(String string) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
|
||||
<?import org.cryptomator.ui.controls.NumericTextField?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.CheckBox?>
|
||||
@@ -12,7 +13,7 @@
|
||||
<?import javafx.scene.control.ToggleGroup?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.text.TextFlow?>
|
||||
<?import javafx.scene.control.Tooltip?>
|
||||
<VBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.vaultoptions.MountOptionsController"
|
||||
@@ -24,11 +25,27 @@
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<TextFlow>
|
||||
<Label text="%vaultOptions.mount.info"/>
|
||||
<Label text=" "/>
|
||||
<Hyperlink styleClass="hyperlink-underline" text="%vaultOptions.mount.linkToPreferences" onAction="#openVolumePreferences" wrapText="true"/>
|
||||
</TextFlow>
|
||||
<HBox spacing="12" alignment="CENTER_LEFT">
|
||||
<Label text="%preferences.volume.type"/>
|
||||
<ChoiceBox fx:id="volumeTypeChoiceBox"/>
|
||||
<Hyperlink contentDisplay="GRAPHIC_ONLY" onAction="#openDocs">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="QUESTION_CIRCLE" styleClass="glyph-icon-muted"/>
|
||||
</graphic>
|
||||
<tooltip>
|
||||
<Tooltip text="%preferences.volume.docsTooltip" showDelay="100ms"/>
|
||||
</tooltip>
|
||||
</Hyperlink>
|
||||
</HBox>
|
||||
|
||||
<Label styleClass="label-red" text="%preferences.volume.fuseRestartRequired" visible="${controller.fuseRestartRequired}" managed="${controller.fuseRestartRequired}"/>
|
||||
|
||||
<HBox spacing="12" alignment="CENTER_LEFT" visible="${controller.loopbackPortSupported}" managed="${controller.loopbackPortSupported}">
|
||||
<Label text="%preferences.volume.tcp.port"/>
|
||||
<NumericTextField fx:id="loopbackPortField"/>
|
||||
<Button text="%generic.button.apply" fx:id="loopbackPortApplyButton" onAction="#doChangeLoopbackPort"/>
|
||||
</HBox>
|
||||
|
||||
<CheckBox fx:id="readOnlyCheckbox" text="%vaultOptions.mount.readonly" visible="${controller.readOnlySupported}" managed="${controller.readOnlySupported}"/>
|
||||
|
||||
<VBox visible="${controller.mountFlagsSupported}" managed="${controller.mountFlagsSupported}">
|
||||
|
||||
Reference in New Issue
Block a user