diff --git a/pom.xml b/pom.xml
index 0ddf03d29..f50685384 100644
--- a/pom.xml
+++ b/pom.xml
@@ -164,11 +164,18 @@
nimbus-jose-jwt
${nimbus-jose.version}
+
+
com.fasterxml.jackson.core
jackson-databind
${jackson.version}
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jsr310
+ ${jackson.version}
+
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index b353b7a8a..cfac6bbeb 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -39,6 +39,7 @@ open module org.cryptomator.desktop {
requires com.auth0.jwt;
requires com.google.common;
requires com.fasterxml.jackson.databind;
+ requires com.fasterxml.jackson.datatype.jsr310;
requires com.nimbusds.jose.jwt;
requires com.nulabinc.zxcvbn;
requires com.tobiasdiez.easybind;
diff --git a/src/main/java/org/cryptomator/common/settings/Settings.java b/src/main/java/org/cryptomator/common/settings/Settings.java
index f17a1f802..be0361153 100644
--- a/src/main/java/org/cryptomator/common/settings/Settings.java
+++ b/src/main/java/org/cryptomator/common/settings/Settings.java
@@ -26,7 +26,6 @@ import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.NodeOrientation;
import java.time.Instant;
-import java.util.Date;
import java.util.function.Consumer;
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_USER_INTERFACE_ORIENTATION = NodeOrientation.LEFT_TO_RIGHT.name();
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_LAST_SUCCESSFUL_UPDATE_CHECK = Instant.ofEpochSecond(946681200); //2000-01-01T00:00:00Z
+ public static final Instant DEFAULT_TIMESTAMP = Instant.parse("2000-01-01T00:00:00Z");
public final ObservableList directories;
public final BooleanProperty askedForUpdateCheck;
public final BooleanProperty checkForUpdates;
@@ -71,7 +69,6 @@ public class Settings {
public final StringProperty mountService;
public final ObjectProperty lastUpdateReminder;
public final ObjectProperty lastSuccessfulUpdateCheck;
- public final StringProperty latestVersion;
private Consumer saveCmd;
@@ -108,9 +105,8 @@ public class Settings {
this.windowHeight = new SimpleIntegerProperty(this, "windowHeight", json.windowHeight);
this.language = new SimpleStringProperty(this, "language", json.language);
this.mountService = new SimpleStringProperty(this, "mountService", json.mountService);
- this.lastUpdateReminder = new SimpleObjectProperty<>(this, "lastUpdateReminder", json.lastUpdateReminder.toInstant());
- this.lastSuccessfulUpdateCheck = new SimpleObjectProperty<>(this, "lastSuccessfulUpdateCheck", json.lastSuccessfulUpdateCheck.toInstant());
- this.latestVersion = new SimpleStringProperty(this, "latestVersion", json.latestVersion);
+ this.lastUpdateReminder = new SimpleObjectProperty<>(this, "lastUpdateReminder", json.lastUpdateReminder);
+ this.lastSuccessfulUpdateCheck = new SimpleObjectProperty<>(this, "lastSuccessfulUpdateCheck", json.lastSuccessfulUpdateCheck);
this.directories.addAll(json.directories.stream().map(VaultSettings::new).toList());
@@ -139,7 +135,6 @@ public class Settings {
mountService.addListener(this::somethingChanged);
lastUpdateReminder.addListener(this::somethingChanged);
lastSuccessfulUpdateCheck.addListener(this::somethingChanged);
- latestVersion.addListener(this::somethingChanged);
}
@SuppressWarnings("deprecation")
@@ -193,9 +188,8 @@ public class Settings {
json.windowHeight = windowHeight.get();
json.language = language.get();
json.mountService = mountService.get();
- json.lastUpdateReminder = Date.from(lastUpdateReminder.get());
- json.lastSuccessfulUpdateCheck = Date.from(lastSuccessfulUpdateCheck.get());
- json.latestVersion = latestVersion.get();
+ json.lastUpdateReminder = lastUpdateReminder.get();
+ json.lastSuccessfulUpdateCheck = lastSuccessfulUpdateCheck.get();
return json;
}
diff --git a/src/main/java/org/cryptomator/common/settings/SettingsJson.java b/src/main/java/org/cryptomator/common/settings/SettingsJson.java
index ebaf841ed..0acd72fe7 100644
--- a/src/main/java/org/cryptomator/common/settings/SettingsJson.java
+++ b/src/main/java/org/cryptomator/common/settings/SettingsJson.java
@@ -5,7 +5,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
-import java.util.Date;
+import java.time.Instant;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
@@ -83,14 +83,11 @@ class SettingsJson {
String preferredVolumeImpl;
@JsonProperty("lastUpdateReminder")
- @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
- Date lastUpdateReminder = Date.from(Settings.DEFAULT_LAST_UPDATE_REMINDER);
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'", timezone = "UTC")
+ Instant lastUpdateReminder = Settings.DEFAULT_TIMESTAMP;
@JsonProperty("lastSuccessfulUpdateCheck")
- @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss z")
- Date lastSuccessfulUpdateCheck = Date.from(Settings.DEFAULT_LAST_SUCCESSFUL_UPDATE_CHECK);
-
- @JsonProperty("latestVersion")
- String latestVersion;
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'", timezone = "UTC")
+ Instant lastSuccessfulUpdateCheck = Settings.DEFAULT_TIMESTAMP;
}
diff --git a/src/main/java/org/cryptomator/common/settings/SettingsProvider.java b/src/main/java/org/cryptomator/common/settings/SettingsProvider.java
index 586708ed1..a33b51027 100644
--- a/src/main/java/org/cryptomator/common/settings/SettingsProvider.java
+++ b/src/main/java/org/cryptomator/common/settings/SettingsProvider.java
@@ -10,6 +10,7 @@ package org.cryptomator.common.settings;
import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.google.common.base.Suppliers;
import org.cryptomator.common.Environment;
import org.slf4j.Logger;
@@ -36,7 +37,7 @@ import java.util.stream.Stream;
@Singleton
public class SettingsProvider implements Supplier {
- 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 long SAVE_DELAY_MS = 1000;
diff --git a/src/main/java/org/cryptomator/ui/fxapp/UpdateChecker.java b/src/main/java/org/cryptomator/ui/fxapp/UpdateChecker.java
index 32267f27c..0d266dd02 100644
--- a/src/main/java/org/cryptomator/ui/fxapp/UpdateChecker.java
+++ b/src/main/java/org/cryptomator/ui/fxapp/UpdateChecker.java
@@ -35,6 +35,7 @@ public class UpdateChecker {
private final ObjectProperty lastSuccessfulUpdateCheck = new SimpleObjectProperty<>();
private final Comparator versionComparator = new SemVerComparator();
private final BooleanBinding updateAvailable;
+ private final BooleanBinding checkFailed;
@Inject
UpdateChecker(Settings settings, //
@@ -43,13 +44,13 @@ public class UpdateChecker {
this.env = env;
this.settings = settings;
this.updateCheckerService = updateCheckerService;
- this.latestVersion.bindBidirectional(settings.latestVersion);
this.lastSuccessfulUpdateCheck.bindBidirectional(settings.lastSuccessfulUpdateCheck);
this.updateAvailable = Bindings.createBooleanBinding(() -> {
var latestVersion = this.latestVersion.get();
return latestVersion != null && versionComparator.compare(getCurrentVersion(), latestVersion) < 0;
}, latestVersion);
+ this.checkFailed = Bindings.createBooleanBinding(() -> state.isEqualTo(UpdateChecker.UpdateCheckState.CHECK_FAILED).get(), state);
}
public void automaticallyCheckForUpdatesIfEnabled() {
@@ -87,7 +88,6 @@ public class UpdateChecker {
private void checkFailed(WorkerStateEvent event) {
state.set(UpdateCheckState.CHECK_FAILED);
- LOG.warn("Error checking for updates", event.getSource().getException());
}
public enum UpdateCheckState {
@@ -109,6 +109,9 @@ public class UpdateChecker {
public BooleanBinding updateAvailableProperty() {
return updateAvailable;
}
+ public BooleanBinding checkFailedProperty() {
+ return checkFailed;
+ }
public boolean isUpdateAvailable() {
return updateAvailable.get();
diff --git a/src/main/java/org/cryptomator/ui/preferences/UpdatesPreferencesController.java b/src/main/java/org/cryptomator/ui/preferences/UpdatesPreferencesController.java
index e5597db08..ebfee8689 100644
--- a/src/main/java/org/cryptomator/ui/preferences/UpdatesPreferencesController.java
+++ b/src/main/java/org/cryptomator/ui/preferences/UpdatesPreferencesController.java
@@ -47,10 +47,11 @@ public class UpdatesPreferencesController implements FxController {
private final ObservableValue timeDifferenceMessage;
private final String currentVersion;
private final BooleanBinding updateAvailable;
+ private final BooleanBinding checkFailed;
private final BooleanProperty upToDateLabelVisible = new SimpleBooleanProperty(false);
private final ObjectProperty updateCheckState;
private final DateTimeFormatter formatter;
- private final BooleanBinding isUpdateSuccessfulAndCurrent;
+ private final BooleanBinding upToDate;
/* FXML */
public CheckBox checkForUpdatesCheckbox;
@@ -72,13 +73,14 @@ public class UpdatesPreferencesController implements FxController {
this.updateAvailable = updateChecker.updateAvailableProperty();
this.updateCheckState = updateChecker.updateCheckStateProperty();
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() {
checkForUpdatesCheckbox.selectedProperty().bindBidirectional(settings.checkForUpdates);
- isUpdateSuccessfulAndCurrent.addListener((_, _, newVal) -> {
+ upToDate.addListener((_, _, newVal) -> {
if (newVal) {
upToDateLabelVisible.set(true);
PauseTransition delay = new PauseTransition(javafx.util.Duration.seconds(5));
@@ -131,7 +133,7 @@ public class UpdatesPreferencesController implements FxController {
public String getLastSuccessfulUpdateCheck() {
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()));
} else {
return "-";
@@ -139,7 +141,7 @@ public class UpdatesPreferencesController implements FxController {
}
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");
}
@@ -180,11 +182,11 @@ public class UpdatesPreferencesController implements FxController {
}
public BooleanBinding checkFailedProperty() {
- return updateCheckState.isEqualTo(UpdateChecker.UpdateCheckState.CHECK_FAILED);
+ return checkFailed;
}
public boolean isCheckFailed() {
- return checkFailedProperty().get();
+ return checkFailed.get();
}
}
diff --git a/src/main/java/org/cryptomator/ui/updatereminder/UpdateReminderComponent.java b/src/main/java/org/cryptomator/ui/updatereminder/UpdateReminderComponent.java
index ffd127451..dfa1e5484 100644
--- a/src/main/java/org/cryptomator/ui/updatereminder/UpdateReminderComponent.java
+++ b/src/main/java/org/cryptomator/ui/updatereminder/UpdateReminderComponent.java
@@ -25,7 +25,8 @@ public interface UpdateReminderComponent {
default void checkAndShowUpdateReminderWindow() {
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);
Stage stage = window();
stage.setScene(updateReminderScene().get());
diff --git a/src/main/resources/fxml/preferences_updates.fxml b/src/main/resources/fxml/preferences_updates.fxml
index 66e15d695..97c917603 100644
--- a/src/main/resources/fxml/preferences_updates.fxml
+++ b/src/main/resources/fxml/preferences_updates.fxml
@@ -12,6 +12,8 @@
+
+
-
-
+
+
+
+
+
+
+
diff --git a/src/main/resources/i18n/strings.properties b/src/main/resources/i18n/strings.properties
index cbefacd21..0fbe68ca8 100644
--- a/src/main/resources/i18n/strings.properties
+++ b/src/main/resources/i18n/strings.properties
@@ -326,7 +326,7 @@ preferences.updates.lastUpdateCheck.never=never
preferences.updates.lastUpdateCheck.recently=recently
preferences.updates.lastUpdateCheck.daysAgo=%s days 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.
## Contribution