mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-04-17 16:16:52 -04:00
Wire UpdateService
This commit is contained in:
@@ -50,6 +50,7 @@ open module org.cryptomator.desktop {
|
||||
requires io.github.coffeelibs.tinyoauth2client;
|
||||
requires org.slf4j;
|
||||
requires org.apache.commons.lang3;
|
||||
requires org.purejava.portal;
|
||||
|
||||
/* dagger bs */
|
||||
requires jakarta.inject;
|
||||
|
||||
@@ -35,7 +35,7 @@ public class AppUpdateChecker {
|
||||
}
|
||||
}
|
||||
|
||||
public String checkForUpdates(DistributionChannel.Value channel) {
|
||||
public Object getUpdater(DistributionChannel.Value channel) {
|
||||
if (updateServices.isEmpty()) {
|
||||
LOG.error("No UpdateService found");
|
||||
return null;
|
||||
@@ -47,7 +47,7 @@ public class AppUpdateChecker {
|
||||
LOG.error("Required service for channel LINUX_FLATPAK not available");
|
||||
return null;
|
||||
} else {
|
||||
return flatpakService.isUpdateAvailable(DistributionChannel.Value.LINUX_FLATPAK);
|
||||
return flatpakService.getLatestReleaseChecker(DistributionChannel.Value.LINUX_FLATPAK);
|
||||
}
|
||||
}
|
||||
default -> throw new IllegalStateException("Unexpected value 'channel': " + channel);
|
||||
@@ -68,4 +68,10 @@ public class AppUpdateChecker {
|
||||
}).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
public UpdateService getServiceForChannel(DistributionChannel.Value requiredChannel) {
|
||||
return updateServices.stream().filter(service -> {
|
||||
DistributionChannel annotation = service.getClass().getAnnotation(DistributionChannel.class);
|
||||
return annotation != null && annotation.value() == requiredChannel;
|
||||
}).findFirst().orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@ import org.cryptomator.common.SemVerComparator;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.common.updates.AppUpdateChecker;
|
||||
import org.cryptomator.integrations.common.DistributionChannel;
|
||||
import org.cryptomator.integrations.update.UpdateService;
|
||||
import org.cryptomator.integrations.update.UpdateFailedException;
|
||||
import org.purejava.portal.rest.UpdateCheckerTask;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -22,6 +23,7 @@ import javafx.concurrent.Worker;
|
||||
import javafx.concurrent.WorkerStateEvent;
|
||||
import javafx.util.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Comparator;
|
||||
|
||||
@FxApplicationScoped
|
||||
@@ -33,11 +35,13 @@ public class UpdateChecker {
|
||||
private final Environment env;
|
||||
private final Settings settings;
|
||||
private final StringProperty latestVersion = new SimpleStringProperty();
|
||||
private final StringProperty latestAppUpdaterVersion = new SimpleStringProperty();
|
||||
private final ScheduledService<String> updateCheckerService;
|
||||
private final ObjectProperty<UpdateCheckState> state = new SimpleObjectProperty<>(UpdateCheckState.NOT_CHECKED);
|
||||
private final ObjectProperty<Instant> lastSuccessfulUpdateCheck;
|
||||
private final Comparator<String> versionComparator = new SemVerComparator();
|
||||
private final BooleanBinding updateAvailable;
|
||||
private final BooleanBinding appUpdateAvailable;
|
||||
private final BooleanBinding checkFailed;
|
||||
private final AppUpdateChecker updateChecker;
|
||||
|
||||
@@ -51,6 +55,7 @@ public class UpdateChecker {
|
||||
this.updateCheckerService = updateCheckerService;
|
||||
this.lastSuccessfulUpdateCheck = settings.lastSuccessfulUpdateCheck;
|
||||
this.updateAvailable = Bindings.createBooleanBinding(this::isUpdateAvailable, latestVersion);
|
||||
this.appUpdateAvailable = Bindings.createBooleanBinding(this::isAppUpdateAvailable, latestAppUpdaterVersion);
|
||||
this.checkFailed = Bindings.equal(UpdateCheckState.CHECK_FAILED, state);
|
||||
this.updateChecker = updateChecker;
|
||||
}
|
||||
@@ -58,14 +63,11 @@ public class UpdateChecker {
|
||||
public void automaticallyCheckForUpdatesIfEnabled() {
|
||||
if (!env.disableUpdateCheck() && settings.checkForUpdates.get()) {
|
||||
if (updateChecker.isUpdateServiceAvailable(env.getBuildNumber())) { // prefer AppUpdateChecker
|
||||
String version = "";
|
||||
switch (env.getBuildNumber().get()) {
|
||||
case "flatpak-1" -> version = updateChecker.checkForUpdates(DistributionChannel.Value.LINUX_FLATPAK);
|
||||
case "flatpak-1" -> startCheckingWithFlatpakUpdater((UpdateCheckerTask) updateChecker.getUpdater(DistributionChannel.Value.LINUX_FLATPAK), AUTO_CHECK_DELAY);
|
||||
default -> LOG.error("Unexpected value 'buildNumber': {}", env.getBuildNumber().get());
|
||||
}
|
||||
LOG.info("Retrieved version from Update Service {}", version);
|
||||
} else { // fallback is the "redirect user to website" approach
|
||||
LOG.info("Common \"redirect user to website\" approach");
|
||||
startCheckingForUpdates(AUTO_CHECK_DELAY);
|
||||
}
|
||||
}
|
||||
@@ -75,6 +77,11 @@ public class UpdateChecker {
|
||||
startCheckingForUpdates(Duration.ZERO);
|
||||
}
|
||||
|
||||
public void updateAppNow() throws UpdateFailedException {
|
||||
var service = updateChecker.getServiceForChannel(DistributionChannel.Value.LINUX_FLATPAK);
|
||||
service.triggerUpdate();
|
||||
}
|
||||
|
||||
private void startCheckingForUpdates(Duration initialDelay) {
|
||||
updateCheckerService.cancel();
|
||||
updateCheckerService.reset();
|
||||
@@ -85,11 +92,31 @@ public class UpdateChecker {
|
||||
updateCheckerService.start();
|
||||
}
|
||||
|
||||
private void startCheckingWithFlatpakUpdater(UpdateCheckerTask service, Duration initialDelay) {
|
||||
service.cancel();
|
||||
service.reset();
|
||||
service.setDelay(convertFxToJavaTime(initialDelay));
|
||||
service.setOnRunning(this::checkStarted);
|
||||
service.setOnSucceeded(this::checkSucceeded);
|
||||
service.setOnFailed(this::checkFailed);
|
||||
service.start();
|
||||
}
|
||||
|
||||
private java.time.Duration convertFxToJavaTime(javafx.util.Duration fxDuration) {
|
||||
double millis = fxDuration.toMillis();
|
||||
return java.time.Duration.of((long) millis, ChronoUnit.MILLIS);
|
||||
}
|
||||
|
||||
private void checkStarted(WorkerStateEvent event) {
|
||||
LOG.debug("Checking for updates...");
|
||||
state.set(UpdateCheckState.IS_CHECKING);
|
||||
}
|
||||
|
||||
private void checkStarted() {
|
||||
LOG.debug("Checking for updates...");
|
||||
state.set(UpdateCheckState.IS_CHECKING);
|
||||
}
|
||||
|
||||
private void checkSucceeded(WorkerStateEvent event) {
|
||||
var latestVersionString = updateCheckerService.getValue();
|
||||
LOG.info("Current version: {}, latest version: {}", getCurrentVersion(), latestVersionString);
|
||||
@@ -98,15 +125,26 @@ public class UpdateChecker {
|
||||
state.set(UpdateCheckState.CHECK_SUCCESSFUL);
|
||||
}
|
||||
|
||||
private void checkSucceeded(String version) {
|
||||
LOG.info("Current version: {}, latest version: {}", getCurrentVersion(), version);
|
||||
lastSuccessfulUpdateCheck.set(Instant.now());
|
||||
latestAppUpdaterVersion.set(version);
|
||||
state.set(UpdateCheckState.CHECK_SUCCESSFUL);
|
||||
}
|
||||
|
||||
private void checkFailed(WorkerStateEvent event) {
|
||||
state.set(UpdateCheckState.CHECK_FAILED);
|
||||
}
|
||||
|
||||
private void checkFailed(Throwable throwable) {
|
||||
state.set(UpdateCheckState.CHECK_FAILED);
|
||||
}
|
||||
|
||||
public enum UpdateCheckState {
|
||||
NOT_CHECKED,
|
||||
IS_CHECKING,
|
||||
CHECK_SUCCESSFUL,
|
||||
CHECK_FAILED;
|
||||
CHECK_FAILED
|
||||
}
|
||||
|
||||
/* Observable Properties */
|
||||
@@ -118,23 +156,38 @@ public class UpdateChecker {
|
||||
return latestVersion;
|
||||
}
|
||||
|
||||
public ReadOnlyStringProperty latestAppUpdaterVersionProperty() {
|
||||
return latestAppUpdaterVersion;
|
||||
}
|
||||
|
||||
public BooleanBinding updateAvailableProperty() {
|
||||
return updateAvailable;
|
||||
}
|
||||
|
||||
public BooleanBinding appUpdateAvailableProperty() {
|
||||
return appUpdateAvailable;
|
||||
}
|
||||
|
||||
public BooleanBinding checkFailedProperty() {
|
||||
return checkFailed;
|
||||
}
|
||||
|
||||
public boolean isUpdateAvailable() {
|
||||
public boolean isUpdateAvailable(StringProperty versionProperty) {
|
||||
String currentVersion = getCurrentVersion();
|
||||
String latestVersionString = latestVersion.get();
|
||||
String latestVersionString = versionProperty.get();
|
||||
|
||||
if (currentVersion == null || latestVersionString == null) {
|
||||
return false;
|
||||
} else {
|
||||
return versionComparator.compare(currentVersion, latestVersionString) < 0;
|
||||
}
|
||||
return versionComparator.compare(currentVersion, latestVersionString) < 0;
|
||||
}
|
||||
|
||||
public boolean isUpdateAvailable() {
|
||||
return isUpdateAvailable(latestVersion);
|
||||
}
|
||||
|
||||
public boolean isAppUpdateAvailable() {
|
||||
return isUpdateAvailable(latestAppUpdaterVersion);
|
||||
}
|
||||
|
||||
public ObjectProperty<Instant> lastSuccessfulUpdateCheckProperty() {
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.cryptomator.ui.preferences;
|
||||
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.integrations.update.UpdateFailedException;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.fxapp.UpdateChecker;
|
||||
|
||||
@@ -51,6 +52,7 @@ public class UpdatesPreferencesController implements FxController {
|
||||
private final ObservableValue<String> timeDifferenceMessage;
|
||||
private final String currentVersion;
|
||||
private final BooleanBinding updateAvailable;
|
||||
private final BooleanBinding appUpdateAvailable;
|
||||
private final BooleanBinding checkFailed;
|
||||
private final BooleanProperty upToDateLabelVisible = new SimpleBooleanProperty(false);
|
||||
private final DateTimeFormatter formatter;
|
||||
@@ -73,6 +75,7 @@ public class UpdatesPreferencesController implements FxController {
|
||||
this.timeDifferenceMessage = Bindings.createStringBinding(this::getTimeDifferenceMessage, lastSuccessfulUpdateCheck);
|
||||
this.currentVersion = environment.getAppVersion();
|
||||
this.updateAvailable = updateChecker.updateAvailableProperty();
|
||||
this.appUpdateAvailable = updateChecker.appUpdateAvailableProperty();
|
||||
this.formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(Locale.getDefault());
|
||||
this.upToDate = updateChecker.updateCheckStateProperty().isEqualTo(UpdateChecker.UpdateCheckState.CHECK_SUCCESSFUL).and(latestVersion.isEqualTo(currentVersion));
|
||||
this.checkFailed = updateChecker.checkFailedProperty();
|
||||
@@ -98,6 +101,11 @@ public class UpdatesPreferencesController implements FxController {
|
||||
updateChecker.checkForUpdatesNow();
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void updateNow() throws UpdateFailedException {
|
||||
updateChecker.updateAppNow();
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void visitDownloadsPage() {
|
||||
application.getHostServices().showDocument(downloadsUri);
|
||||
@@ -174,10 +182,18 @@ public class UpdatesPreferencesController implements FxController {
|
||||
return updateAvailable;
|
||||
}
|
||||
|
||||
public BooleanBinding appUdateAvailableProperty() {
|
||||
return appUpdateAvailable;
|
||||
}
|
||||
|
||||
public boolean isUpdateAvailable() {
|
||||
return updateAvailable.get();
|
||||
}
|
||||
|
||||
public boolean isAppUpdateAvailable() {
|
||||
return appUpdateAvailable.get();
|
||||
}
|
||||
|
||||
public BooleanBinding checkFailedProperty() {
|
||||
return checkFailed;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
<?import javafx.scene.control.CheckBox?>
|
||||
<?import javafx.scene.control.Hyperlink?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.control.Tooltip?>
|
||||
<?import javafx.scene.text.TextFlow?>
|
||||
@@ -53,5 +52,6 @@
|
||||
</graphic>
|
||||
</Label>
|
||||
<Hyperlink text="${linkLabel.value}" onAction="#visitDownloadsPage" textAlignment="CENTER" wrapText="true" styleClass="hyperlink-underline" visible="${controller.updateAvailable}" managed="${controller.updateAvailable}"/>
|
||||
<Button text="Hello Flatpak!" onAction="#updateNow" visible="${controller.appUpdateAvailable}"/>
|
||||
</VBox>
|
||||
</VBox>
|
||||
|
||||
Reference in New Issue
Block a user