introduced new dependency

removed latestVersion from Settings
changed SettingsJson from Date to Instant
new UpdateChecker Property checkFailed
optimized naming
changed wordning
refactoring
This commit is contained in:
Jan-Peter Klein 2024-04-29 10:34:17 +02:00
parent ae697d7b73
commit b16f32ca83
No known key found for this signature in database
GPG Key ID: 90EDA3A7C822FD0E
10 changed files with 46 additions and 37 deletions

View File

@ -164,11 +164,18 @@
<artifactId>nimbus-jose-jwt</artifactId> <artifactId>nimbus-jose-jwt</artifactId>
<version>${nimbus-jose.version}</version> <version>${nimbus-jose.version}</version>
</dependency> </dependency>
<!-- Jackson -->
<dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId> <groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId> <artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version> <version>${jackson.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- EasyBind --> <!-- EasyBind -->
<dependency> <dependency>

View File

@ -39,6 +39,7 @@ open module org.cryptomator.desktop {
requires com.auth0.jwt; requires com.auth0.jwt;
requires com.google.common; requires com.google.common;
requires com.fasterxml.jackson.databind; requires com.fasterxml.jackson.databind;
requires com.fasterxml.jackson.datatype.jsr310;
requires com.nimbusds.jose.jwt; requires com.nimbusds.jose.jwt;
requires com.nulabinc.zxcvbn; requires com.nulabinc.zxcvbn;
requires com.tobiasdiez.easybind; requires com.tobiasdiez.easybind;

View File

@ -26,7 +26,6 @@ import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.geometry.NodeOrientation; import javafx.geometry.NodeOrientation;
import java.time.Instant; import java.time.Instant;
import java.util.Date;
import java.util.function.Consumer; import java.util.function.Consumer;
public class Settings { public class Settings {
@ -46,8 +45,7 @@ public class Settings {
static final String DEFAULT_KEYCHAIN_PROVIDER = SystemUtils.IS_OS_WINDOWS ? "org.cryptomator.windows.keychain.WindowsProtectedKeychainAccess" : SystemUtils.IS_OS_MAC ? "org.cryptomator.macos.keychain.MacSystemKeychainAccess" : "org.cryptomator.linux.keychain.SecretServiceKeychainAccess"; static final String DEFAULT_KEYCHAIN_PROVIDER = SystemUtils.IS_OS_WINDOWS ? "org.cryptomator.windows.keychain.WindowsProtectedKeychainAccess" : SystemUtils.IS_OS_MAC ? "org.cryptomator.macos.keychain.MacSystemKeychainAccess" : "org.cryptomator.linux.keychain.SecretServiceKeychainAccess";
static final String DEFAULT_USER_INTERFACE_ORIENTATION = NodeOrientation.LEFT_TO_RIGHT.name(); static final String DEFAULT_USER_INTERFACE_ORIENTATION = NodeOrientation.LEFT_TO_RIGHT.name();
static final boolean DEFAULT_SHOW_MINIMIZE_BUTTON = false; static final boolean DEFAULT_SHOW_MINIMIZE_BUTTON = false;
static final Instant DEFAULT_LAST_UPDATE_REMINDER = Instant.ofEpochSecond(946681200); //2000-01-01T00:00:00Z public static final Instant DEFAULT_TIMESTAMP = Instant.parse("2000-01-01T00:00:00Z");
public static final Instant DEFAULT_LAST_SUCCESSFUL_UPDATE_CHECK = Instant.ofEpochSecond(946681200); //2000-01-01T00:00:00Z
public final ObservableList<VaultSettings> directories; public final ObservableList<VaultSettings> directories;
public final BooleanProperty askedForUpdateCheck; public final BooleanProperty askedForUpdateCheck;
public final BooleanProperty checkForUpdates; public final BooleanProperty checkForUpdates;
@ -71,7 +69,6 @@ public class Settings {
public final StringProperty mountService; public final StringProperty mountService;
public final ObjectProperty<Instant> lastUpdateReminder; public final ObjectProperty<Instant> lastUpdateReminder;
public final ObjectProperty<Instant> lastSuccessfulUpdateCheck; public final ObjectProperty<Instant> lastSuccessfulUpdateCheck;
public final StringProperty latestVersion;
private Consumer<Settings> saveCmd; private Consumer<Settings> saveCmd;
@ -108,9 +105,8 @@ public class Settings {
this.windowHeight = new SimpleIntegerProperty(this, "windowHeight", json.windowHeight); this.windowHeight = new SimpleIntegerProperty(this, "windowHeight", json.windowHeight);
this.language = new SimpleStringProperty(this, "language", json.language); this.language = new SimpleStringProperty(this, "language", json.language);
this.mountService = new SimpleStringProperty(this, "mountService", json.mountService); this.mountService = new SimpleStringProperty(this, "mountService", json.mountService);
this.lastUpdateReminder = new SimpleObjectProperty<>(this, "lastUpdateReminder", json.lastUpdateReminder.toInstant()); this.lastUpdateReminder = new SimpleObjectProperty<>(this, "lastUpdateReminder", json.lastUpdateReminder);
this.lastSuccessfulUpdateCheck = new SimpleObjectProperty<>(this, "lastSuccessfulUpdateCheck", json.lastSuccessfulUpdateCheck.toInstant()); this.lastSuccessfulUpdateCheck = new SimpleObjectProperty<>(this, "lastSuccessfulUpdateCheck", json.lastSuccessfulUpdateCheck);
this.latestVersion = new SimpleStringProperty(this, "latestVersion", json.latestVersion);
this.directories.addAll(json.directories.stream().map(VaultSettings::new).toList()); this.directories.addAll(json.directories.stream().map(VaultSettings::new).toList());
@ -139,7 +135,6 @@ public class Settings {
mountService.addListener(this::somethingChanged); mountService.addListener(this::somethingChanged);
lastUpdateReminder.addListener(this::somethingChanged); lastUpdateReminder.addListener(this::somethingChanged);
lastSuccessfulUpdateCheck.addListener(this::somethingChanged); lastSuccessfulUpdateCheck.addListener(this::somethingChanged);
latestVersion.addListener(this::somethingChanged);
} }
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@ -193,9 +188,8 @@ public class Settings {
json.windowHeight = windowHeight.get(); json.windowHeight = windowHeight.get();
json.language = language.get(); json.language = language.get();
json.mountService = mountService.get(); json.mountService = mountService.get();
json.lastUpdateReminder = Date.from(lastUpdateReminder.get()); json.lastUpdateReminder = lastUpdateReminder.get();
json.lastSuccessfulUpdateCheck = Date.from(lastSuccessfulUpdateCheck.get()); json.lastSuccessfulUpdateCheck = lastSuccessfulUpdateCheck.get();
json.latestVersion = latestVersion.get();
return json; return json;
} }

View File

@ -5,7 +5,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Date; import java.time.Instant;
import java.util.List; import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
@ -83,14 +83,11 @@ class SettingsJson {
String preferredVolumeImpl; String preferredVolumeImpl;
@JsonProperty("lastUpdateReminder") @JsonProperty("lastUpdateReminder")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'", timezone = "UTC")
Date lastUpdateReminder = Date.from(Settings.DEFAULT_LAST_UPDATE_REMINDER); Instant lastUpdateReminder = Settings.DEFAULT_TIMESTAMP;
@JsonProperty("lastSuccessfulUpdateCheck") @JsonProperty("lastSuccessfulUpdateCheck")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss z") @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'", timezone = "UTC")
Date lastSuccessfulUpdateCheck = Date.from(Settings.DEFAULT_LAST_SUCCESSFUL_UPDATE_CHECK); Instant lastSuccessfulUpdateCheck = Settings.DEFAULT_TIMESTAMP;
@JsonProperty("latestVersion")
String latestVersion;
} }

View File

@ -10,6 +10,7 @@ package org.cryptomator.common.settings;
import com.fasterxml.jackson.core.JacksonException; import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
import org.cryptomator.common.Environment; import org.cryptomator.common.Environment;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -36,7 +37,7 @@ import java.util.stream.Stream;
@Singleton @Singleton
public class SettingsProvider implements Supplier<Settings> { public class SettingsProvider implements Supplier<Settings> {
private static final ObjectMapper JSON = new ObjectMapper().setDefaultLeniency(true); private static final ObjectMapper JSON = new ObjectMapper().setDefaultLeniency(true).registerModule(new JavaTimeModule());
private static final Logger LOG = LoggerFactory.getLogger(SettingsProvider.class); private static final Logger LOG = LoggerFactory.getLogger(SettingsProvider.class);
private static final long SAVE_DELAY_MS = 1000; private static final long SAVE_DELAY_MS = 1000;

View File

@ -35,6 +35,7 @@ public class UpdateChecker {
private final ObjectProperty<Instant> lastSuccessfulUpdateCheck = new SimpleObjectProperty<>(); private final ObjectProperty<Instant> lastSuccessfulUpdateCheck = new SimpleObjectProperty<>();
private final Comparator<String> versionComparator = new SemVerComparator(); private final Comparator<String> versionComparator = new SemVerComparator();
private final BooleanBinding updateAvailable; private final BooleanBinding updateAvailable;
private final BooleanBinding checkFailed;
@Inject @Inject
UpdateChecker(Settings settings, // UpdateChecker(Settings settings, //
@ -43,13 +44,13 @@ public class UpdateChecker {
this.env = env; this.env = env;
this.settings = settings; this.settings = settings;
this.updateCheckerService = updateCheckerService; this.updateCheckerService = updateCheckerService;
this.latestVersion.bindBidirectional(settings.latestVersion);
this.lastSuccessfulUpdateCheck.bindBidirectional(settings.lastSuccessfulUpdateCheck); this.lastSuccessfulUpdateCheck.bindBidirectional(settings.lastSuccessfulUpdateCheck);
this.updateAvailable = Bindings.createBooleanBinding(() -> { this.updateAvailable = Bindings.createBooleanBinding(() -> {
var latestVersion = this.latestVersion.get(); var latestVersion = this.latestVersion.get();
return latestVersion != null && versionComparator.compare(getCurrentVersion(), latestVersion) < 0; return latestVersion != null && versionComparator.compare(getCurrentVersion(), latestVersion) < 0;
}, latestVersion); }, latestVersion);
this.checkFailed = Bindings.createBooleanBinding(() -> state.isEqualTo(UpdateChecker.UpdateCheckState.CHECK_FAILED).get(), state);
} }
public void automaticallyCheckForUpdatesIfEnabled() { public void automaticallyCheckForUpdatesIfEnabled() {
@ -87,7 +88,6 @@ public class UpdateChecker {
private void checkFailed(WorkerStateEvent event) { private void checkFailed(WorkerStateEvent event) {
state.set(UpdateCheckState.CHECK_FAILED); state.set(UpdateCheckState.CHECK_FAILED);
LOG.warn("Error checking for updates", event.getSource().getException());
} }
public enum UpdateCheckState { public enum UpdateCheckState {
@ -109,6 +109,9 @@ public class UpdateChecker {
public BooleanBinding updateAvailableProperty() { public BooleanBinding updateAvailableProperty() {
return updateAvailable; return updateAvailable;
} }
public BooleanBinding checkFailedProperty() {
return checkFailed;
}
public boolean isUpdateAvailable() { public boolean isUpdateAvailable() {
return updateAvailable.get(); return updateAvailable.get();

View File

@ -47,10 +47,11 @@ public class UpdatesPreferencesController implements FxController {
private final ObservableValue<String> timeDifferenceMessage; private final ObservableValue<String> timeDifferenceMessage;
private final String currentVersion; private final String currentVersion;
private final BooleanBinding updateAvailable; private final BooleanBinding updateAvailable;
private final BooleanBinding checkFailed;
private final BooleanProperty upToDateLabelVisible = new SimpleBooleanProperty(false); private final BooleanProperty upToDateLabelVisible = new SimpleBooleanProperty(false);
private final ObjectProperty<UpdateChecker.UpdateCheckState> updateCheckState; private final ObjectProperty<UpdateChecker.UpdateCheckState> updateCheckState;
private final DateTimeFormatter formatter; private final DateTimeFormatter formatter;
private final BooleanBinding isUpdateSuccessfulAndCurrent; private final BooleanBinding upToDate;
/* FXML */ /* FXML */
public CheckBox checkForUpdatesCheckbox; public CheckBox checkForUpdatesCheckbox;
@ -72,13 +73,14 @@ public class UpdatesPreferencesController implements FxController {
this.updateAvailable = updateChecker.updateAvailableProperty(); this.updateAvailable = updateChecker.updateAvailableProperty();
this.updateCheckState = updateChecker.updateCheckStateProperty(); this.updateCheckState = updateChecker.updateCheckStateProperty();
this.formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(Locale.getDefault()); this.formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(Locale.getDefault());
this.isUpdateSuccessfulAndCurrent = updateCheckState.isEqualTo(UpdateChecker.UpdateCheckState.CHECK_SUCCESSFUL).and(latestVersion.isEqualTo(currentVersion)); this.upToDate = updateCheckState.isEqualTo(UpdateChecker.UpdateCheckState.CHECK_SUCCESSFUL).and(latestVersion.isEqualTo(currentVersion));
this.checkFailed = updateChecker.checkFailedProperty();
} }
public void initialize() { public void initialize() {
checkForUpdatesCheckbox.selectedProperty().bindBidirectional(settings.checkForUpdates); checkForUpdatesCheckbox.selectedProperty().bindBidirectional(settings.checkForUpdates);
isUpdateSuccessfulAndCurrent.addListener((_, _, newVal) -> { upToDate.addListener((_, _, newVal) -> {
if (newVal) { if (newVal) {
upToDateLabelVisible.set(true); upToDateLabelVisible.set(true);
PauseTransition delay = new PauseTransition(javafx.util.Duration.seconds(5)); PauseTransition delay = new PauseTransition(javafx.util.Duration.seconds(5));
@ -131,7 +133,7 @@ public class UpdatesPreferencesController implements FxController {
public String getLastSuccessfulUpdateCheck() { public String getLastSuccessfulUpdateCheck() {
Instant lastCheck = lastSuccessfulUpdateCheck.getValue(); Instant lastCheck = lastSuccessfulUpdateCheck.getValue();
if (lastCheck != null && !lastCheck.equals(Settings.DEFAULT_LAST_SUCCESSFUL_UPDATE_CHECK)) { if (lastCheck != null && !lastCheck.equals(Settings.DEFAULT_TIMESTAMP)) {
return formatter.format(LocalDateTime.ofInstant(lastCheck, ZoneId.systemDefault())); return formatter.format(LocalDateTime.ofInstant(lastCheck, ZoneId.systemDefault()));
} else { } else {
return "-"; return "-";
@ -139,7 +141,7 @@ public class UpdatesPreferencesController implements FxController {
} }
private String updateTimeDifferenceMessage(Instant lastSuccessCheck) { private String updateTimeDifferenceMessage(Instant lastSuccessCheck) {
if (lastSuccessCheck.equals(Settings.DEFAULT_LAST_SUCCESSFUL_UPDATE_CHECK)) { if (lastSuccessCheck.equals(Settings.DEFAULT_TIMESTAMP)) {
return resourceBundle.getString("preferences.updates.lastUpdateCheck.never"); return resourceBundle.getString("preferences.updates.lastUpdateCheck.never");
} }
@ -180,11 +182,11 @@ public class UpdatesPreferencesController implements FxController {
} }
public BooleanBinding checkFailedProperty() { public BooleanBinding checkFailedProperty() {
return updateCheckState.isEqualTo(UpdateChecker.UpdateCheckState.CHECK_FAILED); return checkFailed;
} }
public boolean isCheckFailed() { public boolean isCheckFailed() {
return checkFailedProperty().get(); return checkFailed.get();
} }
} }

View File

@ -25,7 +25,8 @@ public interface UpdateReminderComponent {
default void checkAndShowUpdateReminderWindow() { default void checkAndShowUpdateReminderWindow() {
var now = Instant.now(); var now = Instant.now();
if (settings().lastUpdateReminder.get().isBefore(now.minus(Duration.ofDays(14))) && !settings().checkForUpdates.getValue()) { var twoWeeksAgo = now.minus(Duration.ofDays(14));
if (settings().lastUpdateReminder.get().isBefore(twoWeeksAgo) && !settings().checkForUpdates.getValue() && settings().lastSuccessfulUpdateCheck.get().isBefore(twoWeeksAgo)) {
settings().lastUpdateReminder.set(now); settings().lastUpdateReminder.set(now);
Stage stage = window(); Stage stage = window();
stage.setScene(updateReminderScene().get()); stage.setScene(updateReminderScene().get());

View File

@ -12,6 +12,8 @@
<?import javafx.scene.layout.HBox?> <?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?> <?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Tooltip?> <?import javafx.scene.control.Tooltip?>
<?import javafx.scene.text.TextFlow?>
<?import javafx.scene.text.Text?>
<VBox xmlns:fx="http://javafx.com/fxml" <VBox xmlns:fx="http://javafx.com/fxml"
xmlns="http://javafx.com/javafx" xmlns="http://javafx.com/javafx"
fx:controller="org.cryptomator.ui.preferences.UpdatesPreferencesController" fx:controller="org.cryptomator.ui.preferences.UpdatesPreferencesController"
@ -34,12 +36,13 @@
</Button> </Button>
<HBox fx:id="checkFailedHBox" spacing="12" alignment="CENTER" visible="${controller.checkFailed}" managed="${controller.checkFailed}"> <HBox fx:id="checkFailedHBox" spacing="12" alignment="CENTER" visible="${controller.checkFailed}" managed="${controller.checkFailed}">
<Label text="%preferences.updates.checkFailed" wrapText="true"> <TextFlow styleClass="text-flow" textAlignment="CENTER">
<graphic> <FontAwesome5IconView glyphSize="12" styleClass="glyph-icon-orange" glyph="EXCLAMATION_TRIANGLE"/>
<FontAwesome5IconView glyphSize="12" styleClass="glyph-icon-orange" glyph="EXCLAMATION_TRIANGLE"/> <Text text=" "/>
</graphic> <Text text="%preferences.updates.checkFailed"/>
</Label> <Text text=" "/>
<Hyperlink styleClass="hyperlink-underline" text="%preferences.general.debugDirectory" onAction="#showLogfileDirectory"/> <Hyperlink styleClass="hyperlink-underline" text="%preferences.general.debugDirectory" onAction="#showLogfileDirectory"/>
</TextFlow>
</HBox> </HBox>
<FormattedLabel format="%preferences.updates.lastUpdateCheck" arg1="${controller.timeDifferenceMessage}" textAlignment="CENTER" wrapText="true"> <FormattedLabel format="%preferences.updates.lastUpdateCheck" arg1="${controller.timeDifferenceMessage}" textAlignment="CENTER" wrapText="true">
<tooltip> <tooltip>

View File

@ -326,7 +326,7 @@ preferences.updates.lastUpdateCheck.never=never
preferences.updates.lastUpdateCheck.recently=recently preferences.updates.lastUpdateCheck.recently=recently
preferences.updates.lastUpdateCheck.daysAgo=%s days ago preferences.updates.lastUpdateCheck.daysAgo=%s days ago
preferences.updates.lastUpdateCheck.hoursAgo=%s hours ago preferences.updates.lastUpdateCheck.hoursAgo=%s hours ago
preferences.updates.checkFailed=Check failed preferences.updates.checkFailed=Looking for updates failed. Please check your internet connection and try again later.
preferences.updates.upToDate=Cryptomator is up-to-date. preferences.updates.upToDate=Cryptomator is up-to-date.
## Contribution ## Contribution