mirror of
https://github.com/cryptomator/cryptomator.git
synced 2024-11-23 03:59:51 +00:00
refactored updateChecker by incorporating state management and date tracking
This commit is contained in:
parent
2302db6206
commit
4064b61cd7
@ -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;}
|
||||
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -8,6 +8,7 @@
|
||||
<?import javafx.scene.control.Hyperlink?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import org.cryptomator.ui.controls.FontAwesome5Spinner?>
|
||||
|
||||
<VBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.preferences.UpdatesPreferencesController"
|
||||
@ -18,19 +19,17 @@
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="24"/>
|
||||
</padding>
|
||||
<children>
|
||||
<FormattedLabel format="%preferences.updates.currentVersion" arg1="${controller.currentVersion}" textAlignment="CENTER" wrapText="true"/>
|
||||
<FormattedLabel format="%preferences.updates.currentVersion" arg1="${controller.currentVersion}" textAlignment="CENTER" wrapText="true"/>
|
||||
<CheckBox fx:id="checkForUpdatesCheckbox" text="%preferences.updates.autoUpdateCheck"/>
|
||||
|
||||
<CheckBox fx:id="checkForUpdatesCheckbox" text="%preferences.updates.autoUpdateCheck"/>
|
||||
|
||||
<VBox alignment="CENTER" spacing="12">
|
||||
<Button text="%preferences.updates.checkNowBtn" defaultButton="true" onAction="#checkNow" contentDisplay="${controller.checkForUpdatesButtonState}">
|
||||
<graphic>
|
||||
<FontAwesome5Spinner fx:id="spinner" glyphSize="12"/>
|
||||
</graphic>
|
||||
</Button>
|
||||
|
||||
<Hyperlink text="${linkLabel.value}" onAction="#visitDownloadsPage" textAlignment="CENTER" wrapText="true" styleClass="hyperlink-underline" visible="${controller.updateAvailable}"/>
|
||||
</VBox>
|
||||
</children>
|
||||
<VBox alignment="CENTER" spacing="12">
|
||||
<Button text="%preferences.updates.checkNowBtn" defaultButton="true" onAction="#checkNow" contentDisplay="${controller.checkForUpdatesButtonState}">
|
||||
<graphic>
|
||||
<FontAwesome5Spinner glyphSize="12"/>
|
||||
</graphic>
|
||||
</Button>
|
||||
<FormattedLabel fx:id="statusFormattedLabel" format="%preferences.updates.status" wrapText="true"/>
|
||||
<FormattedLabel fx:id="updateCheckDateFormattedLabel" format="%preferences.updates.lastUpdateCheck" textAlignment="CENTER" wrapText="true"/>
|
||||
<Hyperlink text="${linkLabel.value}" onAction="#visitDownloadsPage" textAlignment="CENTER" wrapText="true" styleClass="hyperlink-underline" visible="${controller.updateAvailable}" managed="${controller.updateAvailable}"/>
|
||||
</VBox>
|
||||
</VBox>
|
||||
|
@ -321,6 +321,13 @@ preferences.updates.currentVersion=Current Version: %s
|
||||
preferences.updates.autoUpdateCheck=Check for updates automatically
|
||||
preferences.updates.checkNowBtn=Check Now
|
||||
preferences.updates.updateAvailable=Update to version %s available.
|
||||
preferences.updates.lastUpdateCheck=The last update check was performed on: %s.
|
||||
preferences.updates.status=Status: %s
|
||||
preferences.updates.status.notChecked=Not checked
|
||||
preferences.updates.status.isChecking=Is checking
|
||||
preferences.updates.status.checkSuccessful=Check successful
|
||||
preferences.updates.status.checkFailed=Check failed
|
||||
|
||||
## Contribution
|
||||
preferences.contribute=Support Us
|
||||
preferences.contribute.registeredFor=Supporter certificate registered for %s
|
||||
|
Loading…
Reference in New Issue
Block a user