refactored updateChecker by incorporating state management and date tracking

This commit is contained in:
Jan-Peter Klein
2024-02-29 09:29:26 +01:00
parent 2302db6206
commit 4064b61cd7
5 changed files with 96 additions and 42 deletions

View File

@@ -2,44 +2,50 @@ package org.cryptomator.ui.fxapp;
import org.cryptomator.common.Environment;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.ui.health.Check;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Named;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.concurrent.ScheduledService;
import javafx.concurrent.Worker;
import javafx.concurrent.WorkerStateEvent;
import javafx.util.Duration;
import java.time.LocalDateTime;
import java.util.Comparator;
@FxApplicationScoped
public class UpdateChecker {
private static final Logger LOG = LoggerFactory.getLogger(UpdateChecker.class);
private static final Duration AUTOCHECK_DELAY = Duration.seconds(5);
private static final Duration AUTO_CHECK_DELAY = Duration.seconds(5);
private final Environment env;
private final Settings settings;
private final StringProperty latestVersionProperty;
private final Comparator<String> semVerComparator;
private final StringProperty latestVersionProperty = new SimpleStringProperty();
private final ScheduledService<String> updateCheckerService;
private final ObjectProperty<UpdateCheckState> state = new SimpleObjectProperty<>(UpdateCheckState.NOT_CHECKED);
private final ObjectProperty<LocalDateTime> updateCheckTimeProperty = new SimpleObjectProperty<>();
@Inject
UpdateChecker(Settings settings, Environment env, @Named("latestVersion") StringProperty latestVersionProperty, @Named("SemVer") Comparator<String> semVerComparator, ScheduledService<String> updateCheckerService) {
UpdateChecker(Settings settings, //
Environment env, //
ScheduledService<String> updateCheckerService) {
this.env = env;
this.settings = settings;
this.latestVersionProperty = latestVersionProperty;
this.semVerComparator = semVerComparator;
this.updateCheckerService = updateCheckerService;
}
public void automaticallyCheckForUpdatesIfEnabled() {
if (!env.disableUpdateCheck() && settings.checkForUpdates.get()) {
startCheckingForUpdates(AUTOCHECK_DELAY);
startCheckingForUpdates(AUTO_CHECK_DELAY);
}
}
@@ -59,26 +65,30 @@ public class UpdateChecker {
private void checkStarted(WorkerStateEvent event) {
LOG.debug("Checking for updates...");
state.set(UpdateCheckState.IS_CHECKING);
}
private void checkSucceeded(WorkerStateEvent event) {
String latestVersion = updateCheckerService.getValue();
LOG.info("Current version: {}, lastest version: {}", getCurrentVersion(), latestVersion);
if (semVerComparator.compare(getCurrentVersion(), latestVersion) < 0) {
// update is available
latestVersionProperty.set(latestVersion);
} else {
latestVersionProperty.set(null);
}
LOG.info("Current version: {}, latest version: {}", getCurrentVersion(), latestVersion);
state.set(UpdateCheckState.CHECK_SUCCESSFUL);
updateCheckTimeProperty.set(LocalDateTime.now());
latestVersionProperty.set(latestVersion);
}
private void checkFailed(WorkerStateEvent event) {
LOG.warn("Error checking for updates", event.getSource().getException());
state.set(UpdateCheckState.CHECK_FAILED);
}
public enum UpdateCheckState {
NOT_CHECKED,
IS_CHECKING,
CHECK_SUCCESSFUL,
CHECK_FAILED;
}
/* Observable Properties */
public BooleanBinding checkingForUpdatesProperty() {
return updateCheckerService.stateProperty().isEqualTo(Worker.State.RUNNING);
}
@@ -88,7 +98,12 @@ public class UpdateChecker {
}
public String getCurrentVersion() {
return env.getAppVersion();
return "1.12.3"; //env.getAppVersion();
}
public ObjectProperty<LocalDateTime> updateCheckTimeProperty() {
return updateCheckTimeProperty;
}
public ObjectProperty<UpdateCheckState> updateCheckStateProperty() { return state;}
}

View File

@@ -11,8 +11,6 @@ import org.slf4j.LoggerFactory;
import javax.inject.Named;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.ObjectBinding;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.concurrent.ScheduledService;
import javafx.concurrent.Task;
import javafx.util.Duration;
@@ -32,13 +30,6 @@ public abstract class UpdateCheckerModule {
private static final Duration UPDATE_CHECK_INTERVAL = Duration.hours(3);
private static final Duration DISABLED_UPDATE_CHECK_INTERVAL = Duration.hours(100000); // Duration.INDEFINITE leads to overflows...
@Provides
@Named("latestVersion")
@FxApplicationScoped
static StringProperty provideLatestVersion() {
return new SimpleStringProperty();
}
@Provides
@FxApplicationScoped
static Optional<HttpClient> provideHttpClient() {

View File

@@ -1,7 +1,9 @@
package org.cryptomator.ui.preferences;
import org.cryptomator.common.SemVerComparator;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.controls.FormattedLabel;
import org.cryptomator.ui.fxapp.UpdateChecker;
import javax.inject.Inject;
@@ -9,11 +11,19 @@ import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.binding.ObjectBinding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.fxml.FXML;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ContentDisplay;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Comparator;
import java.util.Locale;
import java.util.ResourceBundle;
@PreferencesScoped
public class UpdatesPreferencesController implements FxController {
@@ -21,28 +31,60 @@ public class UpdatesPreferencesController implements FxController {
private final Application application;
private final Settings settings;
private final ResourceBundle resourceBundle;
private final UpdateChecker updateChecker;
private final ObjectBinding<ContentDisplay> checkForUpdatesButtonState;
private final ReadOnlyStringProperty latestVersion;
private final String currentVersion;
private final BooleanBinding updateAvailable;
private final ObjectProperty<LocalDateTime> updateCheckDateProperty;
private final Comparator<String> versionComparator = new SemVerComparator();
private final ObjectProperty<UpdateChecker.UpdateCheckState> updateCheckStateProperty;
/* FXML */
public CheckBox checkForUpdatesCheckbox;
public FormattedLabel updateCheckDateFormattedLabel;
public FormattedLabel statusFormattedLabel;
@Inject
UpdatesPreferencesController(Application application, Settings settings, UpdateChecker updateChecker) {
UpdatesPreferencesController(Application application, Settings settings, ResourceBundle resourceBundle, UpdateChecker updateChecker) {
this.application = application;
this.settings = settings;
this.resourceBundle = resourceBundle;
this.updateChecker = updateChecker;
this.checkForUpdatesButtonState = Bindings.when(updateChecker.checkingForUpdatesProperty()).then(ContentDisplay.LEFT).otherwise(ContentDisplay.TEXT_ONLY);
this.latestVersion = updateChecker.latestVersionProperty();
this.updateAvailable = latestVersion.isNotNull();
this.currentVersion = updateChecker.getCurrentVersion();
this.updateAvailable = Bindings.createBooleanBinding(() -> {
if (latestVersion.get() != null) {
return versionComparator.compare(currentVersion, latestVersion.get()) < 0;
} else {
return false;
}
}, latestVersion);
this.updateCheckDateProperty = updateChecker.updateCheckTimeProperty();
this.updateCheckStateProperty = updateChecker.updateCheckStateProperty();
}
public void initialize() {
checkForUpdatesCheckbox.selectedProperty().bindBidirectional(settings.checkForUpdates);
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(Locale.getDefault());
updateCheckDateFormattedLabel.arg1Property().bind(Bindings.createStringBinding(() -> {
return (updateCheckDateProperty.get() != null) ? updateCheckDateProperty.get().format(formatter) : "";
}, updateCheckDateProperty));
updateCheckDateFormattedLabel.managedProperty().bind(updateCheckDateProperty.isNotNull());
updateCheckDateFormattedLabel.visibleProperty().bind(updateCheckDateProperty.isNotNull());
statusFormattedLabel.arg1Property().bind(Bindings.createObjectBinding(() ->{
return switch (updateCheckStateProperty.get()) {
case NOT_CHECKED -> resourceBundle.getString("preferences.updates.status.notChecked");
case IS_CHECKING -> resourceBundle.getString("preferences.updates.status.isChecking");
case CHECK_SUCCESSFUL -> resourceBundle.getString("preferences.updates.status.checkSuccessful");
case CHECK_FAILED -> resourceBundle.getString("preferences.updates.status.checkFailed");
};
}, updateCheckStateProperty
));
}
@FXML