From 458866f7d6460e688897b851248c8a2c22dc80d1 Mon Sep 17 00:00:00 2001 From: Markus Kreusch Date: Tue, 22 May 2018 11:35:45 +0200 Subject: [PATCH] Asking user once before enabling update check --- .../cryptomator/common/settings/Settings.java | 22 ++++---- .../common/settings/SettingsJsonAdapter.java | 17 +++--- .../ui/controllers/WelcomeController.java | 52 +++++++++++++------ .../cryptomator/ui/util/AsyncTaskService.java | 44 ++++++++++++---- .../ui/src/main/resources/localization/en.txt | 3 ++ 5 files changed, 95 insertions(+), 43 deletions(-) diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/Settings.java b/main/commons/src/main/java/org/cryptomator/common/settings/Settings.java index bd32a1cb6..25ed6021a 100644 --- a/main/commons/src/main/java/org/cryptomator/common/settings/Settings.java +++ b/main/commons/src/main/java/org/cryptomator/common/settings/Settings.java @@ -8,26 +8,20 @@ ******************************************************************************/ package org.cryptomator.common.settings; -import java.util.function.Consumer; - -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.IntegerProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleIntegerProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; +import javafx.beans.property.*; import javafx.beans.value.ObservableValue; import javafx.collections.FXCollections; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; +import java.util.function.Consumer; + public class Settings { public static final int MIN_PORT = 1024; public static final int MAX_PORT = 65535; - public static final boolean DEFAULT_CHECK_FOR_UDPATES = true; + public static final boolean DEFAULT_ASKED_FOR_UPDATE_CHECK = false; + public static final boolean DEFAULT_CHECK_FOR_UDPATES = false; public static final int DEFAULT_PORT = 42427; public static final int DEFAULT_NUM_TRAY_NOTIFICATIONS = 3; public static final String DEFAULT_GVFS_SCHEME = "dav"; @@ -35,6 +29,7 @@ public class Settings { public static final VolumeImpl DEFAULT_VOLUME_IMPL = VolumeImpl.FUSE; private final ObservableList directories = FXCollections.observableArrayList(VaultSettings::observables); + private final BooleanProperty askedForUpdateCheck = new SimpleBooleanProperty(DEFAULT_ASKED_FOR_UPDATE_CHECK); private final BooleanProperty checkForUpdates = new SimpleBooleanProperty(DEFAULT_CHECK_FOR_UDPATES); private final IntegerProperty port = new SimpleIntegerProperty(DEFAULT_PORT); private final IntegerProperty numTrayNotifications = new SimpleIntegerProperty(DEFAULT_NUM_TRAY_NOTIFICATIONS); @@ -49,6 +44,7 @@ public class Settings { */ Settings() { directories.addListener((ListChangeListener.Change change) -> this.save()); + askedForUpdateCheck.addListener(this::somethingChanged); checkForUpdates.addListener(this::somethingChanged); port.addListener(this::somethingChanged); numTrayNotifications.addListener(this::somethingChanged); @@ -77,6 +73,10 @@ public class Settings { return directories; } + public BooleanProperty askedForUpdateCheck() { + return askedForUpdateCheck; + } + public BooleanProperty checkForUpdates() { return checkForUpdates; } diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/SettingsJsonAdapter.java b/main/commons/src/main/java/org/cryptomator/common/settings/SettingsJsonAdapter.java index 00dc439f7..e02b901a0 100644 --- a/main/commons/src/main/java/org/cryptomator/common/settings/SettingsJsonAdapter.java +++ b/main/commons/src/main/java/org/cryptomator/common/settings/SettingsJsonAdapter.java @@ -5,17 +5,16 @@ *******************************************************************************/ package org.cryptomator.common.settings; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; public class SettingsJsonAdapter extends TypeAdapter { @@ -28,6 +27,7 @@ public class SettingsJsonAdapter extends TypeAdapter { out.beginObject(); out.name("directories"); writeVaultSettingsArray(out, value.getDirectories()); + out.name("askedForUpdateCheck").value(value.askedForUpdateCheck().get()); out.name("checkForUpdatesEnabled").value(value.checkForUpdates().get()); out.name("port").value(value.port().get()); out.name("numTrayNotifications").value(value.numTrayNotifications().get()); @@ -56,6 +56,9 @@ public class SettingsJsonAdapter extends TypeAdapter { case "directories": settings.getDirectories().addAll(readVaultSettingsArray(in)); break; + case "askedForUpdateCheck": + settings.askedForUpdateCheck().set(in.nextBoolean()); + break; case "checkForUpdatesEnabled": settings.checkForUpdates().set(in.nextBoolean()); break; diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/WelcomeController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/WelcomeController.java index aed401acc..6754afdb3 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/WelcomeController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/WelcomeController.java @@ -2,25 +2,12 @@ * Copyright (c) 2014, 2017 Sebastian Stenzel * All rights reserved. * This program and the accompanying materials are made available under the terms of the accompanying LICENSE file. - * + * * Contributors: * Sebastian Stenzel - initial API and implementation ******************************************************************************/ package org.cryptomator.ui.controllers; -import java.net.URI; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.time.Duration; -import java.util.Comparator; -import java.util.Map; -import java.util.Optional; -import java.util.ResourceBundle; - -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; - import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; @@ -30,6 +17,7 @@ import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.Node; import javafx.scene.Parent; +import javafx.scene.control.ButtonType; import javafx.scene.control.Hyperlink; import javafx.scene.control.Label; import javafx.scene.control.ProgressIndicator; @@ -44,6 +32,21 @@ import org.cryptomator.ui.util.AsyncTaskService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; +import java.net.URI; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.Comparator; +import java.util.Map; +import java.util.Optional; +import java.util.ResourceBundle; +import java.util.concurrent.TimeUnit; + +import static org.cryptomator.ui.util.DialogBuilderUtil.buildYesNoDialog; + @Singleton public class WelcomeController implements ViewController { @@ -58,7 +61,7 @@ public class WelcomeController implements ViewController { @Inject public WelcomeController(Application app, @Named("applicationVersion") Optional applicationVersion, Localization localization, Settings settings, @Named("SemVer") Comparator semVerComparator, - AsyncTaskService asyncTaskService) { + AsyncTaskService asyncTaskService) { this.app = app; this.applicationVersion = applicationVersion; this.localization = localization; @@ -86,6 +89,8 @@ public class WelcomeController implements ViewController { public void initialize(URL location, ResourceBundle resources) { if (areUpdatesManagedExternally()) { checkForUpdatesContainer.setVisible(false); + } else if (!settings.askedForUpdateCheck().get()) { + this.askForUpdateCheck(); } else if (settings.checkForUpdates().get()) { this.checkForUpdates(); } @@ -104,6 +109,23 @@ public class WelcomeController implements ViewController { return Boolean.parseBoolean(System.getProperty("cryptomator.updatesManagedExternally", "false")); } + private void askForUpdateCheck() { + asyncTaskService.runDelayedOnUiThread(1, TimeUnit.SECONDS, () -> { + Optional result = buildYesNoDialog( + localization.getString("welcome.askForUpdateCheck.dialog.title"), + localization.getString("welcome.askForUpdateCheck.dialog.header"), + localization.getString("welcome.askForUpdateCheck.dialog.content"), + ButtonType.YES).showAndWait(); + if (result.isPresent()) { + settings.askedForUpdateCheck().set(true); + settings.checkForUpdates().set(result.get().equals(ButtonType.YES)); + } + if (settings.checkForUpdates().get()) { + this.checkForUpdates(); + } + }); + } + private void checkForUpdates() { checkForUpdatesStatus.setText(localization.getString("welcome.checkForUpdates.label.currentlyChecking")); checkForUpdatesIndicator.setVisible(true); diff --git a/main/ui/src/main/java/org/cryptomator/ui/util/AsyncTaskService.java b/main/ui/src/main/java/org/cryptomator/ui/util/AsyncTaskService.java index a4aa3f96c..b25d51e79 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/util/AsyncTaskService.java +++ b/main/ui/src/main/java/org/cryptomator/ui/util/AsyncTaskService.java @@ -5,20 +5,22 @@ *******************************************************************************/ package org.cryptomator.ui.util; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutorService; - -import javax.inject.Inject; -import javax.inject.Singleton; - +import javafx.application.Platform; import org.cryptomator.common.ConsumerThrowingException; import org.cryptomator.common.RunnableThrowingException; import org.cryptomator.common.SupplierThrowingException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javafx.application.Platform; +import javax.inject.Inject; +import javax.inject.Singleton; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; + +import static java.util.Objects.requireNonNull; +import static java.util.concurrent.TimeUnit.MILLISECONDS; @Singleton public class AsyncTaskService { @@ -34,7 +36,7 @@ public class AsyncTaskService { /** * Creates a new async task - * + * * @param task Tasks to be invoked in a background thread. * @return The async task */ @@ -45,9 +47,13 @@ public class AsyncTaskService { }); } + public void runDelayedOnUiThread(long duration, TimeUnit unit, RunnableThrowingException task) { + asyncTaskOf(() -> null).onSuccess(task).runDelayedBy(duration, unit); + } + /** * Creates a new async task - * + * * @param task Tasks to be invoked in a background thread. * @return The async task */ @@ -100,9 +106,21 @@ public class AsyncTaskService { @Override public void run() { + runDelayedBy(0, MILLISECONDS); + } + + @Override + public void runDelayedBy(long duration, TimeUnit unit) { + requireNonNull(unit, "unit must not be null"); + if (duration < 0) { + throw new IllegalArgumentException("duration must not be negative"); + } errorHandlers.add(ErrorHandler.LOGGING_HANDLER); executor.execute(() -> logExceptions(() -> { try { + if (duration > 0) { + Thread.sleep(unit.toMillis(duration)); + } ResultType result = task.get(); Platform.runLater(() -> { try { @@ -214,6 +232,12 @@ public class AsyncTaskService { */ @Override void run(); + + /** + * Starts the async task delayed by {@code duration unit} + */ + void runDelayedBy(long duration, TimeUnit unit); + } } diff --git a/main/ui/src/main/resources/localization/en.txt b/main/ui/src/main/resources/localization/en.txt index cdd52452c..0926d2c49 100644 --- a/main/ui/src/main/resources/localization/en.txt +++ b/main/ui/src/main/resources/localization/en.txt @@ -23,6 +23,9 @@ main.createVault.nonEmptyDir.content=The selected directory already contains fil # welcome.fxml welcome.checkForUpdates.label.currentlyChecking=Checking for Updates... welcome.newVersionMessage=Version %1$s can be downloaded.\nThis is %2$s. +welcome.askForUpdateCheck.dialog.title=Update check +welcome.askForUpdateCheck.dialog.header=Enable the integrated update check? +welcome.askForUpdateCheck.dialog.content=To check for updates, Cryptomator will fetch the current version from the Cryptomator servers and display a hint to you if a newer version is available.\n\nWe recommend to enable the update check to always be sure you have the newest version of Cryptomator, with all security patches, installed. If you do not enable the update check you may check and download the current version from https://cryptomator.org/downloads/.\n\nYou can change this at any time from within the settings. # initialize.fxml initialize.label.password=Password