浏览代码

refactored updateChecker by incorporating state management and date tracking

Jan-Peter Klein 1 年之前
父节点
当前提交
4064b61cd7

+ 32 - 17
src/main/java/org/cryptomator/ui/fxapp/UpdateChecker.java

@@ -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);
 	}
 
-	/* Observable Properties */
+	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;}
 
 }

+ 0 - 9
src/main/java/org/cryptomator/ui/fxapp/UpdateCheckerModule.java

@@ -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() {

+ 44 - 2
src/main/java/org/cryptomator/ui/preferences/UpdatesPreferencesController.java

@@ -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

+ 13 - 14
src/main/resources/fxml/preferences_updates.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"/>
-
-		<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>
+	<FormattedLabel format="%preferences.updates.currentVersion" arg1="${controller.currentVersion}" textAlignment="CENTER" wrapText="true"/>
+	<CheckBox fx:id="checkForUpdatesCheckbox" text="%preferences.updates.autoUpdateCheck"/>
 
-			<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>

+ 7 - 0
src/main/resources/i18n/strings.properties

@@ -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