From 9b019726bbc7175cd2877d70aa752a5f62bbf25e Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 20 Nov 2019 17:11:54 +0100 Subject: [PATCH] show badge for missing license key in window title --- .../cryptomator/common/LicenseChecker.java | 2 +- .../org/cryptomator/common/LicenseHolder.java | 79 +++++++++++++++++++ .../ui/controls/FontAwesome5Icon.java | 1 + .../cryptomator/ui/fxapp/FxApplication.java | 5 +- .../ui/mainwindow/MainWindowController.java | 17 +++- .../LicenseKeyPreferencesController.java | 58 ++------------ .../ui/preferences/PreferencesComponent.java | 7 +- .../ui/preferences/PreferencesController.java | 36 ++++++++- .../ui/preferences/PreferencesModule.java | 8 ++ .../preferences/SelectedPreferencesTab.java | 28 +++++++ .../ui/traymenu/TrayMenuController.java | 3 +- .../src/main/resources/fxml/main_window.fxml | 15 +++- .../fxml/preferences_donationkey.fxml | 6 +- .../main/resources/i18n/strings.properties | 2 +- 14 files changed, 199 insertions(+), 68 deletions(-) create mode 100644 main/commons/src/main/java/org/cryptomator/common/LicenseHolder.java create mode 100644 main/ui/src/main/java/org/cryptomator/ui/preferences/SelectedPreferencesTab.java diff --git a/main/commons/src/main/java/org/cryptomator/common/LicenseChecker.java b/main/commons/src/main/java/org/cryptomator/common/LicenseChecker.java index 82134f77f..93f16f755 100644 --- a/main/commons/src/main/java/org/cryptomator/common/LicenseChecker.java +++ b/main/commons/src/main/java/org/cryptomator/common/LicenseChecker.java @@ -19,7 +19,7 @@ import java.security.spec.X509EncodedKeySpec; import java.util.Optional; @Singleton -public class LicenseChecker { +class LicenseChecker { private final JWTVerifier verifier; diff --git a/main/commons/src/main/java/org/cryptomator/common/LicenseHolder.java b/main/commons/src/main/java/org/cryptomator/common/LicenseHolder.java new file mode 100644 index 000000000..70d439afe --- /dev/null +++ b/main/commons/src/main/java/org/cryptomator/common/LicenseHolder.java @@ -0,0 +1,79 @@ +package org.cryptomator.common; + +import com.auth0.jwt.interfaces.DecodedJWT; +import javafx.beans.binding.Bindings; +import javafx.beans.binding.BooleanBinding; +import javafx.beans.binding.StringBinding; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import org.cryptomator.common.settings.Settings; + +import javax.inject.Inject; +import javax.inject.Singleton; +import java.util.Optional; + +@Singleton +public class LicenseHolder { + + private final Settings settings; + private final LicenseChecker licenseChecker; + private final ObjectProperty validJwtClaims; + private final StringBinding licenseSubject; + private final BooleanBinding validLicenseProperty; + + @Inject + public LicenseHolder(LicenseChecker licenseChecker, Settings settings) { + this.settings = settings; + this.licenseChecker = licenseChecker; + this.validJwtClaims = new SimpleObjectProperty<>(); + this.licenseSubject = Bindings.createStringBinding(this::getLicenseSubject, validJwtClaims); + this.validLicenseProperty = validJwtClaims.isNotNull(); + + Optional claims = licenseChecker.check(settings.licenseKey().get()); + validJwtClaims.set(claims.orElse(null)); + } + + public boolean validateAndStoreLicense(String licenseKey) { + Optional claims = licenseChecker.check(licenseKey); + validJwtClaims.set(claims.orElse(null)); + if (claims.isPresent()) { + settings.licenseKey().set(licenseKey); + return true; + } else { + return false; + } + } + + /* Observable Properties */ + + public Optional getLicenseKey() { + DecodedJWT claims = validJwtClaims.get(); + if (claims != null) { + return Optional.of(claims.getToken()); + } else { + return Optional.empty(); + } + } + + public StringBinding licenseSubjectProperty() { + return licenseSubject; + } + + public String getLicenseSubject() { + DecodedJWT claims = validJwtClaims.get(); + if (claims != null) { + return claims.getSubject(); + } else { + return null; + } + } + + public BooleanBinding validLicenseProperty() { + return validLicenseProperty; + } + + public boolean isValidLicense() { + return validLicenseProperty.get(); + } + +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/controls/FontAwesome5Icon.java b/main/ui/src/main/java/org/cryptomator/ui/controls/FontAwesome5Icon.java index 7a22d1ced..d592876d6 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controls/FontAwesome5Icon.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controls/FontAwesome5Icon.java @@ -10,6 +10,7 @@ public enum FontAwesome5Icon { COG("\uF013"), // COGS("\uF085"), // EXCLAMATION("\uF12A"), + EXCLAMATION_CIRCLE("\uF06A"), // EXCLAMATION_TRIANGLE("\uF071"), // EYE("\uF06E"), // EYE_SLASH("\uF070"), // diff --git a/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java b/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java index f52a9b2ed..570c9cdf3 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java +++ b/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java @@ -18,6 +18,7 @@ import org.cryptomator.jni.MacApplicationUiState; import org.cryptomator.jni.MacFunctions; import org.cryptomator.ui.mainwindow.MainWindowComponent; import org.cryptomator.ui.preferences.PreferencesComponent; +import org.cryptomator.ui.preferences.SelectedPreferencesTab; import org.cryptomator.ui.quit.QuitComponent; import org.cryptomator.ui.unlock.UnlockComponent; import org.slf4j.Logger; @@ -79,9 +80,9 @@ public class FxApplication extends Application { } } - public void showPreferencesWindow() { + public void showPreferencesWindow(SelectedPreferencesTab selectedTab) { Platform.runLater(() -> { - Stage stage = preferencesWindow.get().showPreferencesWindow(); + Stage stage = preferencesWindow.get().showPreferencesWindow(selectedTab); addVisibleStage(stage); LOG.debug("Showing Preferences"); }); diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/MainWindowController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/MainWindowController.java index 291efe4fe..e6fe1fd72 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/MainWindowController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/MainWindowController.java @@ -10,10 +10,12 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.Region; import javafx.scene.layout.VBox; import javafx.stage.Stage; +import org.cryptomator.common.LicenseHolder; import org.cryptomator.common.vaults.VaultListManager; import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.fxapp.FxApplication; import org.cryptomator.ui.fxapp.UpdateChecker; +import org.cryptomator.ui.preferences.SelectedPreferencesTab; import org.cryptomator.ui.wrongfilealert.WrongFileAlertComponent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,6 +40,7 @@ public class MainWindowController implements FxController { private final boolean minimizeToSysTray; private final UpdateChecker updateChecker; private final BooleanBinding updateAvailable; + private final LicenseHolder licenseHolder; private final VaultListManager vaultListManager; private final WrongFileAlertComponent.Builder wrongFileAlert; private final BooleanProperty draggingOver = new SimpleBooleanProperty(); @@ -49,12 +52,13 @@ public class MainWindowController implements FxController { private double yOffset; @Inject - public MainWindowController(@MainWindow Stage window, FxApplication application, @Named("trayMenuSupported") boolean minimizeToSysTray, UpdateChecker updateChecker, VaultListManager vaultListManager, WrongFileAlertComponent.Builder wrongFileAlert) { + public MainWindowController(@MainWindow Stage window, FxApplication application, @Named("trayMenuSupported") boolean minimizeToSysTray, UpdateChecker updateChecker, LicenseHolder licenseHolder, VaultListManager vaultListManager, WrongFileAlertComponent.Builder wrongFileAlert) { this.window = window; this.application = application; this.minimizeToSysTray = minimizeToSysTray; this.updateChecker = updateChecker; this.updateAvailable = updateChecker.latestVersionProperty().isNotNull(); + this.licenseHolder = licenseHolder; this.vaultListManager = vaultListManager; this.wrongFileAlert = wrongFileAlert; } @@ -136,11 +140,20 @@ public class MainWindowController implements FxController { @FXML public void showPreferences() { - application.showPreferencesWindow(); + application.showPreferencesWindow(SelectedPreferencesTab.ANY); + } + + @FXML + public void showDonationKeyPreferences() { + application.showPreferencesWindow(SelectedPreferencesTab.DONATION_KEY); } /* Getter/Setter */ + public LicenseHolder getLicenseHolder() { + return licenseHolder; + } + public BooleanBinding updateAvailableProperty() { return updateAvailable; } diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/LicenseKeyPreferencesController.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/LicenseKeyPreferencesController.java index 33c613ce4..f18bc7882 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/preferences/LicenseKeyPreferencesController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/preferences/LicenseKeyPreferencesController.java @@ -1,60 +1,37 @@ package org.cryptomator.ui.preferences; -import com.auth0.jwt.interfaces.DecodedJWT; import javafx.application.Application; -import javafx.beans.binding.Bindings; -import javafx.beans.binding.BooleanBinding; -import javafx.beans.binding.StringBinding; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ObservableValue; import javafx.fxml.FXML; import javafx.scene.control.TextArea; -import org.cryptomator.common.LicenseChecker; -import org.cryptomator.common.settings.Settings; +import org.cryptomator.common.LicenseHolder; import org.cryptomator.ui.common.FxController; import javax.inject.Inject; -import java.util.Optional; @PreferencesScoped public class LicenseKeyPreferencesController implements FxController { private static final String DONATION_URI = "https://cryptomator.org/#donate"; - private final Settings settings; private final Application application; - private final LicenseChecker licenseChecker; - private final ObjectProperty validJwtClaims; - private final StringBinding licenseSubject; - private final BooleanBinding validLicenseProperty; + private final LicenseHolder licenseHolder; public TextArea donationKeyField; @Inject - LicenseKeyPreferencesController(Settings settings, Application application, LicenseChecker licenseChecker) { - this.settings = settings; + LicenseKeyPreferencesController(Application application, LicenseHolder licenseHolder) { this.application = application; - this.licenseChecker = licenseChecker; - this.validJwtClaims = new SimpleObjectProperty<>(); - this.licenseSubject = Bindings.createStringBinding(this::getLicenseSubject, validJwtClaims); - this.validLicenseProperty = validJwtClaims.isNotNull(); - - Optional claims = licenseChecker.check(settings.licenseKey().get()); - validJwtClaims.set(claims.orElse(null)); + this.licenseHolder = licenseHolder; } @FXML public void initialize() { - donationKeyField.setText(settings.licenseKey().get()); + donationKeyField.setText(licenseHolder.getLicenseKey().orElse(null)); donationKeyField.textProperty().addListener(this::registrationKeyChanged); } private void registrationKeyChanged(@SuppressWarnings("unused") ObservableValue observable, @SuppressWarnings("unused") String oldValue, String newValue) { - Optional claims = licenseChecker.check(newValue); - validJwtClaims.set(claims.orElse(null)); - if (claims.isPresent()) { - settings.licenseKey().set(newValue); - } + licenseHolder.validateAndStoreLicense(newValue); } @FXML @@ -62,26 +39,7 @@ public class LicenseKeyPreferencesController implements FxController { application.getHostServices().showDocument(DONATION_URI); } - /* Observable Properties */ - - public StringBinding licenseSubjectProperty() { - return licenseSubject; - } - - public String getLicenseSubject() { - DecodedJWT claims = validJwtClaims.get(); - if (claims != null) { - return claims.getSubject(); - } else { - return null; - } - } - - public BooleanBinding validLicenseProperty() { - return validLicenseProperty; - } - - public boolean isValidLicense() { - return validLicenseProperty.get(); + public LicenseHolder getLicenseHolder() { + return licenseHolder; } } diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesComponent.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesComponent.java index 49408d639..320b8c63f 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesComponent.java +++ b/main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesComponent.java @@ -7,9 +7,9 @@ package org.cryptomator.ui.preferences; import dagger.Lazy; import dagger.Subcomponent; +import javafx.beans.property.ObjectProperty; import javafx.scene.Scene; import javafx.stage.Stage; -import org.cryptomator.ui.common.FXMLLoaderFactory; import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlScene; @@ -23,7 +23,10 @@ public interface PreferencesComponent { @FxmlScene(FxmlFile.PREFERENCES) Lazy scene(); - default Stage showPreferencesWindow() { + ObjectProperty selectedTabProperty(); + + default Stage showPreferencesWindow(SelectedPreferencesTab selectedTab) { + selectedTabProperty().set(selectedTab); Stage stage = window(); stage.setScene(scene().get()); stage.show(); diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesController.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesController.java index 7ce4793cc..718f9d443 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesController.java @@ -1,6 +1,9 @@ package org.cryptomator.ui.preferences; +import javafx.beans.Observable; import javafx.beans.binding.BooleanBinding; +import javafx.beans.property.ObjectProperty; +import javafx.beans.value.ObservableValue; import javafx.fxml.FXML; import javafx.scene.control.Tab; import javafx.scene.control.TabPane; @@ -15,25 +18,50 @@ import javax.inject.Inject; public class PreferencesController implements FxController { private final Stage window; + private final ObjectProperty selectedTabProperty; private final BooleanBinding updateAvailable; public TabPane tabPane; + public Tab generalTab; + public Tab volumeTab; public Tab updatesTab; + public Tab donationKeyTab; @Inject - public PreferencesController(@PreferencesWindow Stage window, UpdateChecker updateChecker) { + public PreferencesController(@PreferencesWindow Stage window, ObjectProperty selectedTabProperty, UpdateChecker updateChecker) { this.window = window; + this.selectedTabProperty = selectedTabProperty; this.updateAvailable = updateChecker.latestVersionProperty().isNotNull(); } @FXML public void initialize() { window.setOnShowing(this::windowWillAppear); + selectedTabProperty.addListener(observable -> this.selectChosenTab()); } - private void windowWillAppear(@SuppressWarnings("unused") WindowEvent windowEvent) { - if (updateAvailable.get()) { - tabPane.getSelectionModel().select(updatesTab); + private void selectChosenTab() { + Tab toBeSelected = getTabToSelect(selectedTabProperty.get()); + tabPane.getSelectionModel().select(toBeSelected); + } + + private Tab getTabToSelect(SelectedPreferencesTab selectedTab) { + switch (selectedTab) { + case UPDATES: + return updatesTab; + case VOLUME: + return volumeTab; + case DONATION_KEY: + return donationKeyTab; + case GENERAL: + return generalTab; + case ANY: + default: + return updateAvailable.get() ? updatesTab : generalTab; } } + private void windowWillAppear(@SuppressWarnings("unused") WindowEvent windowEvent) { + selectChosenTab(); + } + } diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesModule.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesModule.java index 5f8852df9..2ed7be66e 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesModule.java @@ -4,6 +4,8 @@ import dagger.Binds; import dagger.Module; import dagger.Provides; import dagger.multibindings.IntoMap; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.stage.Stage; @@ -23,6 +25,12 @@ import java.util.ResourceBundle; @Module abstract class PreferencesModule { + @Provides + @PreferencesScoped + static ObjectProperty provideSelectedTabProperty() { + return new SimpleObjectProperty<>(SelectedPreferencesTab.ANY); + } + @Provides @PreferencesWindow @PreferencesScoped diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/SelectedPreferencesTab.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/SelectedPreferencesTab.java new file mode 100644 index 000000000..74f305c6e --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/preferences/SelectedPreferencesTab.java @@ -0,0 +1,28 @@ +package org.cryptomator.ui.preferences; + +public enum SelectedPreferencesTab { + /** + * Let the controller decide which tab to show. + */ + ANY, + + /** + * Show general tab + */ + GENERAL, + + /** + * Show volume tab + */ + VOLUME, + + /** + * Show updates tab + */ + UPDATES, + + /** + * Show donation key tab + */ + DONATION_KEY, +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayMenuController.java b/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayMenuController.java index c95a02905..1c73b5959 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayMenuController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayMenuController.java @@ -8,6 +8,7 @@ import org.cryptomator.common.vaults.Vault; import org.cryptomator.common.vaults.VaultState; import org.cryptomator.ui.fxapp.FxApplication; import org.cryptomator.ui.launcher.FxApplicationStarter; +import org.cryptomator.ui.preferences.SelectedPreferencesTab; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -150,7 +151,7 @@ class TrayMenuController { } private void showPreferencesWindow(@SuppressWarnings("unused") EventObject actionEvent) { - fxApplicationStarter.get(true).thenAccept(FxApplication::showPreferencesWindow); + fxApplicationStarter.get(true).thenAccept(app -> app.showPreferencesWindow(SelectedPreferencesTab.ANY)); } private void handleQuitRequest(EventObject e, QuitResponse response) { diff --git a/main/ui/src/main/resources/fxml/main_window.fxml b/main/ui/src/main/resources/fxml/main_window.fxml index 20ba77aa2..ef2517cb1 100644 --- a/main/ui/src/main/resources/fxml/main_window.fxml +++ b/main/ui/src/main/resources/fxml/main_window.fxml @@ -22,10 +22,21 @@