mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-15 09:11:29 +00:00
Compare commits
3 Commits
develop
...
feature/pr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1bc256c6d5 | ||
|
|
f3581c5acf | ||
|
|
506827ffef |
@@ -0,0 +1,51 @@
|
||||
package org.cryptomator.common.settings;
|
||||
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
|
||||
public class NetworkSettings {
|
||||
|
||||
public final ObjectProperty<ProxyMode> mode;
|
||||
public final StringProperty httpProxy;
|
||||
public final IntegerProperty httpPort;
|
||||
public final BooleanProperty samePortProxyForHttpHttps;
|
||||
public final StringProperty httpsProxy;
|
||||
public final IntegerProperty httpsPort;
|
||||
|
||||
NetworkSettings(NetworkSettingsJson json){
|
||||
this.mode = new SimpleObjectProperty<>(this, "mode", json.mode);
|
||||
this.httpProxy = new SimpleStringProperty(this, "httpProxy", json.httpProxy);
|
||||
this.httpPort = new SimpleIntegerProperty(this, "httpPort", json.httpPort);
|
||||
this.samePortProxyForHttpHttps = new SimpleBooleanProperty(this, "samePortProxyForHttpHttps", json.samePortProxyForHttpHttps);
|
||||
this.httpsProxy = new SimpleStringProperty(this, "httpsProxy", json.httpsProxy);
|
||||
this.httpsPort = new SimpleIntegerProperty(this, "httpsPort", json.httpsPort);
|
||||
}
|
||||
|
||||
NetworkSettingsJson serialized(){
|
||||
var json = new NetworkSettingsJson();
|
||||
json.mode = mode.get();
|
||||
json.httpProxy = httpProxy.get();
|
||||
json.httpPort = httpPort.get();
|
||||
json.samePortProxyForHttpHttps = samePortProxyForHttpHttps.get();
|
||||
json.httpsProxy = httpsProxy.get();
|
||||
json.httpsPort = httpsPort.get();
|
||||
return json;
|
||||
}
|
||||
|
||||
Observable[] observables() {
|
||||
return new Observable[]{mode, httpProxy, httpPort,httpsProxy,httpsPort};
|
||||
}
|
||||
|
||||
public enum ProxyMode {
|
||||
NO,
|
||||
SYSTEM,
|
||||
MANUAL
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package org.cryptomator.common.settings;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
class NetworkSettingsJson {
|
||||
|
||||
@JsonProperty("mode")
|
||||
NetworkSettings.ProxyMode mode = NetworkSettings.ProxyMode.NO;
|
||||
|
||||
@JsonProperty("httpProxy")
|
||||
String httpProxy;
|
||||
|
||||
@JsonProperty("httpPort")
|
||||
int httpPort;
|
||||
|
||||
@JsonProperty("samePortProxyForHttpHttps")
|
||||
boolean samePortProxyForHttpHttps;
|
||||
|
||||
@JsonProperty(value = "httpsProxy")
|
||||
String httpsProxy;
|
||||
|
||||
@JsonProperty("httpsPort")
|
||||
int httpsPort;
|
||||
|
||||
}
|
||||
@@ -47,6 +47,7 @@ public class Settings {
|
||||
static final boolean DEFAULT_SHOW_MINIMIZE_BUTTON = false;
|
||||
public static final Instant DEFAULT_TIMESTAMP = Instant.parse("2000-01-01T00:00:00Z");
|
||||
public final ObservableList<VaultSettings> directories;
|
||||
public final ObjectProperty<NetworkSettings> networkSettings;
|
||||
public final BooleanProperty askedForUpdateCheck;
|
||||
public final BooleanProperty checkForUpdates;
|
||||
public final BooleanProperty startHidden;
|
||||
@@ -84,6 +85,7 @@ public class Settings {
|
||||
*/
|
||||
Settings(SettingsJson json) {
|
||||
this.directories = FXCollections.observableArrayList(VaultSettings::observables);
|
||||
this.networkSettings = new SimpleObjectProperty<>(this, "networkSettings", new NetworkSettings(json.networkSettings));
|
||||
this.askedForUpdateCheck = new SimpleBooleanProperty(this, "askedForUpdateCheck", json.askedForUpdateCheck);
|
||||
this.checkForUpdates = new SimpleBooleanProperty(this, "checkForUpdates", json.checkForUpdatesEnabled);
|
||||
this.startHidden = new SimpleBooleanProperty(this, "startHidden", json.startHidden);
|
||||
@@ -111,6 +113,12 @@ public class Settings {
|
||||
migrateLegacySettings(json);
|
||||
|
||||
directories.addListener(this::somethingChanged);
|
||||
networkSettings.get().mode.addListener(this::somethingChanged);
|
||||
networkSettings.get().httpProxy.addListener(this::somethingChanged);
|
||||
networkSettings.get().httpPort.addListener(this::somethingChanged);
|
||||
networkSettings.get().samePortProxyForHttpHttps.addListener(this::somethingChanged);
|
||||
networkSettings.get().httpsProxy.addListener(this::somethingChanged);
|
||||
networkSettings.get().httpsPort.addListener(this::somethingChanged);
|
||||
askedForUpdateCheck.addListener(this::somethingChanged);
|
||||
checkForUpdates.addListener(this::somethingChanged);
|
||||
startHidden.addListener(this::somethingChanged);
|
||||
@@ -165,6 +173,7 @@ public class Settings {
|
||||
SettingsJson serialized() {
|
||||
var json = new SettingsJson();
|
||||
json.directories = directories.stream().map(VaultSettings::serialized).toList();
|
||||
json.networkSettings = networkSettings.get().serialized();
|
||||
json.askedForUpdateCheck = askedForUpdateCheck.get();
|
||||
json.checkForUpdatesEnabled = checkForUpdates.get();
|
||||
json.startHidden = startHidden.get();
|
||||
|
||||
@@ -15,6 +15,9 @@ class SettingsJson {
|
||||
@JsonProperty("directories")
|
||||
List<VaultSettingsJson> directories = List.of();
|
||||
|
||||
@JsonProperty("networkSettings")
|
||||
NetworkSettingsJson networkSettings = new NetworkSettingsJson();
|
||||
|
||||
@JsonProperty("writtenByVersion")
|
||||
String writtenByVersion;
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ public enum FontAwesome5Icon {
|
||||
LOCK("\uF023"), //
|
||||
LOCK_OPEN("\uF3C1"), //
|
||||
MAGIC("\uF0D0"), //
|
||||
NETWORK("\uF6FF"), //
|
||||
PENCIL("\uF303"), //
|
||||
PLUS("\uF067"), //
|
||||
PRINT("\uF02F"), //
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
package org.cryptomator.ui.preferences;
|
||||
|
||||
import org.cryptomator.common.settings.NetworkSettings;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.controls.NumericTextField;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.RadioButton;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.control.ToggleGroup;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
@PreferencesScoped
|
||||
public class NetworkPreferencesController implements FxController {
|
||||
|
||||
private final Settings settings;
|
||||
|
||||
public ToggleGroup proxyToggleGroup;
|
||||
public RadioButton noProxyBtn;
|
||||
public RadioButton systemSettingsBtn;
|
||||
public RadioButton manualProxyBtn;
|
||||
public VBox manualProxyBox;
|
||||
public HBox httpsProxyBox;
|
||||
|
||||
@FXML
|
||||
public TextField httpProxy;
|
||||
public NumericTextField httpPort;
|
||||
public CheckBox samePortProxyForHttpHttps;
|
||||
public TextField httpsProxy;
|
||||
public NumericTextField httpsPort;
|
||||
|
||||
@Inject
|
||||
NetworkPreferencesController(Settings settings) {
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
|
||||
initializeTextFieldWithValidation(httpProxy, settings.networkSettings.get().httpProxy);
|
||||
initializeTextFieldWithValidation(httpPort, settings.networkSettings.get().httpPort);
|
||||
initializeTextFieldWithValidation(httpsProxy, settings.networkSettings.get().httpsProxy);
|
||||
initializeTextFieldWithValidation(httpsPort, settings.networkSettings.get().httpsPort);
|
||||
|
||||
samePortProxyForHttpHttps.selectedProperty().bindBidirectional(settings.networkSettings.get().samePortProxyForHttpHttps);
|
||||
httpsProxyBox.setDisable(settings.networkSettings.get().samePortProxyForHttpHttps.get());
|
||||
samePortProxyForHttpHttps.selectedProperty().addListener((_, _, newValue) -> {
|
||||
httpsProxyBox.setDisable(newValue);
|
||||
});
|
||||
|
||||
switch (settings.networkSettings.get().mode.get()) {
|
||||
case NO -> {
|
||||
proxyToggleGroup.selectToggle(noProxyBtn);
|
||||
manualProxyBox.setDisable(true);
|
||||
}
|
||||
case SYSTEM -> {
|
||||
proxyToggleGroup.selectToggle(systemSettingsBtn);
|
||||
manualProxyBox.setDisable(true);
|
||||
}
|
||||
case MANUAL -> {
|
||||
proxyToggleGroup.selectToggle(manualProxyBtn);
|
||||
manualProxyBox.setDisable(false);
|
||||
}
|
||||
}
|
||||
|
||||
proxyToggleGroup.selectedToggleProperty().addListener((_, _, newValue) -> {
|
||||
if (newValue != null) {
|
||||
manualProxyBox.setDisable(!newValue.equals(manualProxyBtn));
|
||||
|
||||
if (newValue.equals(noProxyBtn)) {
|
||||
settings.networkSettings.get().mode.set(NetworkSettings.ProxyMode.NO);
|
||||
} else if (newValue.equals(systemSettingsBtn)) {
|
||||
settings.networkSettings.get().mode.set(NetworkSettings.ProxyMode.SYSTEM);
|
||||
} else if (newValue.equals(manualProxyBtn)) {
|
||||
settings.networkSettings.get().mode.set(NetworkSettings.ProxyMode.MANUAL);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void initializeTextFieldWithValidation(TextField textField, StringProperty property) {
|
||||
textField.setText(property.get());
|
||||
|
||||
textField.textProperty().addListener((_, _, newValue) -> {
|
||||
if (isValidHttpProxy(newValue)) {
|
||||
textField.setStyle("-fx-border-color: green; -fx-border-width: 2px; -fx-border-radius: 3px; -fx-padding: 3px;");
|
||||
} else {
|
||||
textField.setStyle("-fx-border-color: red; -fx-border-width: 2px; -fx-border-radius: 3px; -fx-padding: 3px;");
|
||||
}
|
||||
});
|
||||
|
||||
textField.focusedProperty().addListener((_, oldValue, newValue) -> {
|
||||
if (!newValue) {
|
||||
String text = textField.getText();
|
||||
if (isValidHttpProxy(text)) {
|
||||
property.set(text);
|
||||
textField.setStyle("");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isValidHttpProxy(String text) {
|
||||
if (text == null || text.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
String regex = "^([\\w.-]+)$";
|
||||
return text.matches(regex);
|
||||
}
|
||||
|
||||
private void initializeTextFieldWithValidation(TextField textField, IntegerProperty property) {
|
||||
textField.setText(String.valueOf(property.get()));
|
||||
|
||||
textField.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (isValidPort(newValue)) {
|
||||
textField.setStyle("-fx-border-color: green; -fx-border-width: 2px; -fx-border-radius: 3px; -fx-padding: 3px;");
|
||||
} else {
|
||||
textField.setStyle("-fx-border-color: red; -fx-border-width: 2px; -fx-border-radius: 3px; -fx-padding: 3px;");
|
||||
}
|
||||
});
|
||||
|
||||
textField.focusedProperty().addListener((_, _, newValue) -> {
|
||||
if (!newValue) {
|
||||
String text = textField.getText();
|
||||
if (isValidPort(text)) {
|
||||
property.set(Integer.parseInt(text));
|
||||
textField.setText(removeLeadingZeros(textField.getText()));
|
||||
textField.setStyle("");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static String removeLeadingZeros(String str) {
|
||||
if (str == null || str.isEmpty()) {
|
||||
return str;
|
||||
}
|
||||
return str.replaceFirst("^0+(?!$)", "");
|
||||
}
|
||||
|
||||
private boolean isValidPort(String text) {
|
||||
if (text == null || text.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
int value = Integer.parseInt(text);
|
||||
return value >= 1024 && value <= 8888;
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ public class PreferencesController implements FxController {
|
||||
public Tab updatesTab;
|
||||
public Tab contributeTab;
|
||||
public Tab aboutTab;
|
||||
public Tab networkTab;
|
||||
|
||||
@Inject
|
||||
public PreferencesController(Environment env, @PreferencesWindow Stage window, ObjectProperty<SelectedPreferencesTab> selectedTabProperty, UpdateChecker updateChecker) {
|
||||
@@ -63,6 +64,7 @@ public class PreferencesController implements FxController {
|
||||
case UPDATES -> updatesTab;
|
||||
case CONTRIBUTE -> contributeTab;
|
||||
case ABOUT -> aboutTab;
|
||||
case NETWORK -> networkTab;
|
||||
case ANY -> updateAvailable.get() ? updatesTab : generalTab;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -89,4 +89,9 @@ abstract class PreferencesModule {
|
||||
@FxControllerKey(AboutController.class)
|
||||
abstract FxController bindAboutController(AboutController controller);
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(NetworkPreferencesController.class)
|
||||
abstract FxController bindNetworkPreferencesController(NetworkPreferencesController controller);
|
||||
|
||||
}
|
||||
|
||||
@@ -35,4 +35,8 @@ public enum SelectedPreferencesTab {
|
||||
* Show about tab
|
||||
*/
|
||||
ABOUT,
|
||||
/**
|
||||
* Show network tab
|
||||
*/
|
||||
NETWORK
|
||||
}
|
||||
|
||||
@@ -46,6 +46,14 @@
|
||||
<fx:include source="preferences_updates.fxml"/>
|
||||
</content>
|
||||
</Tab>
|
||||
<Tab fx:id="network" id="NETWORK" text="%preferences.network">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="NETWORK"/>
|
||||
</graphic>
|
||||
<content>
|
||||
<fx:include source="preferences_network.fxml"/>
|
||||
</content>
|
||||
</Tab>
|
||||
<Tab fx:id="contributeTab" id="CONTRIBUTE" text="%preferences.contribute">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="HEART"/>
|
||||
|
||||
50
src/main/resources/fxml/preferences_network.fxml
Normal file
50
src/main/resources/fxml/preferences_network.fxml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.RadioButton?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.control.TextField?>
|
||||
|
||||
<?import javafx.scene.control.CheckBox?>
|
||||
<?import javafx.scene.control.ToggleGroup?>
|
||||
<?import org.cryptomator.ui.controls.NumericTextField?>
|
||||
<VBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.preferences.NetworkPreferencesController"
|
||||
spacing="24">
|
||||
<fx:define>
|
||||
<ToggleGroup fx:id="proxyToggleGroup"/>
|
||||
</fx:define>
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="24"/>
|
||||
</padding>
|
||||
<VBox>
|
||||
<Label text="Configure Proxy Access to the Internet"/>
|
||||
<RadioButton fx:id="noProxyBtn" text="No Proxy" toggleGroup="${proxyToggleGroup}" />
|
||||
<RadioButton fx:id="systemSettingsBtn" text="Use system proxy settings" toggleGroup="${proxyToggleGroup}" />
|
||||
<RadioButton fx:id="manualProxyBtn" text="Manual proxy configuration" toggleGroup="${proxyToggleGroup}" />
|
||||
<VBox fx:id="manualProxyBox">
|
||||
<padding>
|
||||
<Insets left="24"/>
|
||||
</padding>
|
||||
<HBox spacing="12" alignment="CENTER_LEFT">
|
||||
<Label text="HTTP Proxy" minWidth="90" />
|
||||
<TextField fx:id="httpProxy" HBox.hgrow="ALWAYS" />
|
||||
<Label text="Port"/>
|
||||
<NumericTextField fx:id="httpPort" prefWidth="60" promptText="0" />
|
||||
</HBox>
|
||||
<CheckBox fx:id="samePortProxyForHttpHttps" text="Also use this proxy for HTTPS"/>
|
||||
<HBox fx:id="httpsProxyBox" spacing="12" alignment="CENTER_LEFT">
|
||||
<Label text="HTTPS Proxy" minWidth="90"/>
|
||||
<TextField fx:id="httpsProxy" HBox.hgrow="ALWAYS" />
|
||||
<Label text="Port"/>
|
||||
<NumericTextField fx:id="httpsPort" prefWidth="60" promptText="0"/>
|
||||
</HBox>
|
||||
</VBox>
|
||||
|
||||
</VBox>
|
||||
|
||||
|
||||
</VBox>
|
||||
@@ -328,6 +328,8 @@ preferences.updates.lastUpdateCheck.daysAgo=%s days ago
|
||||
preferences.updates.lastUpdateCheck.hoursAgo=%s hours ago
|
||||
preferences.updates.checkFailed=Looking for updates failed. Please check your internet connection or try again later.
|
||||
preferences.updates.upToDate=Cryptomator is up-to-date.
|
||||
## Network
|
||||
preferences.network=Network
|
||||
|
||||
## Contribution
|
||||
preferences.contribute=Support Us
|
||||
|
||||
Reference in New Issue
Block a user